From 3f6ac3b56c61fb9164113e9a44defb660611b4c0 Mon Sep 17 00:00:00 2001 From: Fernando Ledesma Date: Tue, 12 Dec 2023 01:14:39 +0000 Subject: [PATCH] feat: ssz support nested containers (#509) --- lib/ssz_ex.ex | 14 +++++ .../beacon_chain/attestation_data.ex | 13 +++++ lib/ssz_types/beacon_chain/checkpoint.ex | 8 +++ .../beacon_chain/indexed_attestation.ex | 10 ++++ test/unit/ssz_ex_test.exs | 54 +++++++++++++++++++ 5 files changed, 99 insertions(+) diff --git a/lib/ssz_ex.ex b/lib/ssz_ex.ex index e46db263c..1add539de 100644 --- a/lib/ssz_ex.ex +++ b/lib/ssz_ex.ex @@ -380,8 +380,22 @@ defmodule LambdaEthereumConsensus.SszEx do defp get_fixed_size({:int, size}), do: div(size, @bits_per_byte) defp get_fixed_size({:bytes, size}), do: size + defp get_fixed_size(module) when is_atom(module) do + schemas = module.schema() + + schemas + |> Enum.map(fn {_, schema} -> get_fixed_size(schema) end) + |> Enum.sum() + end + defp variable_size?({:list, _, _}), do: true defp variable_size?(:bool), do: false defp variable_size?({:int, _}), do: false defp variable_size?({:bytes, _}), do: false + + defp variable_size?(module) when is_atom(module) do + module.schema() + |> Enum.map(fn {_, schema} -> variable_size?(schema) end) + |> Enum.any?() + end end diff --git a/lib/ssz_types/beacon_chain/attestation_data.ex b/lib/ssz_types/beacon_chain/attestation_data.ex index 6aa45cd0d..a11f26368 100644 --- a/lib/ssz_types/beacon_chain/attestation_data.ex +++ b/lib/ssz_types/beacon_chain/attestation_data.ex @@ -4,6 +4,8 @@ defmodule SszTypes.AttestationData do Related definitions in `native/ssz_nif/src/types/`. """ + @behaviour LambdaEthereumConsensus.Container + fields = [ :slot, :index, @@ -22,4 +24,15 @@ defmodule SszTypes.AttestationData do source: SszTypes.Checkpoint.t(), target: SszTypes.Checkpoint.t() } + + @impl LambdaEthereumConsensus.Container + def schema do + [ + {:slot, {:int, 64}}, + {:index, {:int, 64}}, + {:beacon_block_root, {:bytes, 32}}, + {:source, SszTypes.Checkpoint}, + {:target, SszTypes.Checkpoint} + ] + end end diff --git a/lib/ssz_types/beacon_chain/checkpoint.ex b/lib/ssz_types/beacon_chain/checkpoint.ex index 4b3a7769c..47a9223d9 100644 --- a/lib/ssz_types/beacon_chain/checkpoint.ex +++ b/lib/ssz_types/beacon_chain/checkpoint.ex @@ -4,6 +4,7 @@ defmodule SszTypes.Checkpoint do Related definitions in `native/ssz_nif/src/types/`. """ + @behaviour LambdaEthereumConsensus.Container fields = [ :root, :epoch @@ -16,4 +17,11 @@ defmodule SszTypes.Checkpoint do epoch: SszTypes.epoch(), root: SszTypes.root() } + + def schema do + [ + {:epoch, {:int, 64}}, + {:root, {:bytes, 32}} + ] + end end diff --git a/lib/ssz_types/beacon_chain/indexed_attestation.ex b/lib/ssz_types/beacon_chain/indexed_attestation.ex index 9e3bbf777..dbe7c2acb 100644 --- a/lib/ssz_types/beacon_chain/indexed_attestation.ex +++ b/lib/ssz_types/beacon_chain/indexed_attestation.ex @@ -3,6 +3,7 @@ defmodule SszTypes.IndexedAttestation do Struct definition for `IndexedAttestation`. Related definitions in `native/ssz_nif/src/types/`. """ + @behaviour LambdaEthereumConsensus.Container fields = [ :attesting_indices, @@ -19,4 +20,13 @@ defmodule SszTypes.IndexedAttestation do data: SszTypes.AttestationData.t(), signature: SszTypes.bls_signature() } + + @impl LambdaEthereumConsensus.Container + def schema do + [ + {:attesting_indices, {:list, {:int, 64}, 2048}}, + {:data, SszTypes.AttestationData}, + {:signature, {:bytes, 96}} + ] + end end diff --git a/test/unit/ssz_ex_test.exs b/test/unit/ssz_ex_test.exs index 3ad2603a5..44378e1f4 100644 --- a/test/unit/ssz_ex_test.exs +++ b/test/unit/ssz_ex_test.exs @@ -28,6 +28,60 @@ defmodule Unit.SSZExTest do assert_roundtrip(<<0>>, false, :bool) end + test "serialize and deserialize nested container" do + checkpoint_source = %SszTypes.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 = %SszTypes.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 = %SszTypes.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 = %SszTypes.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>> + } + + serialized = + <<228, 0, 0, 0, 218, 138, 84, 194, 236, 27, 46, 70, 218, 202, 156, 184, 220, 22, 12, 96, 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, 19, 190, 10, 34, 86, 46, 103, 52, 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, 165, 175, 62, 152, 145, 229, 105, 39, + 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, 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, 23, 39, 193, 253, 47, 133, 188, 219, 85, 227, 198, + 60, 241, 213, 185, 110>> + + assert_roundtrip(serialized, indexed_attestation, SszTypes.IndexedAttestation) + end + test "serialize and deserialize list" do # for test purposes only, do not use in practice assert_roundtrip(<<1, 1, 0>>, [true, true, false], {:list, :bool, 3})