Skip to content

Commit 84a83a7

Browse files
feat: merklelization of containers (#697)
1 parent 181ac77 commit 84a83a7

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

lib/spec/runners/ssz_generic.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,15 @@ defmodule SszGenericTestRunner do
6969
{:container, module},
7070
real_serialized,
7171
real_deserialized,
72-
_hash_tree_root
72+
expected_hash_tree_root
7373
) do
7474
real_struct = struct!(module, real_deserialized)
7575
{:ok, deserialized} = SszEx.decode(real_serialized, module)
7676
assert deserialized == real_struct
7777
{:ok, serialized} = SszEx.encode(real_struct, module)
7878
assert serialized == real_serialized
79+
actual_hash_tree_root = SszEx.hash_tree_root!(real_struct, module)
80+
assert actual_hash_tree_root == expected_hash_tree_root
7981
end
8082

8183
defp assert_ssz(
@@ -92,7 +94,7 @@ defmodule SszGenericTestRunner do
9294

9395
assert serialized == real_serialized
9496

95-
{:ok, actual_hash_tree_root} = SszEx.hash_tree_root(real_deserialized, schema)
97+
actual_hash_tree_root = SszEx.hash_tree_root!(real_deserialized, schema)
9698

9799
assert actual_hash_tree_root == expected_hash_tree_root
98100
end

lib/ssz_ex.ex

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,41 @@ defmodule LambdaEthereumConsensus.SszEx do
7575
@spec hash_tree_root!(non_neg_integer, {:int, non_neg_integer}) :: Types.root()
7676
def hash_tree_root!(value, {:int, size}), do: pack(value, {:int, size})
7777

78+
@spec hash_tree_root!(binary, {:bytes, non_neg_integer}) :: Types.root()
79+
def hash_tree_root!(value, {:bytes, size}) do
80+
packed_chunks = pack(value, {:bytes, size})
81+
leaf_count = packed_chunks |> get_chunks_len() |> next_pow_of_two()
82+
root = merkleize_chunks_with_virtual_padding(packed_chunks, leaf_count)
83+
root
84+
end
85+
86+
@spec hash_tree_root!(list(), {:list, any, non_neg_integer}) :: Types.root()
87+
def hash_tree_root!(list, {:list, type, size}) do
88+
{:ok, root} = hash_tree_root(list, {:list, type, size})
89+
root
90+
end
91+
92+
@spec hash_tree_root!(list(), {:vector, any, non_neg_integer}) :: Types.root()
93+
def hash_tree_root!(vector, {:vector, type, size}) do
94+
{:ok, root} = hash_tree_root(vector, {:vector, type, size})
95+
root
96+
end
97+
98+
@spec hash_tree_root!(struct(), atom()) :: Types.root()
99+
def hash_tree_root!(container, module) when is_map(container) do
100+
chunks =
101+
module.schema()
102+
|> Enum.reduce(<<>>, fn {key, schema}, acc_root ->
103+
value = container |> Map.get(key)
104+
root = hash_tree_root!(value, schema)
105+
acc_root <> root
106+
end)
107+
108+
leaf_count = chunks |> get_chunks_len() |> next_pow_of_two()
109+
root = merkleize_chunks_with_virtual_padding(chunks, leaf_count)
110+
root
111+
end
112+
78113
@spec hash_tree_root(list(), {:list, any, non_neg_integer}) ::
79114
{:ok, Types.root()} | {:error, String.t()}
80115
def hash_tree_root(list, {:list, type, size}) do
@@ -207,6 +242,11 @@ defmodule LambdaEthereumConsensus.SszEx do
207242
<<value::size(size)-little>> |> pack_bytes()
208243
end
209244

245+
@spec pack(binary, {:bytes, non_neg_integer}) :: binary()
246+
def pack(value, {:bytes, _size}) do
247+
value |> pack_bytes()
248+
end
249+
210250
@spec pack(list(), {:list | :vector, any, non_neg_integer}) :: binary() | :error
211251
def pack(list, {type, schema, _}) when type in [:vector, :list] do
212252
if variable_size?(schema) do

0 commit comments

Comments
 (0)