Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: validate SSZ schemas for containers #877

Merged
merged 7 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ config :lambda_ethereum_consensus, BeaconApi.Endpoint,
formats: [json: BeaconApi.ErrorJSON],
layout: false
]

# Load minimal config by default, to allow schema checking
config :lambda_ethereum_consensus, ChainSpec,
config: MinimalConfig,
genesis_validators_root: <<0::256>>
12 changes: 12 additions & 0 deletions lib/container.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,16 @@ defmodule LambdaEthereumConsensus.Container do
It specifies both the serialization order and the schema for each key in the map.
"""
@callback schema() :: Keyword.t(SszEx.schema())

defmacro __using__(_opts) do
quote do
@behaviour unquote(__MODULE__)

@after_compile unquote(__MODULE__)
end
end

def __after_compile__(env, _bytecode) do
SszEx.validate_schema!(env.module)
end
end
36 changes: 36 additions & 0 deletions lib/ssz_ex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ defmodule LambdaEthereumConsensus.SszEx do
#################
import Bitwise

@allowed_uints [8, 16, 32, 64, 128, 256]
@bytes_per_chunk 32
@bits_per_byte 8
@bits_per_chunk @bytes_per_chunk * @bits_per_byte
Expand All @@ -48,6 +49,41 @@ defmodule LambdaEthereumConsensus.SszEx do
@spec hash_nodes(binary(), binary()) :: binary()
def hash_nodes(left, right), do: :crypto.hash(:sha256, left <> right)

@spec validate_schema!(schema()) :: :ok
def validate_schema!(:bool), do: :ok
def validate_schema!({:int, n}) when n in @allowed_uints, do: :ok
def validate_schema!({:bytes, size}) when size > 0, do: :ok
def validate_schema!({:byte_list, size}) when size > 0, do: :ok
def validate_schema!({:list, :bytes, size}) when size > 0, do: :ok
def validate_schema!({:vector, :bytes, size}) when size > 0, do: :ok
def validate_schema!({:list, sub, size}) when size > 0, do: validate_schema!(sub)
def validate_schema!({:vector, sub, size}) when size > 0, do: validate_schema!(sub)
def validate_schema!({:bitlist, size}) when size > 0, do: :ok
def validate_schema!({:bitvector, size}) when size > 0, do: :ok

def validate_schema!(module) when is_atom(module) do
schema = module.schema()
# validate each sub-schema
{fields, subschemas} = Enum.unzip(schema)
Enum.each(subschemas, &validate_schema!/1)

# check the struct field names match the schema keys
struct_fields =
module.__struct__() |> Map.keys() |> MapSet.new() |> MapSet.delete(:__struct__)

fields = MapSet.new(fields)

if MapSet.equal?(fields, struct_fields) do
:ok
else
missing =
MapSet.symmetric_difference(fields, struct_fields)
|> Enum.map_join(", ", &inspect/1)

raise "The struct and its schema differ by some fields: #{missing}"
end
end

@spec encode(any(), schema()) :: {:ok, binary()} | {:error, String.t()}
def encode(value, {:int, size}), do: encode_int(value, size)
def encode(value, :bool), do: encode_bool(value)
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/attestation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Types.Attestation do
"""
alias LambdaEthereumConsensus.Utils.BitList

