Skip to content

Commit

Permalink
Add nested containers tests
Browse files Browse the repository at this point in the history
  • Loading branch information
avilagaston9 committed Apr 23, 2024
1 parent 92bf497 commit 76c7536
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 20 deletions.
10 changes: 5 additions & 5 deletions lib/ssz_ex/decode.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ defmodule SszEx.Decode do
def decode(binary, module) when is_atom(module) do
with {:ok, result} <-
if(Utils.variable_size?(module),
do: decode_variable_container(binary, module) |> Utils.add_trace("#{module}"),
else: decode_fixed_container(binary, module) |> Utils.add_trace("#{module}")
do: decode_variable_container(binary, module),
else: decode_fixed_container(binary, module)
) do
if exported?(module, :decode_ex, 1) do
{:ok, module.decode_ex(result)}
Expand Down Expand Up @@ -339,15 +339,15 @@ defmodule SszEx.Decode do
<<chunk::binary-size(size), rest::bitstring>> = rest_bytes

{:cont,
{rest, [{key, decode(chunk, schema) |> Utils.add_trace(key)} | acc_variable_parts]}}
{rest, [{key, decode(chunk, schema) |> Error.add_trace(key)} | acc_variable_parts]}}

error ->
{:halt, {<<>>, [{key, error} | acc_variable_parts]}}
end

[{_offset, {key, schema}}], {rest_bytes, acc_variable_parts} ->
{:cont,
{<<>>, [{key, decode(rest_bytes, schema) |> Utils.add_trace(key)} | acc_variable_parts]}}
{<<>>, [{key, decode(rest_bytes, schema) |> Error.add_trace(key)} | acc_variable_parts]}}
end)
|> then(fn {<<>>, variable_parts} ->
flatten_container_results(variable_parts)
Expand All @@ -367,7 +367,7 @@ defmodule SszEx.Decode do
ssz_fixed_len = Utils.get_fixed_size(schema)
<<chunk::binary-size(ssz_fixed_len), rest::bitstring>> = binary

{rest, [{key, decode(chunk, schema) |> Utils.add_trace(key)} | fixed_parts], offsets,
{rest, [{key, decode(chunk, schema) |> Error.add_trace(key)} | fixed_parts], offsets,
items_index + ssz_fixed_len}
end
end)
Expand Down
4 changes: 2 additions & 2 deletions lib/ssz_ex/encode.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ defmodule SszEx.Encode do
do: encode_bitvector(value, size)

def encode(container, module) when is_map(container) do
encode_container(container, module.schema()) |> Utils.add_trace("#{module}")
encode_container(container, module.schema())
end

defp encode_int(value, size) when is_integer(value), do: {:ok, <<value::size(size)-little>>}
Expand Down Expand Up @@ -173,7 +173,7 @@ defmodule SszEx.Encode do

defp encode_schemas(tuple_values) do
Enum.map(tuple_values, fn {value, key, schema} ->
encode(value, schema) |> Utils.add_trace(key)
encode(value, schema) |> Error.add_trace(key)
end)
|> Utils.flatten_results()
end
Expand Down
7 changes: 6 additions & 1 deletion lib/ssz_ex/error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule SszEx.Error do

def format(%Error{message: message, stacktrace: stacktrace}) do
"#{message}"
formatted_stacktrace = stacktrace |> Enum.reverse() |> Enum.join("\n")
formatted_stacktrace = stacktrace |> Enum.join(".")
"#{message}Stacktrace: #{formatted_stacktrace}"
end

Expand All @@ -22,6 +22,11 @@ defmodule SszEx.Error do
%Error{message: message, stacktrace: [new_trace | stacktrace]}
end

def add_trace({:error, %Error{} = error}, module),
do: {:error, Error.add_trace(error, module)}

def add_trace(value, _module), do: value

defimpl String.Chars, for: __MODULE__ do
def to_string(error), do: Error.format(error)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/ssz_ex/merkleization.ex
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ defmodule SszEx.Merkleization do
root = chunks |> merkleize_chunks_with_virtual_padding(leaf_count)
{:ok, root}

{:error, %Error{} = error} ->
{:error, Error.add_trace(error, "#{module}")}
{:error, %Error{}} ->
value
end
end

Expand Down
11 changes: 10 additions & 1 deletion lib/ssz_ex/ssz_ex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,17 @@ defmodule SszEx do

@spec encode(struct()) ::
{:ok, binary()} | {:error, Error.t()}
def encode(%name{} = value), do: encode(value, name)
def encode(%name{} = value), do: encode(value, name) |> Error.add_trace("#{name}")

@spec encode(any(), schema()) ::
{:ok, binary()} | {:error, Error.t()}
def encode(value, schema), do: Encode.encode(value, schema)

@spec decode(binary(), schema()) ::
{:ok, any()} | {:error, Error.t()}
def decode(value, module) when is_atom(module),
do: Decode.decode(value, module) |> Error.add_trace("#{module}")

@spec decode(binary(), schema()) ::
{:ok, any()} | {:error, Error.t()}
def decode(value, schema), do: Decode.decode(value, schema)
Expand All @@ -78,6 +83,10 @@ defmodule SszEx do
@spec hash_tree_root!(any, any) :: Types.root()
def hash_tree_root!(value, schema), do: Merkleization.hash_tree_root!(value, schema)

@spec hash_tree_root(struct()) :: {:ok, Types.root()} | {:error, Error.t()}
def hash_tree_root(%name{} = value),
do: hash_tree_root(value, name) |> Error.add_trace("#{name}")

@spec hash_tree_root(any, any) :: {:ok, Types.root()} | {:error, Error.t()}
def hash_tree_root(value, schema), do: Merkleization.hash_tree_root(value, schema)

Expand Down
6 changes: 0 additions & 6 deletions lib/ssz_ex/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ defmodule SszEx.Utils do

alias LambdaEthereumConsensus.Utils.BitList
alias LambdaEthereumConsensus.Utils.BitVector
alias SszEx.Error

@allowed_uints [8, 16, 32, 64, 128, 256]
@bits_per_byte 8
Expand Down Expand Up @@ -115,9 +114,4 @@ defmodule SszEx.Utils do
def size_of(:bool), do: @bytes_per_boolean

def size_of({:int, size}), do: size |> div(@bits_per_byte)

def add_trace({:error, %Error{} = error}, module),
do: {:error, Error.add_trace(error, module)}

def add_trace(value, _module), do: value
end
103 changes: 100 additions & 3 deletions test/unit/ssz_ex_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,59 @@ defmodule Unit.SSZExTest do
assert {:ok, deserialized} === SszEx.decode(serialized, schema)
end

def build_broken_attester_slashing() do
checkpoint_source = %Types.Checkpoint{
epoch: 3_776_037_760_046_644_755,
root:
<<29, 22, 191, 147, 188, 238, 162, 89, 147, 162, 202, 111, 169, 162, 84, 95, 194, 85, 54,
172, 44, 74, 37, 128, 248, 21, 86, 246, 151, 54, 24, 54>>
}

checkpoint_target = %Types.Checkpoint{
epoch: 2_840_053_453_521_072_037,
root:
<<15, 174, 23, 120, 4, 9, 2, 116, 67, 73, 254, 53, 197, 3, 191, 166, 104, 34, 121, 2, 57,
69, 75, 69, 254, 237, 132, 68, 254, 49, 127, 175>>
}

attestation_data = %Types.AttestationData{
slot: 5_057_010_135_270_197_978,
index: 6_920_931_864_607_509_210,
beacon_block_root:
<<31, 38, 101, 174, 248, 168, 116, 226, 15, 39, 218, 148, 42, 8, 80, 80, 241, 149, 162,
32, 176, 208, 120, 120, 89, 123, 136, 115, 154, 28, 21, 174>>,
source: checkpoint_source,
target: checkpoint_target
}

indexed_attestation_1 = %Types.IndexedAttestation{
attesting_indices: [15_833_676_831_095_072_535, 7_978_643_446_947_046_229],
data: attestation_data,
signature:
<<46, 244, 83, 164, 182, 222, 218, 247, 8, 186, 138, 100, 5, 96, 34, 117, 134, 123, 219,
188, 181, 11, 209, 57, 207, 24, 249, 42, 74, 27, 228, 97, 73, 46, 219, 202, 122, 149,
135, 30, 91, 126, 180, 69, 129, 170, 147, 142, 242, 27, 233, 63, 242, 7, 144, 8, 192,
165, 194, 220, 77, 247, 128, 107, 41, 199, 166, 59, 34, 160, 222, 114, 250, 250, 3, 130,
145, 8, 45, 65, 13, 82, 44, 80, 30, 181, 239, 54, 152, 237, 244, 72, 231, 179, 239, 22>>
}

broken_attestation = %Types.IndexedAttestation{
attesting_indices: List.duplicate(0, 3000),
data: attestation_data,
signature:
<<46, 244, 83, 164, 182, 222, 218, 247, 8, 186, 138, 100, 5, 96, 34, 117, 134, 123, 219,
188, 181, 11, 209, 57, 207, 24, 249, 42, 74, 27, 228, 97, 73, 46, 219, 202, 122, 149,
135, 30, 91, 126, 180, 69, 129, 170, 147, 142, 242, 27, 233, 63, 242, 7, 144, 8, 192,
165, 194, 220, 77, 247, 128, 107, 41, 199, 166, 59, 34, 160, 222, 114, 250, 250, 3, 130,
145, 8, 45, 65, 13, 82, 44, 80, 30, 181, 239, 54, 152, 237, 244, 72, 231, 179, 239, 22>>
}

%Types.AttesterSlashing{
attestation_1: indexed_attestation_1,
attestation_2: broken_attestation
}
end

test "packing a list of uints" do
list_1 = [1, 2, 3, 4, 5]

Expand Down Expand Up @@ -764,7 +817,7 @@ defmodule Unit.SSZExTest do
assert error == "#{result}"
end

test "stacktrace in hash_tree_root with invalid logs_bloom" do
test "hash_tree_root with invalid logs_bloom" do
execution_payload = %ExecutionPayload{
parent_hash: @default_hash,
fee_recipient: <<0::size(20 * 8)>>,
Expand All @@ -788,7 +841,34 @@ defmodule Unit.SSZExTest do
{:error, error} = SszEx.hash_tree_root(execution_payload, ExecutionPayload)

assert "#{error}" ==
"Invalid binary length while merkleizing byte_vector.\nExpected size: 256.\nFound: 3\nStacktrace: logs_bloom\nElixir.Types.ExecutionPayload"
"Invalid binary length while merkleizing byte_vector.\nExpected size: 256.\nFound: 3\nStacktrace: logs_bloom"
end

test "stacktrace in hash_tree_root with invalid logs_bloom" do
execution_payload = %ExecutionPayload{
parent_hash: @default_hash,
fee_recipient: <<0::size(20 * 8)>>,
state_root: @default_root,
receipts_root: @default_root,
logs_bloom: <<0, 0, 0>>,
prev_randao: <<0::size(32 * 8)>>,
block_number: 0,
gas_limit: 0,
gas_used: 0,
timestamp: 0,
extra_data: <<>>,
base_fee_per_gas: 0,
block_hash: @default_hash,
transactions: [],
withdrawals: [],
blob_gas_used: 0,
excess_blob_gas: 0
}

{:error, error} = SszEx.hash_tree_root(execution_payload)

assert "#{error}" ==
"Invalid binary length while merkleizing byte_vector.\nExpected size: 256.\nFound: 3\nStacktrace: Elixir.Types.ExecutionPayload.logs_bloom"
end

test "stacktrace in encode with invalid sync_committee_bits" do
Expand All @@ -800,6 +880,23 @@ defmodule Unit.SSZExTest do
{:error, error} = SszEx.encode(sync_aggregate)

assert "#{error}" ==
"Invalid binary length while encoding BitVector. \nExpected: 512.\nFound: 2.\nStacktrace: sync_committee_bits\nElixir.Types.SyncAggregate"
"Invalid binary length while encoding BitVector. \nExpected: 512.\nFound: 2.\nStacktrace: Elixir.Types.SyncAggregate.sync_committee_bits"
end

test "stacktrace encode nested container" do
attester_slashing = build_broken_attester_slashing()

{:error, error} = SszEx.encode(attester_slashing)

assert "#{error}" ==
"Invalid binary length while encoding list of {:int, 64}.\nExpected max_size: 2048.\nFound: 3000\nStacktrace: Elixir.Types.AttesterSlashing.attestation_2.attesting_indices"
end

test "stacktrace hash_tree_root nested container" do
attester_slashing = build_broken_attester_slashing()
{:error, error} = SszEx.hash_tree_root(attester_slashing)

assert "Invalid binary length while merkleizing list of {:int, 64}.\nExpected max_size: 2048.\nFound: 3000\nStacktrace: Elixir.Types.AttesterSlashing.attestation_2.attesting_indices" =
"#{error}"
end
end

0 comments on commit 76c7536

Please sign in to comment.