@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:aggregation_bits,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/attestation_data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Types.AttestationData do
Related definitions in `native/ssz_nif/src/types/`.
"""

@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:slot,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/attester_slashing.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.AttesterSlashing do
Struct definition for `AttesterSlashing`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:attestation_1,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/beacon_block.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BeaconBlock do
Struct definition for `BeaconBlock`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

alias Types.BeaconBlockBody

Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/beacon_block_body.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BeaconBlockBody do
Struct definition for `BeaconBlockBody`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:randao_reveal,
Expand Down
5 changes: 3 additions & 2 deletions lib/types/beacon_chain/beacon_block_body_deneb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BeaconBlockBodyDeneb do
Struct definition for `BeaconBlockBody`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:randao_reveal,
Expand Down Expand Up @@ -63,7 +63,8 @@ defmodule Types.BeaconBlockBodyDeneb do
{:execution_payload, Types.ExecutionPayloadDeneb},
{:bls_to_execution_changes,
{:list, Types.BLSToExecutionChange, ChainSpec.get("MAX_BLS_TO_EXECUTION_CHANGES")}},
{:blob_kzg_commitments, {:list, TypeAliases.kzg_commitment()}}
{:blob_kzg_commitments,
{:list, TypeAliases.kzg_commitment(), ChainSpec.get("MAX_BLOB_COMMITMENTS_PER_BLOCK")}}
Copy link
Collaborator Author

@MegaRedHand MegaRedHand Mar 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one. Basically, the max_size for the list was missing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also extensible, so we could potentially add more checks in the future.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super cool!

]
end
end
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/beacon_block_deneb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BeaconBlockDeneb do
Struct definition for `BeaconBlock`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:slot,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/beacon_block_header.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BeaconBlockHeader do
Struct definition for `BeaconBlockHeader`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:slot,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/beacon_state.ex
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ defmodule Types.BeaconState do
end

unless HardForkAliasInjection.deneb?() do
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

alias LambdaEthereumConsensus.StateTransition.Accessors, warn: false
alias LambdaEthereumConsensus.StateTransition.Predicates, warn: false
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/beacon_state_deneb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ defmodule Types.BeaconStateDeneb do
end

if HardForkAliasInjection.deneb?() do
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

alias LambdaEthereumConsensus.StateTransition.Accessors, warn: false
alias LambdaEthereumConsensus.StateTransition.Predicates, warn: false
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/blob_identifier.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BlobIdentifier do
Struct definition for `BlobIdentifier`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:block_root,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/blob_sidecar.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BlobSidecar do
Struct definition for `BlobSidecar`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:index,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/bls_to_execution_change.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.BLSToExecutionChange do
Struct definition for `BLSToExecutionChange`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:validator_index,
Expand Down
3 changes: 2 additions & 1 deletion lib/types/beacon_chain/checkpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ defmodule Types.Checkpoint do
Related definitions in `native/ssz_nif/src/types/`.
"""

@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:root,
:epoch
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/deposit.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.Deposit do
Struct definition for `Deposit`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:proof,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/deposit_data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.DepositData do
Struct definition for `DepositData`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:pubkey,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/deposit_message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.DepositMessage do
Struct definition for `DepositMessage`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:pubkey,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/eth1_data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.Eth1Data do
Struct definition for `Eth1Data`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:deposit_root,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/execution_payload.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.ExecutionPayload do
Struct definition for `ExecutionPayload`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:parent_hash,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/execution_payload_deneb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.ExecutionPayloadDeneb do
Struct definition for `ExecutionPayload`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:parent_hash,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/execution_payload_header.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.ExecutionPayloadHeader do
Struct definition for `ExecutionPayloadHeader`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

@default_execution_payload_header %{
parent_hash: <<0::256>>,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/execution_payload_header_deneb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.ExecutionPayloadHeaderDeneb do
Struct definition for `ExecutionPayloadHeader`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

@default_execution_payload_header %{
parent_hash: <<0::256>>,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/fork.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Types.Fork do
Related definitions in `native/ssz_nif/src/types/`.
"""

@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:previous_version,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/fork_data.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Types.ForkData do
Related definitions in `native/ssz_nif/src/types/`.
"""

@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:current_version,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/historical_batch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.HistoricalBatch do
Struct definition for `HistoricalBatch`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:block_roots,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/historical_summary.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Types.HistoricalSummary do
`HistoricalSummary` matches the components of the phase0 `HistoricalBatch`
making the two hash_tree_root-compatible.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:block_summary_root,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/indexed_attestation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.IndexedAttestation do
Struct definition for `IndexedAttestation`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:attesting_indices,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/pending_attestation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Types.PendingAttestation do
"""
alias LambdaEthereumConsensus.Utils.BitList

@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:aggregation_bits,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/proposer_slashing.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.ProposerSlashing do
Struct definition for `ProposerSlashing`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:signed_header_1,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/signed_beacon_block.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.SignedBeaconBlock do
Struct definition for `SignedBeaconBlock`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:message,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/signed_beacon_block_deneb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.SignedBeaconBlockDeneb do
Struct definition for `SignedBeaconBlock`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:message,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/signed_beacon_block_header.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.SignedBeaconBlockHeader do
Struct definition for `SignedBeaconBlockHeader`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:message,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/signed_bls_to_execution_change.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.SignedBLSToExecutionChange do
Struct definition for `SignedBLSToExecutionChange`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:message,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/beacon_chain/signed_voluntary_exit.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Types.SignedVoluntaryExit do
Struct definition for `SignedVoluntaryExit`.
Related definitions in `native/ssz_nif/src/types/`.
"""
@behaviour LambdaEthereumConsensus.Container
use LambdaEthereumConsensus.Container

fields = [
:message,
Expand Down
Loading
Loading