├── .gitmodules ├── codecov.yml ├── cmd └── sszgen │ ├── utils.go │ ├── forks.go │ ├── tags.go │ ├── parser.go │ ├── main.go │ └── types.go ├── go.mod ├── tests ├── testtypes │ └── consensus-spec-tests │ │ ├── gen_single_field_test_struct_ssz.go │ │ ├── gen_small_test_struct_ssz.go │ │ ├── gen_checkpoint_ssz.go │ │ ├── gen_voluntary_exit_ssz.go │ │ ├── gen_fixed_test_struct_ssz.go │ │ ├── gen_historical_summary_ssz.go │ │ ├── gen_sync_aggregate_ssz.go │ │ ├── gen_sync_committee_ssz.go │ │ ├── gen_historical_batch_ssz.go │ │ ├── gen_single_field_test_struct_monolith_ssz.go │ │ ├── gen_eth1_data_ssz.go │ │ ├── gen_eth1_block_ssz.go │ │ ├── gen_fork_ssz.go │ │ ├── gen_historical_batch_variation_ssz.go │ │ ├── gen_deposit_message_ssz.go │ │ ├── gen_withdrawal_ssz.go │ │ ├── gen_bls_to_execution_change_ssz.go │ │ ├── gen_small_test_struct_monolith_ssz.go │ │ ├── gen_withdrawal_variation_ssz.go │ │ ├── gen_deposit_data_ssz.go │ │ ├── gen_fixed_test_struct_monolith_ssz.go │ │ ├── gen_beacon_block_header_ssz.go │ │ ├── gen_deposit_ssz.go │ │ ├── gen_signed_voluntary_exit_ssz.go │ │ ├── gen_signed_beacon_block_header_ssz.go │ │ ├── gen_proposer_slashing_ssz.go │ │ ├── gen_signed_bls_to_execution_change_ssz.go │ │ ├── gen_aggregate_and_proof_ssz.go │ │ ├── types_basics.go │ │ ├── gen_attester_slashing_ssz.go │ │ ├── gen_beacon_block_ssz.go │ │ ├── gen_bits_struct_ssz.go │ │ ├── gen_attestation_data_ssz.go │ │ ├── gen_validator_ssz.go │ │ ├── gen_attestation_ssz.go │ │ ├── gen_validator_monolith_ssz.go │ │ ├── gen_indexed_attestation_ssz.go │ │ ├── gen_bits_struct_monolith_ssz.go │ │ ├── gen_attestation_data_variation_1_ssz.go │ │ ├── gen_attestation_data_variation_3_ssz.go │ │ ├── gen_attestation_data_variation_2_ssz.go │ │ ├── gen_pending_attestation_ssz.go │ │ ├── gen_attestation_variation_1_ssz.go │ │ ├── gen_attestation_variation_3_ssz.go │ │ ├── gen_attestation_variation_2_ssz.go │ │ ├── gen_execution_payload_header_ssz.go │ │ ├── gen_execution_payload_header_capella_ssz.go │ │ ├── gen_execution_payload_header_deneb_ssz.go │ │ ├── gen_execution_payload_ssz.go │ │ ├── gen_execution_payload_variation_ssz.go │ │ ├── gen_beacon_block_body_ssz.go │ │ ├── gen_execution_payload_capella_ssz.go │ │ ├── gen_beacon_block_body_altair_ssz.go │ │ ├── gen_execution_payload_deneb_ssz.go │ │ ├── gen_beacon_block_body_bellatrix_ssz.go │ │ ├── gen_execution_payload_header_monolith_ssz.go │ │ ├── types_variation.go │ │ ├── gen_beacon_block_body_capella_ssz.go │ │ ├── gen_beacon_block_body_deneb_ssz.go │ │ ├── gen_execution_payload_monolith_2_ssz.go │ │ ├── gen_execution_payload_monolith_ssz.go │ │ ├── gen_beacon_block_body_monolith_ssz.go │ │ ├── gen_beacon_state_ssz.go │ │ ├── gen_beacon_state_altair_ssz.go │ │ ├── gen_beacon_state_bellatrix_ssz.go │ │ ├── gen_beacon_state_deneb_ssz.go │ │ ├── gen_beacon_state_capella_ssz.go │ │ └── types_monoliths.go ├── manual_test.go ├── zeroval_test.go └── corner_cases_test.go ├── scripts └── fuzz.sh ├── utils.go ├── example_checked_test.go ├── .github └── workflows │ └── tests.yml ├── example_static_test.go ├── COPYING ├── zeroes.go ├── go.sum ├── example_asymmetric_test.go ├── sizer.go ├── errors.go ├── generics.go ├── forks.go └── example_dynamic_test.go /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tests/testdata/consensus-spec-tests"] 2 | path = tests/testdata/consensus-spec-tests 3 | url = https://github.com/ethereum/consensus-spec-tests 4 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: no 4 | patch: no 5 | 6 | comment: 7 | layout: "header, diff, flags, components" 8 | 9 | component_management: 10 | individual_components: 11 | - component_id: package_ssz 12 | name: ssz 13 | paths: 14 | - "*" 15 | - component_id: command_sszgen 16 | name: sszgen 17 | paths: 18 | - "cmd/sszgen/**" 19 | -------------------------------------------------------------------------------- /cmd/sszgen/utils.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package main 6 | 7 | import ( 8 | "strings" 9 | ) 10 | 11 | func pkgName(pkgPath string) string { 12 | index := strings.LastIndex(pkgPath, "/") 13 | if index == -1 { 14 | return pkgPath // universal package 15 | } 16 | return pkgPath[index+1:] 17 | } 18 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/karalabe/ssz 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/golang/snappy v0.0.4 7 | github.com/holiman/uint256 v1.3.1 8 | github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 9 | github.com/prysmaticlabs/gohashtree v0.0.4-beta 10 | golang.org/x/sync v0.7.0 11 | golang.org/x/tools v0.22.0 12 | gopkg.in/yaml.v3 v3.0.1 13 | ) 14 | 15 | require ( 16 | github.com/klauspost/cpuid/v2 v2.0.9 // indirect 17 | golang.org/x/mod v0.18.0 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_single_field_test_struct_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *SingleFieldTestStruct) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 1 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *SingleFieldTestStruct) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint8(codec, &obj.A) // Field (0) - A - 1 bytes 15 | } 16 | -------------------------------------------------------------------------------- /scripts/fuzz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Source: https://github.com/golang/go/issues/46312#issuecomment-1727928218 4 | 5 | fuzzTime=${1:-1m} 6 | 7 | files=$(grep -r --include='**_test.go' --files-with-matches 'func Fuzz' .) 8 | for file in ${files}; do 9 | funcs=$(grep '^func Fuzz' "$file" | sed s/func\ // | sed 's/(.*$//') 10 | 11 | for func in ${funcs}; do 12 | echo "Fuzzing $func in $file" 13 | parentDir=$(dirname "$file") 14 | go test "$parentDir" -run="$func" -fuzz="^$func$" -fuzztime="${fuzzTime}" 15 | done 16 | done 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_small_test_struct_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *SmallTestStruct) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 2 + 2 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *SmallTestStruct) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint16(codec, &obj.A) // Field (0) - A - 2 bytes 15 | ssz.DefineUint16(codec, &obj.B) // Field (1) - B - 2 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_checkpoint_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *Checkpoint) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8 + 32 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *Checkpoint) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint64(codec, &obj.Epoch) // Field (0) - Epoch - 8 bytes 15 | ssz.DefineStaticBytes(codec, &obj.Root) // Field (1) - Root - 32 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_voluntary_exit_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *VoluntaryExit) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8 + 8 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *VoluntaryExit) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint64(codec, &obj.Epoch) // Field (0) - Epoch - 8 bytes 15 | ssz.DefineUint64(codec, &obj.ValidatorIndex) // Field (1) - ValidatorIndex - 8 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *FixedTestStruct) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 1 + 8 + 4 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *FixedTestStruct) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint8(codec, &obj.A) // Field (0) - A - 1 bytes 15 | ssz.DefineUint64(codec, &obj.B) // Field (1) - B - 8 bytes 16 | ssz.DefineUint32(codec, &obj.C) // Field (2) - C - 4 bytes 17 | } 18 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_historical_summary_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *HistoricalSummary) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 32 + 32 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *HistoricalSummary) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineStaticBytes(codec, &obj.BlockSummaryRoot) // Field (0) - BlockSummaryRoot - 32 bytes 15 | ssz.DefineStaticBytes(codec, &obj.StateSummaryRoot) // Field (1) - StateSummaryRoot - 32 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_sync_aggregate_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *SyncAggregate) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 64 + 96 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *SyncAggregate) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineStaticBytes(codec, &obj.SyncCommiteeBits) // Field (0) - SyncCommiteeBits - 64 bytes 15 | ssz.DefineStaticBytes(codec, &obj.SyncCommiteeSignature) // Field (1) - SyncCommiteeSignature - 96 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_sync_committee_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *SyncCommittee) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 512*48 + 48 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *SyncCommittee) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.PubKeys[:]) // Field (0) - PubKeys - 24576 bytes 15 | ssz.DefineStaticBytes(codec, &obj.AggregatePubKey) // Field (1) - AggregatePubKey - 48 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_historical_batch_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *HistoricalBatch) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8192*32 + 8192*32 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *HistoricalBatch) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field (0) - BlockRoots - 262144 bytes 15 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.StateRoots[:]) // Field (1) - StateRoots - 262144 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_single_field_test_struct_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *SingleFieldTestStructMonolith) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 9 | if sizer.Fork() >= ssz.ForkUnknown { 10 | size += 1 11 | } 12 | return size 13 | } 14 | 15 | // DefineSSZ defines how an object is encoded/decoded. 16 | func (obj *SingleFieldTestStructMonolith) DefineSSZ(codec *ssz.Codec) { 17 | ssz.DefineUint8PointerOnFork(codec, &obj.A, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (0) - A - 1 bytes 18 | } 19 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_eth1_data_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *Eth1Data) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 32 + 8 + 32 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *Eth1Data) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineStaticBytes(codec, &obj.DepositRoot) // Field (0) - DepositRoot - 32 bytes 15 | ssz.DefineUint64(codec, &obj.DepositCount) // Field (1) - DepositCount - 8 bytes 16 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (2) - BlockHash - 32 bytes 17 | } 18 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_eth1_block_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *Eth1Block) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8 + 32 + 8 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *Eth1Block) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint64(codec, &obj.Timestamp) // Field (0) - Timestamp - 8 bytes 15 | ssz.DefineStaticBytes(codec, &obj.DepositRoot) // Field (1) - DepositRoot - 32 bytes 16 | ssz.DefineUint64(codec, &obj.DepositCount) // Field (2) - DepositCount - 8 bytes 17 | } 18 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_fork_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *Fork) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 4 + 4 + 8 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *Fork) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineStaticBytes(codec, &obj.PreviousVersion) // Field (0) - PreviousVersion - 4 bytes 15 | ssz.DefineStaticBytes(codec, &obj.CurrentVersion) // Field (1) - CurrentVersion - 4 bytes 16 | ssz.DefineUint64(codec, &obj.Epoch) // Field (2) - Epoch - 8 bytes 17 | } 18 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_historical_batch_variation_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *HistoricalBatchVariation) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8192*32 + 8192*32 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *HistoricalBatchVariation) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field (0) - BlockRoots - 262144 bytes 15 | ssz.DefineCheckedArrayOfStaticBytes(codec, &obj.StateRoots, 8192) // Field (1) - StateRoots - 262144 bytes 16 | } 17 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_deposit_message_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *DepositMessage) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 48 + 32 + 8 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *DepositMessage) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineStaticBytes(codec, &obj.Pubkey) // Field (0) - Pubkey - 48 bytes 15 | ssz.DefineStaticBytes(codec, &obj.WithdrawalCredentials) // Field (1) - WithdrawalCredentials - 32 bytes 16 | ssz.DefineUint64(codec, &obj.Amount) // Field (2) - Amount - 8 bytes 17 | } 18 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_withdrawal_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *Withdrawal) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8 + 8 + 20 + 8 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *Withdrawal) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint64(codec, &obj.Index) // Field (0) - Index - 8 bytes 15 | ssz.DefineUint64(codec, &obj.Validator) // Field (1) - Validator - 8 bytes 16 | ssz.DefineStaticBytes(codec, &obj.Address) // Field (2) - Address - 20 bytes 17 | ssz.DefineUint64(codec, &obj.Amount) // Field (3) - Amount - 8 bytes 18 | } 19 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_bls_to_execution_change_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *BLSToExecutionChange) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8 + 48 + 20 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *BLSToExecutionChange) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint64(codec, &obj.ValidatorIndex) // Field (0) - ValidatorIndex - 8 bytes 15 | ssz.DefineStaticBytes(codec, &obj.FromBLSPubKey) // Field (1) - FromBLSPubKey - 48 bytes 16 | ssz.DefineStaticBytes(codec, &obj.ToExecutionAddress) // Field (2) - ToExecutionAddress - 20 bytes 17 | } 18 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_small_test_struct_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *SmallTestStructMonolith) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 9 | if sizer.Fork() >= ssz.ForkUnknown { 10 | size += 2 11 | } 12 | size += 2 13 | return size 14 | } 15 | 16 | // DefineSSZ defines how an object is encoded/decoded. 17 | func (obj *SmallTestStructMonolith) DefineSSZ(codec *ssz.Codec) { 18 | ssz.DefineUint16PointerOnFork(codec, &obj.A, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (0) - A - 2 bytes 19 | ssz.DefineUint16(codec, &obj.B) // Field (1) - B - 2 bytes 20 | } 21 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_withdrawal_variation_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *WithdrawalVariation) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8 + 8 + 20 + 8 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *WithdrawalVariation) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint64(codec, &obj.Index) // Field (0) - Index - 8 bytes 15 | ssz.DefineUint64(codec, &obj.Validator) // Field (1) - Validator - 8 bytes 16 | ssz.DefineCheckedStaticBytes(codec, &obj.Address, 20) // Field (2) - Address - 20 bytes 17 | ssz.DefineUint64(codec, &obj.Amount) // Field (3) - Amount - 8 bytes 18 | } 19 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_deposit_data_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *DepositData) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 48 + 32 + 8 + 96 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *DepositData) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineStaticBytes(codec, &obj.Pubkey) // Field (0) - Pubkey - 48 bytes 15 | ssz.DefineStaticBytes(codec, &obj.WithdrawalCredentials) // Field (1) - WithdrawalCredentials - 32 bytes 16 | ssz.DefineUint64(codec, &obj.Amount) // Field (2) - Amount - 8 bytes 17 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (3) - Signature - 96 bytes 18 | } 19 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_fixed_test_struct_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *FixedTestStructMonolith) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 9 | if sizer.Fork() >= ssz.ForkUnknown { 10 | size += 1 + 8 + 4 11 | } 12 | return size 13 | } 14 | 15 | // DefineSSZ defines how an object is encoded/decoded. 16 | func (obj *FixedTestStructMonolith) DefineSSZ(codec *ssz.Codec) { 17 | ssz.DefineUint8PointerOnFork(codec, &obj.A, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (0) - A - 1 bytes 18 | ssz.DefineUint64PointerOnFork(codec, &obj.B, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (1) - B - 8 bytes 19 | ssz.DefineUint32PointerOnFork(codec, &obj.C, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (2) - C - 4 bytes 20 | } 21 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_header_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *BeaconBlockHeader) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 8 + 8 + 32 + 32 + 32 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *BeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineUint64(codec, &obj.Slot) // Field (0) - Slot - 8 bytes 15 | ssz.DefineUint64(codec, &obj.ProposerIndex) // Field (1) - ProposerIndex - 8 bytes 16 | ssz.DefineStaticBytes(codec, &obj.ParentRoot) // Field (2) - ParentRoot - 32 bytes 17 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field (3) - StateRoot - 32 bytes 18 | ssz.DefineStaticBytes(codec, &obj.BodyRoot) // Field (4) - BodyRoot - 32 bytes 19 | } 20 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_deposit_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheDeposit = ssz.PrecomputeStaticSizeCache((*Deposit)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *Deposit) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheDeposit) { 13 | return staticSizeCacheDeposit[fork] 14 | } 15 | size = 33*32 + (*DepositData)(nil).SizeSSZ(sizer) 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *Deposit) DefineSSZ(codec *ssz.Codec) { 21 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.Proof[:]) // Field (0) - Proof - 1056 bytes 22 | ssz.DefineStaticObject(codec, &obj.Data) // Field (1) - Data - ? bytes (DepositData) 23 | } 24 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_signed_voluntary_exit_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheSignedVoluntaryExit = ssz.PrecomputeStaticSizeCache((*SignedVoluntaryExit)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *SignedVoluntaryExit) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheSignedVoluntaryExit) { 13 | return staticSizeCacheSignedVoluntaryExit[fork] 14 | } 15 | size = (*VoluntaryExit)(nil).SizeSSZ(sizer) + 96 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *SignedVoluntaryExit) DefineSSZ(codec *ssz.Codec) { 21 | ssz.DefineStaticObject(codec, &obj.Exit) // Field (0) - Exit - ? bytes (VoluntaryExit) 22 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (1) - Signature - 96 bytes 23 | } 24 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_signed_beacon_block_header_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheSignedBeaconBlockHeader = ssz.PrecomputeStaticSizeCache((*SignedBeaconBlockHeader)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *SignedBeaconBlockHeader) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheSignedBeaconBlockHeader) { 13 | return staticSizeCacheSignedBeaconBlockHeader[fork] 14 | } 15 | size = (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 96 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *SignedBeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { 21 | ssz.DefineStaticObject(codec, &obj.Header) // Field (0) - Header - ? bytes (BeaconBlockHeader) 22 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (1) - Signature - 96 bytes 23 | } 24 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_proposer_slashing_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheProposerSlashing = ssz.PrecomputeStaticSizeCache((*ProposerSlashing)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *ProposerSlashing) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheProposerSlashing) { 13 | return staticSizeCacheProposerSlashing[fork] 14 | } 15 | size = (*SignedBeaconBlockHeader)(nil).SizeSSZ(sizer) + (*SignedBeaconBlockHeader)(nil).SizeSSZ(sizer) 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *ProposerSlashing) DefineSSZ(codec *ssz.Codec) { 21 | ssz.DefineStaticObject(codec, &obj.Header1) // Field (0) - Header1 - ? bytes (SignedBeaconBlockHeader) 22 | ssz.DefineStaticObject(codec, &obj.Header2) // Field (1) - Header2 - ? bytes (SignedBeaconBlockHeader) 23 | } 24 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz 6 | 7 | import "fmt" 8 | 9 | // PrecomputeStaticSizeCache is a helper to precompute SSZ (static) sizes for a 10 | // monolith type on different forks. 11 | // 12 | // For non-monolith types that are constant across forks (or are not meant to be 13 | // used across forks), all the sizes will be the same so might as well hard-code 14 | // it instead. 15 | func PrecomputeStaticSizeCache(obj Object) []uint32 { 16 | var ( 17 | sizes = make([]uint32, ForkFuture) 18 | sizer = &Sizer{codec: new(Codec)} 19 | ) 20 | switch v := obj.(type) { 21 | case StaticObject: 22 | for fork := 0; fork < len(sizes); fork++ { 23 | sizer.codec.fork = Fork(fork) 24 | sizes[fork] = v.SizeSSZ(sizer) 25 | } 26 | case DynamicObject: 27 | for fork := 0; fork < len(sizes); fork++ { 28 | sizer.codec.fork = Fork(fork) 29 | sizes[fork] = v.SizeSSZ(sizer, true) 30 | } 31 | default: 32 | panic(fmt.Sprintf("unsupported type: %T", obj)) 33 | } 34 | return sizes 35 | } 36 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_signed_bls_to_execution_change_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheSignedBLSToExecutionChange = ssz.PrecomputeStaticSizeCache((*SignedBLSToExecutionChange)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *SignedBLSToExecutionChange) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheSignedBLSToExecutionChange) { 13 | return staticSizeCacheSignedBLSToExecutionChange[fork] 14 | } 15 | size = (*BLSToExecutionChange)(nil).SizeSSZ(sizer) + 96 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *SignedBLSToExecutionChange) DefineSSZ(codec *ssz.Codec) { 21 | ssz.DefineStaticObject(codec, &obj.Message) // Field (0) - Message - ? bytes (BLSToExecutionChange) 22 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (1) - Signature - 96 bytes 23 | } 24 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_aggregate_and_proof_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *AggregateAndProof) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 8 + 4 + 96 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicObject(sizer, obj.Aggregate) 15 | 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *AggregateAndProof) DefineSSZ(codec *ssz.Codec) { 21 | // Define the static data (fields and dynamic offsets) 22 | ssz.DefineUint64(codec, &obj.Index) // Field (0) - Index - 8 bytes 23 | ssz.DefineDynamicObjectOffset(codec, &obj.Aggregate) // Offset (1) - Aggregate - 4 bytes 24 | ssz.DefineStaticBytes(codec, &obj.SelectionProof) // Field (2) - SelectionProof - 96 bytes 25 | 26 | // Define the dynamic data (fields) 27 | ssz.DefineDynamicObjectContent(codec, &obj.Aggregate) // Field (1) - Aggregate - ? bytes 28 | } 29 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/types_basics.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package consensus_spec_tests 6 | 7 | import "github.com/prysmaticlabs/go-bitfield" 8 | 9 | //go:generate go run -cover ../../../cmd/sszgen -type SingleFieldTestStruct -out gen_single_field_test_struct_ssz.go 10 | //go:generate go run -cover ../../../cmd/sszgen -type SmallTestStruct -out gen_small_test_struct_ssz.go 11 | //go:generate go run -cover ../../../cmd/sszgen -type FixedTestStruct -out gen_fixed_test_struct_ssz.go 12 | //go:generate go run -cover ../../../cmd/sszgen -type BitsStruct -out gen_bits_struct_ssz.go 13 | 14 | type SingleFieldTestStruct struct { 15 | A byte 16 | } 17 | 18 | type SmallTestStruct struct { 19 | A uint16 20 | B uint16 21 | } 22 | 23 | type FixedTestStruct struct { 24 | A uint8 25 | B uint64 26 | C uint32 27 | } 28 | 29 | type BitsStruct struct { 30 | A bitfield.Bitlist `ssz-max:"5"` 31 | B [1]byte `ssz-size:"2" ssz:"bits"` 32 | C [1]byte `ssz-size:"1" ssz:"bits"` 33 | D bitfield.Bitlist `ssz-max:"6"` 34 | E [1]byte `ssz-size:"8" ssz:"bits"` 35 | } 36 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attester_slashing_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *AttesterSlashing) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 4 + 4 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicObject(sizer, obj.Attestation1) 15 | size += ssz.SizeDynamicObject(sizer, obj.Attestation2) 16 | 17 | return size 18 | } 19 | 20 | // DefineSSZ defines how an object is encoded/decoded. 21 | func (obj *AttesterSlashing) DefineSSZ(codec *ssz.Codec) { 22 | // Define the static data (fields and dynamic offsets) 23 | ssz.DefineDynamicObjectOffset(codec, &obj.Attestation1) // Offset (0) - Attestation1 - 4 bytes 24 | ssz.DefineDynamicObjectOffset(codec, &obj.Attestation2) // Offset (1) - Attestation2 - 4 bytes 25 | 26 | // Define the dynamic data (fields) 27 | ssz.DefineDynamicObjectContent(codec, &obj.Attestation1) // Field (0) - Attestation1 - ? bytes 28 | ssz.DefineDynamicObjectContent(codec, &obj.Attestation2) // Field (1) - Attestation2 - ? bytes 29 | } 30 | -------------------------------------------------------------------------------- /example_checked_test.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz_test 6 | 7 | import ( 8 | "fmt" 9 | 10 | "github.com/karalabe/ssz" 11 | ) 12 | 13 | type WithdrawalChecked struct { 14 | Index uint64 `ssz-size:"8"` 15 | Validator uint64 `ssz-size:"8"` 16 | Address []byte `ssz-size:"20"` 17 | Amount uint64 `ssz-size:"8"` 18 | } 19 | 20 | func (w *WithdrawalChecked) SizeSSZ(siz *ssz.Sizer) uint32 { return 44 } 21 | 22 | func (w *WithdrawalChecked) DefineSSZ(codec *ssz.Codec) { 23 | ssz.DefineUint64(codec, &w.Index) // Field (0) - Index - 8 bytes 24 | ssz.DefineUint64(codec, &w.Validator) // Field (1) - ValidatorIndex - 8 bytes 25 | ssz.DefineCheckedStaticBytes(codec, &w.Address, 20) // Field (2) - Address - 20 bytes 26 | ssz.DefineUint64(codec, &w.Amount) // Field (3) - Amount - 8 bytes 27 | } 28 | 29 | func ExampleDecodeCheckedObject() { 30 | blob := make([]byte, 44) 31 | 32 | obj := new(WithdrawalChecked) 33 | if err := ssz.DecodeFromBytes(blob, obj); err != nil { 34 | panic(err) 35 | } 36 | fmt.Printf("obj: %#x\n", obj) 37 | // Output: 38 | // obj: &{0x0 0x0 0x0000000000000000000000000000000000000000 0x0} 39 | } 40 | -------------------------------------------------------------------------------- /cmd/sszgen/forks.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package main 6 | 7 | // forkMapping maps fork names to fork values. This is used internally by the 8 | // ssz codec generator to convert tags to values. 9 | var forkMapping = map[string]string{ 10 | "unknown": "Unknown", 11 | "frontier": "Frontier", 12 | "homestead": "Homestead", 13 | "dao": "DAO", 14 | "tangerine": "Tangerine", 15 | "spurious": "Spurious", 16 | "byzantium": "Byzantium", 17 | "constantinople": "Constantinople", 18 | "istanbul": "Istanbul", 19 | "muir": "Muir", 20 | "phase0": "Phase0", 21 | "berlin": "Berlin", 22 | "london": "London", 23 | "altair": "Altair", 24 | "arrow": "Arrow", 25 | "gray": "Gray", 26 | "bellatrix": "Bellatrix", 27 | "paris": "Paris", 28 | "merge": "Merge", 29 | "shapella": "Shapella", 30 | "shanghai": "Shanghai", 31 | "capella": "Capella", 32 | "dencun": "Dencun", 33 | "cancun": "Cancun", 34 | "deneb": "Deneb", 35 | "pectra": "Pectra", 36 | "prague": "Prague", 37 | "electra": "Electra", 38 | "future": "Future", 39 | } 40 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *BeaconBlock) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 8 + 8 + 32 + 32 + 4 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicObject(sizer, obj.Body) 15 | 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *BeaconBlock) DefineSSZ(codec *ssz.Codec) { 21 | // Define the static data (fields and dynamic offsets) 22 | ssz.DefineUint64(codec, &obj.Slot) // Field (0) - Slot - 8 bytes 23 | ssz.DefineUint64(codec, &obj.ProposerIndex) // Field (1) - ProposerIndex - 8 bytes 24 | ssz.DefineStaticBytes(codec, &obj.ParentRoot) // Field (2) - ParentRoot - 32 bytes 25 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field (3) - StateRoot - 32 bytes 26 | ssz.DefineDynamicObjectOffset(codec, &obj.Body) // Offset (4) - Body - 4 bytes 27 | 28 | // Define the dynamic data (fields) 29 | ssz.DefineDynamicObjectContent(codec, &obj.Body) // Field (4) - Body - ? bytes 30 | } 31 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_bits_struct_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *BitsStruct) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 4 + 1 + 1 + 4 + 1 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeSliceOfBits(sizer, obj.A) 15 | size += ssz.SizeSliceOfBits(sizer, obj.D) 16 | 17 | return size 18 | } 19 | 20 | // DefineSSZ defines how an object is encoded/decoded. 21 | func (obj *BitsStruct) DefineSSZ(codec *ssz.Codec) { 22 | // Define the static data (fields and dynamic offsets) 23 | ssz.DefineSliceOfBitsOffset(codec, &obj.A, 5) // Offset (0) - A - 4 bytes 24 | ssz.DefineArrayOfBits(codec, &obj.B, 2) // Field (1) - B - 1 bytes 25 | ssz.DefineArrayOfBits(codec, &obj.C, 1) // Field (2) - C - 1 bytes 26 | ssz.DefineSliceOfBitsOffset(codec, &obj.D, 6) // Offset (3) - D - 4 bytes 27 | ssz.DefineArrayOfBits(codec, &obj.E, 8) // Field (4) - E - 1 bytes 28 | 29 | // Define the dynamic data (fields) 30 | ssz.DefineSliceOfBitsContent(codec, &obj.A, 5) // Field (0) - A - ? bytes 31 | ssz.DefineSliceOfBitsContent(codec, &obj.D, 6) // Field (3) - D - ? bytes 32 | } 33 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_data_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestationData = ssz.PrecomputeStaticSizeCache((*AttestationData)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *AttestationData) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestationData) { 13 | return staticSizeCacheAttestationData[fork] 14 | } 15 | size = 8 + 8 + 32 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *AttestationData) DefineSSZ(codec *ssz.Codec) { 21 | ssz.DefineUint64(codec, &obj.Slot) // Field (0) - Slot - 8 bytes 22 | ssz.DefineUint64(codec, &obj.Index) // Field (1) - Index - 8 bytes 23 | ssz.DefineStaticBytes(codec, &obj.BeaconBlockHash) // Field (2) - BeaconBlockHash - 32 bytes 24 | ssz.DefineStaticObject(codec, &obj.Source) // Field (3) - Source - ? bytes (Checkpoint) 25 | ssz.DefineStaticObject(codec, &obj.Target) // Field (4) - Target - ? bytes (Checkpoint) 26 | } 27 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_validator_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *Validator) SizeSSZ(sizer *ssz.Sizer) uint32 { 9 | return 48 + 32 + 8 + 1 + 8 + 8 + 8 + 8 10 | } 11 | 12 | // DefineSSZ defines how an object is encoded/decoded. 13 | func (obj *Validator) DefineSSZ(codec *ssz.Codec) { 14 | ssz.DefineStaticBytes(codec, &obj.Pubkey) // Field (0) - Pubkey - 48 bytes 15 | ssz.DefineStaticBytes(codec, &obj.WithdrawalCredentials) // Field (1) - WithdrawalCredentials - 32 bytes 16 | ssz.DefineUint64(codec, &obj.EffectiveBalance) // Field (2) - EffectiveBalance - 8 bytes 17 | ssz.DefineBool(codec, &obj.Slashed) // Field (3) - Slashed - 1 bytes 18 | ssz.DefineUint64(codec, &obj.ActivationEligibilityEpoch) // Field (4) - ActivationEligibilityEpoch - 8 bytes 19 | ssz.DefineUint64(codec, &obj.ActivationEpoch) // Field (5) - ActivationEpoch - 8 bytes 20 | ssz.DefineUint64(codec, &obj.ExitEpoch) // Field (6) - ExitEpoch - 8 bytes 21 | ssz.DefineUint64(codec, &obj.WithdrawableEpoch) // Field (7) - WithdrawableEpoch - 8 bytes 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | os: [ubuntu-latest, macos-latest] 14 | go-version: ['stable', 'oldstable'] 15 | runs-on: ${{ matrix.os }} 16 | 17 | steps: 18 | - name: Enable long paths on git checkouts 19 | run: git config --global core.longpaths true 20 | 21 | - uses: actions/checkout@v4 22 | with: 23 | submodules: 'true' 24 | lfs: 'true' 25 | 26 | - name: Set up Go ${{ matrix.go-version }} 27 | uses: actions/setup-go@v5 28 | with: 29 | go-version: ${{ matrix.go-version }} 30 | 31 | - name: Build 32 | run: go build -v ./... 33 | 34 | - name: Test with coverage 35 | run: go test -v -coverprofile="coverage-${{ matrix.os }}-${{ matrix.go-version }}.txt" -coverpkg=./... ./... 36 | 37 | - name: Codegen with coverage 38 | env: 39 | GOCOVERDIR: "${{ github.workspace }}/coverage" 40 | run: | 41 | mkdir coverage 42 | go generate ./... 43 | go tool covdata textfmt -i=coverage -o=coverage-sszgen-${{ matrix.os }}-${{ matrix.go-version }}.txt 44 | 45 | - name: Upload coverage reports to Codecov 46 | uses: codecov/codecov-action@v4.5.0 47 | with: 48 | token: ${{ secrets.CODECOV_TOKEN }} 49 | -------------------------------------------------------------------------------- /example_static_test.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz_test 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | 11 | "github.com/karalabe/ssz" 12 | ) 13 | 14 | type Address [20]byte 15 | 16 | type Withdrawal struct { 17 | Index uint64 `ssz-size:"8"` 18 | Validator uint64 `ssz-size:"8"` 19 | Address Address `ssz-size:"20"` 20 | Amount uint64 `ssz-size:"8"` 21 | } 22 | 23 | func (w *Withdrawal) SizeSSZ(siz *ssz.Sizer) uint32 { return 44 } 24 | 25 | func (w *Withdrawal) DefineSSZ(codec *ssz.Codec) { 26 | ssz.DefineUint64(codec, &w.Index) // Field (0) - Index - 8 bytes 27 | ssz.DefineUint64(codec, &w.Validator) // Field (1) - ValidatorIndex - 8 bytes 28 | ssz.DefineStaticBytes(codec, &w.Address) // Field (2) - Address - 20 bytes 29 | ssz.DefineUint64(codec, &w.Amount) // Field (3) - Amount - 8 bytes 30 | } 31 | 32 | func ExampleEncodeStaticObject() { 33 | out := new(bytes.Buffer) 34 | if err := ssz.EncodeToStream(out, new(Withdrawal)); err != nil { 35 | panic(err) 36 | } 37 | hash := ssz.HashSequential(new(Withdrawal)) 38 | 39 | fmt.Printf("ssz: %#x\nhash: %#x\n", out, hash) 40 | // Output: 41 | // ssz: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 42 | // hash: 0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71 43 | } 44 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright 2024 ssz Authors 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /zeroes.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz 6 | 7 | import ( 8 | "reflect" 9 | "sync" 10 | ) 11 | 12 | // zeroCache contains zero-values for dynamic objects that got hit during codec 13 | // operations. This is a global sync map, meaning it will be slow to access, but 14 | // encoding/hashing zero values should not happen in production code, it's more 15 | // of a sanity thing to handle weird corner-cases without blowing up. 16 | var zeroCache = new(sync.Map) 17 | 18 | // zeroValueStatic retrieves a previously created (or creates one on the fly) 19 | // zero value for a static object to support operating on half-initialized 20 | // objects (useful for tests mainly, but can also avoid crashes in case of bad 21 | // calling parameters). 22 | func zeroValueStatic[T newableStaticObject[U], U any]() T { 23 | kind := reflect.TypeFor[U]() 24 | 25 | if val, ok := zeroCache.Load(kind); ok { 26 | return val.(T) 27 | } 28 | val := T(new(U)) 29 | zeroCache.Store(kind, val) 30 | return val 31 | } 32 | 33 | // zeroValueDynamic retrieves a previously created (or creates one on the fly) 34 | // zero value for a dynamic object to support operating on half-initialized 35 | // objects (useful for tests mainly, but can also avoid crashes in case of bad 36 | // calling parameters). 37 | func zeroValueDynamic[T newableDynamicObject[U], U any]() T { 38 | kind := reflect.TypeFor[U]() 39 | 40 | if val, ok := zeroCache.Load(kind); ok { 41 | return val.(T) 42 | } 43 | val := T(new(U)) 44 | zeroCache.Store(kind, val) 45 | return val 46 | } 47 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestation = ssz.PrecomputeStaticSizeCache((*Attestation)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *Attestation) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestation) { 15 | size = staticSizeCacheAttestation[fork] 16 | } else { 17 | size = 4 + (*AttestationData)(nil).SizeSSZ(sizer) + 96 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfBits(sizer, obj.AggregationBits) 24 | 25 | return size 26 | } 27 | 28 | // DefineSSZ defines how an object is encoded/decoded. 29 | func (obj *Attestation) DefineSSZ(codec *ssz.Codec) { 30 | // Define the static data (fields and dynamic offsets) 31 | ssz.DefineSliceOfBitsOffset(codec, &obj.AggregationBits, 2048) // Offset (0) - AggregationBits - 4 bytes 32 | ssz.DefineStaticObject(codec, &obj.Data) // Field (1) - Data - ? bytes (AttestationData) 33 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (2) - Signature - 96 bytes 34 | 35 | // Define the dynamic data (fields) 36 | ssz.DefineSliceOfBitsContent(codec, &obj.AggregationBits, 2048) // Field (0) - AggregationBits - ? bytes 37 | } 38 | -------------------------------------------------------------------------------- /tests/manual_test.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | 3 | package tests 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | "os" 9 | "testing" 10 | 11 | "github.com/karalabe/ssz" 12 | types "github.com/karalabe/ssz/tests/testtypes/consensus-spec-tests" 13 | ) 14 | 15 | func BenchmarkMainnetState(b *testing.B) { 16 | blob, err := os.ReadFile("../state.ssz") 17 | if err != nil { 18 | panic(err) 19 | } 20 | obj := new(types.BeaconStateDeneb) 21 | if err := ssz.DecodeFromBytes(blob, obj); err != nil { 22 | panic(err) 23 | } 24 | hash := ssz.HashSequential(obj) 25 | 26 | b.Run(fmt.Sprintf("beacon-state/%d-bytes/encode", len(blob)), func(b *testing.B) { 27 | b.SetBytes(int64(len(blob))) 28 | b.ReportAllocs() 29 | b.ResetTimer() 30 | 31 | for i := 0; i < b.N; i++ { 32 | ssz.EncodeToStream(io.Discard, obj) 33 | } 34 | }) 35 | b.Run(fmt.Sprintf("beacon-state/%d-bytes/decode", len(blob)), func(b *testing.B) { 36 | obj := new(types.BeaconStateDeneb) 37 | 38 | b.SetBytes(int64(len(blob))) 39 | b.ReportAllocs() 40 | b.ResetTimer() 41 | 42 | for i := 0; i < b.N; i++ { 43 | ssz.DecodeFromBytes(blob, obj) 44 | } 45 | }) 46 | b.Run(fmt.Sprintf("beacon-state/%d-bytes/merkleize-sequential", len(blob)), func(b *testing.B) { 47 | b.SetBytes(int64(len(blob))) 48 | b.ReportAllocs() 49 | b.ResetTimer() 50 | 51 | for i := 0; i < b.N; i++ { 52 | if ssz.HashSequential(obj) != hash { 53 | panic("hash mismatch") 54 | } 55 | } 56 | }) 57 | b.Run(fmt.Sprintf("beacon-state/%d-bytes/merkleize-concurrent", len(blob)), func(b *testing.B) { 58 | b.SetBytes(int64(len(blob))) 59 | b.ReportAllocs() 60 | b.ResetTimer() 61 | 62 | for i := 0; i < b.N; i++ { 63 | if ssz.HashConcurrent(obj) != hash { 64 | panic("hash mismatch") 65 | } 66 | } 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_validator_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns the total size of the static ssz object. 8 | func (obj *ValidatorMonolith) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 9 | size = 48 + 32 + 8 10 | if sizer.Fork() >= ssz.ForkUnknown { 11 | size += 1 12 | } 13 | size += 8 + 8 + 8 + 8 14 | return size 15 | } 16 | 17 | // DefineSSZ defines how an object is encoded/decoded. 18 | func (obj *ValidatorMonolith) DefineSSZ(codec *ssz.Codec) { 19 | ssz.DefineStaticBytes(codec, &obj.Pubkey) // Field (0) - Pubkey - 48 bytes 20 | ssz.DefineStaticBytes(codec, &obj.WithdrawalCredentials) // Field (1) - WithdrawalCredentials - 32 bytes 21 | ssz.DefineUint64(codec, &obj.EffectiveBalance) // Field (2) - EffectiveBalance - 8 bytes 22 | ssz.DefineBoolPointerOnFork(codec, &obj.Slashed, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (3) - Slashed - 1 bytes 23 | ssz.DefineUint64(codec, &obj.ActivationEligibilityEpoch) // Field (4) - ActivationEligibilityEpoch - 8 bytes 24 | ssz.DefineUint64(codec, &obj.ActivationEpoch) // Field (5) - ActivationEpoch - 8 bytes 25 | ssz.DefineUint64(codec, &obj.ExitEpoch) // Field (6) - ExitEpoch - 8 bytes 26 | ssz.DefineUint64(codec, &obj.WithdrawableEpoch) // Field (7) - WithdrawableEpoch - 8 bytes 27 | } 28 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_indexed_attestation_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheIndexedAttestation = ssz.PrecomputeStaticSizeCache((*IndexedAttestation)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *IndexedAttestation) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheIndexedAttestation) { 15 | size = staticSizeCacheIndexedAttestation[fork] 16 | } else { 17 | size = 4 + (*AttestationData)(nil).SizeSSZ(sizer) + 96 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfUint64s(sizer, obj.AttestationIndices) 24 | 25 | return size 26 | } 27 | 28 | // DefineSSZ defines how an object is encoded/decoded. 29 | func (obj *IndexedAttestation) DefineSSZ(codec *ssz.Codec) { 30 | // Define the static data (fields and dynamic offsets) 31 | ssz.DefineSliceOfUint64sOffset(codec, &obj.AttestationIndices, 2048) // Offset (0) - AttestationIndices - 4 bytes 32 | ssz.DefineStaticObject(codec, &obj.Data) // Field (1) - Data - ? bytes (AttestationData) 33 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (2) - Signature - 96 bytes 34 | 35 | // Define the dynamic data (fields) 36 | ssz.DefineSliceOfUint64sContent(codec, &obj.AttestationIndices, 2048) // Field (0) - AttestationIndices - ? bytes 37 | } 38 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_bits_struct_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *BitsStructMonolith) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | if sizer.Fork() >= ssz.ForkUnknown { 11 | size += 4 + 1 12 | } 13 | size += 1 + 4 + 1 14 | if fixed { 15 | return size 16 | } 17 | if sizer.Fork() >= ssz.ForkUnknown { 18 | size += ssz.SizeSliceOfBits(sizer, obj.A) 19 | } 20 | size += ssz.SizeSliceOfBits(sizer, obj.D) 21 | 22 | return size 23 | } 24 | 25 | // DefineSSZ defines how an object is encoded/decoded. 26 | func (obj *BitsStructMonolith) DefineSSZ(codec *ssz.Codec) { 27 | // Define the static data (fields and dynamic offsets) 28 | ssz.DefineSliceOfBitsOffsetOnFork(codec, &obj.A, 5, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Offset (0) - A - 4 bytes 29 | ssz.DefineArrayOfBitsPointerOnFork(codec, &obj.B, 2, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (1) - B - 1 bytes 30 | ssz.DefineArrayOfBits(codec, &obj.C, 1) // Field (2) - C - 1 bytes 31 | ssz.DefineSliceOfBitsOffset(codec, &obj.D, 6) // Offset (3) - D - 4 bytes 32 | ssz.DefineArrayOfBits(codec, &obj.E, 8) // Field (4) - E - 1 bytes 33 | 34 | // Define the dynamic data (fields) 35 | ssz.DefineSliceOfBitsContentOnFork(codec, &obj.A, 5, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (0) - A - ? bytes 36 | ssz.DefineSliceOfBitsContent(codec, &obj.D, 6) // Field (3) - D - ? bytes 37 | } 38 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_data_variation_1_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestationDataVariation1 = ssz.PrecomputeStaticSizeCache((*AttestationDataVariation1)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *AttestationDataVariation1) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestationDataVariation1) { 13 | return staticSizeCacheAttestationDataVariation1[fork] 14 | } 15 | if sizer.Fork() >= ssz.ForkFuture { 16 | size += 8 17 | } 18 | size += 8 + 8 + 32 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) 19 | return size 20 | } 21 | 22 | // DefineSSZ defines how an object is encoded/decoded. 23 | func (obj *AttestationDataVariation1) DefineSSZ(codec *ssz.Codec) { 24 | ssz.DefineUint64PointerOnFork(codec, &obj.Future, ssz.ForkFilter{Added: ssz.ForkFuture}) // Field (0) - Future - 8 bytes 25 | ssz.DefineUint64(codec, &obj.Slot) // Field (1) - Slot - 8 bytes 26 | ssz.DefineUint64(codec, &obj.Index) // Field (2) - Index - 8 bytes 27 | ssz.DefineStaticBytes(codec, &obj.BeaconBlockHash) // Field (3) - BeaconBlockHash - 32 bytes 28 | ssz.DefineStaticObject(codec, &obj.Source) // Field (4) - Source - ? bytes (Checkpoint) 29 | ssz.DefineStaticObject(codec, &obj.Target) // Field (5) - Target - ? bytes (Checkpoint) 30 | } 31 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_data_variation_3_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestationDataVariation3 = ssz.PrecomputeStaticSizeCache((*AttestationDataVariation3)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *AttestationDataVariation3) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestationDataVariation3) { 13 | return staticSizeCacheAttestationDataVariation3[fork] 14 | } 15 | size = 8 + 8 + 32 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) 16 | if sizer.Fork() >= ssz.ForkFuture { 17 | size += 8 18 | } 19 | return size 20 | } 21 | 22 | // DefineSSZ defines how an object is encoded/decoded. 23 | func (obj *AttestationDataVariation3) DefineSSZ(codec *ssz.Codec) { 24 | ssz.DefineUint64(codec, &obj.Slot) // Field (0) - Slot - 8 bytes 25 | ssz.DefineUint64(codec, &obj.Index) // Field (1) - Index - 8 bytes 26 | ssz.DefineStaticBytes(codec, &obj.BeaconBlockHash) // Field (2) - BeaconBlockHash - 32 bytes 27 | ssz.DefineStaticObject(codec, &obj.Source) // Field (3) - Source - ? bytes (Checkpoint) 28 | ssz.DefineStaticObject(codec, &obj.Target) // Field (4) - Target - ? bytes (Checkpoint) 29 | ssz.DefineUint64PointerOnFork(codec, &obj.Future, ssz.ForkFilter{Added: ssz.ForkFuture}) // Field (5) - Future - 8 bytes 30 | } 31 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_data_variation_2_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestationDataVariation2 = ssz.PrecomputeStaticSizeCache((*AttestationDataVariation2)(nil)) 9 | 10 | // SizeSSZ returns the total size of the static ssz object. 11 | func (obj *AttestationDataVariation2) SizeSSZ(sizer *ssz.Sizer) (size uint32) { 12 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestationDataVariation2) { 13 | return staticSizeCacheAttestationDataVariation2[fork] 14 | } 15 | size = 8 + 8 + 32 16 | if sizer.Fork() >= ssz.ForkFuture { 17 | size += 8 18 | } 19 | size += (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) 20 | return size 21 | } 22 | 23 | // DefineSSZ defines how an object is encoded/decoded. 24 | func (obj *AttestationDataVariation2) DefineSSZ(codec *ssz.Codec) { 25 | ssz.DefineUint64(codec, &obj.Slot) // Field (0) - Slot - 8 bytes 26 | ssz.DefineUint64(codec, &obj.Index) // Field (1) - Index - 8 bytes 27 | ssz.DefineStaticBytes(codec, &obj.BeaconBlockHash) // Field (2) - BeaconBlockHash - 32 bytes 28 | ssz.DefineUint64PointerOnFork(codec, &obj.Future, ssz.ForkFilter{Added: ssz.ForkFuture}) // Field (3) - Future - 8 bytes 29 | ssz.DefineStaticObject(codec, &obj.Source) // Field (4) - Source - ? bytes (Checkpoint) 30 | ssz.DefineStaticObject(codec, &obj.Target) // Field (5) - Target - ? bytes (Checkpoint) 31 | } 32 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_pending_attestation_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCachePendingAttestation = ssz.PrecomputeStaticSizeCache((*PendingAttestation)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *PendingAttestation) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCachePendingAttestation) { 15 | size = staticSizeCachePendingAttestation[fork] 16 | } else { 17 | size = 4 + (*AttestationData)(nil).SizeSSZ(sizer) + 8 + 8 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfBits(sizer, obj.AggregationBits) 24 | 25 | return size 26 | } 27 | 28 | // DefineSSZ defines how an object is encoded/decoded. 29 | func (obj *PendingAttestation) DefineSSZ(codec *ssz.Codec) { 30 | // Define the static data (fields and dynamic offsets) 31 | ssz.DefineSliceOfBitsOffset(codec, &obj.AggregationBits, 2048) // Offset (0) - AggregationBits - 4 bytes 32 | ssz.DefineStaticObject(codec, &obj.Data) // Field (1) - Data - ? bytes (AttestationData) 33 | ssz.DefineUint64(codec, &obj.InclusionDelay) // Field (2) - InclusionDelay - 8 bytes 34 | ssz.DefineUint64(codec, &obj.ProposerIndex) // Field (3) - ProposerIndex - 8 bytes 35 | 36 | // Define the dynamic data (fields) 37 | ssz.DefineSliceOfBitsContent(codec, &obj.AggregationBits, 2048) // Field (0) - AggregationBits - ? bytes 38 | } 39 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 2 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 3 | github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= 4 | github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= 5 | github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= 6 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 7 | github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= 8 | github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= 9 | github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8kiphgdOBTcbTvo8MwkvpKjO0SlAgjv4xIK5FGJ94= 10 | github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15/go.mod h1:8svFBIKKu31YriBG/pNizo9N0Jr9i5PQ+dFkxWg3x5k= 11 | github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= 12 | github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= 13 | golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= 14 | golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 15 | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= 16 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 17 | golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= 18 | golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= 19 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 20 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 21 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 22 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 23 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_variation_1_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestationVariation1 = ssz.PrecomputeStaticSizeCache((*AttestationVariation1)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *AttestationVariation1) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestationVariation1) { 15 | size = staticSizeCacheAttestationVariation1[fork] 16 | } else { 17 | if sizer.Fork() >= ssz.ForkFuture { 18 | size += 8 19 | } 20 | size += 4 + (*AttestationData)(nil).SizeSSZ(sizer) + 96 21 | } 22 | // Either return the static size or accumulate the dynamic too 23 | if fixed { 24 | return size 25 | } 26 | size += ssz.SizeSliceOfBits(sizer, obj.AggregationBits) 27 | 28 | return size 29 | } 30 | 31 | // DefineSSZ defines how an object is encoded/decoded. 32 | func (obj *AttestationVariation1) DefineSSZ(codec *ssz.Codec) { 33 | // Define the static data (fields and dynamic offsets) 34 | ssz.DefineUint64PointerOnFork(codec, &obj.Future, ssz.ForkFilter{Added: ssz.ForkFuture}) // Field (0) - Future - 8 bytes 35 | ssz.DefineSliceOfBitsOffset(codec, &obj.AggregationBits, 2048) // Offset (1) - AggregationBits - 4 bytes 36 | ssz.DefineStaticObject(codec, &obj.Data) // Field (2) - Data - ? bytes (AttestationData) 37 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (3) - Signature - 96 bytes 38 | 39 | // Define the dynamic data (fields) 40 | ssz.DefineSliceOfBitsContent(codec, &obj.AggregationBits, 2048) // Field (1) - AggregationBits - ? bytes 41 | } 42 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_variation_3_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestationVariation3 = ssz.PrecomputeStaticSizeCache((*AttestationVariation3)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *AttestationVariation3) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestationVariation3) { 15 | size = staticSizeCacheAttestationVariation3[fork] 16 | } else { 17 | size = 4 + (*AttestationData)(nil).SizeSSZ(sizer) + 96 18 | if sizer.Fork() >= ssz.ForkFuture { 19 | size += 8 20 | } 21 | } 22 | // Either return the static size or accumulate the dynamic too 23 | if fixed { 24 | return size 25 | } 26 | size += ssz.SizeSliceOfBits(sizer, obj.AggregationBits) 27 | 28 | return size 29 | } 30 | 31 | // DefineSSZ defines how an object is encoded/decoded. 32 | func (obj *AttestationVariation3) DefineSSZ(codec *ssz.Codec) { 33 | // Define the static data (fields and dynamic offsets) 34 | ssz.DefineSliceOfBitsOffset(codec, &obj.AggregationBits, 2048) // Offset (0) - AggregationBits - 4 bytes 35 | ssz.DefineStaticObject(codec, &obj.Data) // Field (1) - Data - ? bytes (AttestationData) 36 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (2) - Signature - 96 bytes 37 | ssz.DefineUint64PointerOnFork(codec, &obj.Future, ssz.ForkFilter{Added: ssz.ForkFuture}) // Field (3) - Future - 8 bytes 38 | 39 | // Define the dynamic data (fields) 40 | ssz.DefineSliceOfBitsContent(codec, &obj.AggregationBits, 2048) // Field (0) - AggregationBits - ? bytes 41 | } 42 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_attestation_variation_2_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheAttestationVariation2 = ssz.PrecomputeStaticSizeCache((*AttestationVariation2)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *AttestationVariation2) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheAttestationVariation2) { 15 | size = staticSizeCacheAttestationVariation2[fork] 16 | } else { 17 | size = 4 + (*AttestationData)(nil).SizeSSZ(sizer) 18 | if sizer.Fork() >= ssz.ForkFuture { 19 | size += 8 20 | } 21 | size += 96 22 | } 23 | // Either return the static size or accumulate the dynamic too 24 | if fixed { 25 | return size 26 | } 27 | size += ssz.SizeSliceOfBits(sizer, obj.AggregationBits) 28 | 29 | return size 30 | } 31 | 32 | // DefineSSZ defines how an object is encoded/decoded. 33 | func (obj *AttestationVariation2) DefineSSZ(codec *ssz.Codec) { 34 | // Define the static data (fields and dynamic offsets) 35 | ssz.DefineSliceOfBitsOffset(codec, &obj.AggregationBits, 2048) // Offset (0) - AggregationBits - 4 bytes 36 | ssz.DefineStaticObject(codec, &obj.Data) // Field (1) - Data - ? bytes (AttestationData) 37 | ssz.DefineUint64PointerOnFork(codec, &obj.Future, ssz.ForkFilter{Added: ssz.ForkFuture}) // Field (2) - Future - 8 bytes 38 | ssz.DefineStaticBytes(codec, &obj.Signature) // Field (3) - Signature - 96 bytes 39 | 40 | // Define the dynamic data (fields) 41 | ssz.DefineSliceOfBitsContent(codec, &obj.AggregationBits, 2048) // Field (0) - AggregationBits - ? bytes 42 | } 43 | -------------------------------------------------------------------------------- /example_asymmetric_test.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz_test 6 | 7 | import ( 8 | "fmt" 9 | 10 | "github.com/karalabe/ssz" 11 | ) 12 | 13 | type WithdrawalAsym struct { 14 | Index uint64 `ssz-size:"8"` 15 | Validator uint64 `ssz-size:"8"` 16 | Address Address `ssz-size:"20"` 17 | Amount uint64 `ssz-size:"8"` 18 | } 19 | 20 | func (w *WithdrawalAsym) SizeSSZ(siz *ssz.Sizer) uint32 { return 44 } 21 | 22 | func (w *WithdrawalAsym) DefineSSZ(codec *ssz.Codec) { 23 | codec.DefineEncoder(func(enc *ssz.Encoder) { 24 | ssz.EncodeUint64(enc, w.Index) // Field (0) - Index - 8 bytes 25 | ssz.EncodeUint64(enc, w.Validator) // Field (1) - ValidatorIndex - 8 bytes 26 | ssz.EncodeStaticBytes(enc, &w.Address) // Field (2) - Address - 20 bytes 27 | ssz.EncodeUint64(enc, w.Amount) // Field (3) - Amount - 8 bytes 28 | }) 29 | codec.DefineDecoder(func(dec *ssz.Decoder) { 30 | ssz.DecodeUint64(dec, &w.Index) // Field (0) - Index - 8 bytes 31 | ssz.DecodeUint64(dec, &w.Validator) // Field (1) - ValidatorIndex - 8 bytes 32 | ssz.DecodeStaticBytes(dec, &w.Address) // Field (2) - Address - 20 bytes 33 | ssz.DecodeUint64(dec, &w.Amount) // Field (3) - Amount - 8 bytes 34 | }) 35 | codec.DefineHasher(func(has *ssz.Hasher) { 36 | ssz.HashUint64(has, w.Index) // Field (0) - Index - 8 bytes 37 | ssz.HashUint64(has, w.Validator) // Field (1) - ValidatorIndex - 8 bytes 38 | ssz.HashStaticBytes(has, &w.Address) // Field (2) - Address - 20 bytes 39 | ssz.HashUint64(has, w.Amount) // Field (3) - Amount - 8 bytes 40 | }) 41 | } 42 | 43 | func ExampleEncodeAsymmetricObject() { 44 | blob := make([]byte, ssz.Size((*WithdrawalAsym)(nil))) 45 | if err := ssz.EncodeToBytes(blob, new(WithdrawalAsym)); err != nil { 46 | panic(err) 47 | } 48 | hash := ssz.HashSequential(new(WithdrawalAsym)) 49 | 50 | fmt.Printf("ssz: %#x\nhash: %#x\n", blob, hash) 51 | // Output: 52 | // ssz: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 53 | // hash: 0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71 54 | } 55 | -------------------------------------------------------------------------------- /cmd/sszgen/tags.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | const ( 14 | sszTagIdent = "ssz" 15 | sszSizeTagIdent = "ssz-size" 16 | sszMaxTagIdent = "ssz-max" 17 | sszForkTagIdent = "ssz-fork" 18 | ) 19 | 20 | // sizeTag describes the restriction for types. 21 | type sizeTag struct { 22 | bits bool // whether the sizes are bits instead of bytes 23 | size []int // 0 means the size for that dimension is undefined 24 | limit []int // 0 means the limit for that dimension is undefined 25 | } 26 | 27 | func parseTags(input string) (bool, *sizeTag, string, error) { 28 | if len(input) == 0 { 29 | return false, nil, "", nil 30 | } 31 | var ( 32 | ignore bool 33 | tags sizeTag 34 | fork string 35 | 36 | setTag = func(v int, ident string) { 37 | if ident == sszMaxTagIdent { 38 | tags.limit = append(tags.limit, v) 39 | } else { 40 | tags.size = append(tags.size, v) 41 | } 42 | } 43 | ) 44 | for _, tag := range strings.Fields(input) { 45 | parts := strings.Split(tag, ":") 46 | if len(parts) != 2 { 47 | return false, nil, "", fmt.Errorf("invalid tag %s", tag) 48 | } 49 | ident, remain := parts[0], strings.Trim(parts[1], "\"") 50 | switch ident { 51 | case sszTagIdent: 52 | if remain == "-" { 53 | ignore = true 54 | } else if remain == "bits" { 55 | tags.bits = true 56 | } 57 | case sszMaxTagIdent, sszSizeTagIdent: 58 | parts := strings.Split(remain, ",") 59 | for _, p := range parts { 60 | if p == "?" { 61 | setTag(0, ident) 62 | continue 63 | } 64 | num, err := strconv.ParseInt(p, 10, 64) 65 | if err != nil { 66 | return false, nil, "", err 67 | } 68 | setTag(int(num), ident) 69 | } 70 | case sszForkTagIdent: 71 | var negate bool 72 | if remain[0] == '!' { 73 | negate = true 74 | remain = remain[1:] 75 | } 76 | if enum, ok := forkMapping[remain]; !ok { 77 | return ignore, nil, "", fmt.Errorf("invalid fork tag %s", tag) 78 | } else { 79 | fork = enum 80 | if negate { 81 | fork = "!" + fork 82 | } 83 | } 84 | } 85 | } 86 | if tags.size == nil && tags.limit == nil { 87 | return ignore, nil, fork, nil 88 | } 89 | return ignore, &tags, fork, nil 90 | } 91 | -------------------------------------------------------------------------------- /cmd/sszgen/parser.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "go/types" 10 | ) 11 | 12 | // parseContext contains some helpers for interpreting generated types. 13 | type parseContext struct { 14 | staticObjectIface *types.Interface 15 | dynamicObjectIface *types.Interface 16 | } 17 | 18 | // newParseContext loads a few ssz library interfaces for the generator. 19 | func newParseContext(library *types.Package) *parseContext { 20 | var ( 21 | static = library.Scope().Lookup("StaticObject").Type().Underlying() 22 | dynamic = library.Scope().Lookup("DynamicObject").Type().Underlying() 23 | ) 24 | return &parseContext{ 25 | staticObjectIface: static.(*types.Interface), 26 | dynamicObjectIface: dynamic.(*types.Interface), 27 | } 28 | } 29 | 30 | // parsePackage retrieves the specified named-types from the target package and 31 | // creates ssz containers out of them. 32 | func (p *parseContext) parsePackage(target *types.Package, names []string) ([]*sszContainer, error) { 33 | // If no types were requested, parse all of them 34 | if len(names) == 0 { 35 | names = target.Scope().Names() 36 | } 37 | var containers []*sszContainer 38 | for _, name := range names { 39 | named, str, err := p.lookupStruct(target.Scope(), name) 40 | if err != nil { 41 | return nil, err 42 | } 43 | typ, err := p.makeContainer(named, str) 44 | if err != nil { 45 | return nil, err 46 | } 47 | containers = append(containers, typ) 48 | } 49 | return containers, nil 50 | } 51 | 52 | // lookupStruct is a small helper to check that a type name is indeed a struct 53 | // that we can convert into an ssz type. 54 | func (p *parseContext) lookupStruct(scope *types.Scope, name string) (*types.Named, *types.Struct, error) { 55 | obj := scope.Lookup(name) 56 | if obj == nil { 57 | return nil, nil, fmt.Errorf("identifier not found: %s", name) 58 | } 59 | typ, ok := obj.(*types.TypeName) 60 | if !ok { 61 | return nil, nil, fmt.Errorf("identifier not a type: %s", name) 62 | } 63 | dec, ok := typ.Type().(*types.Named) 64 | if !ok { 65 | return nil, nil, fmt.Errorf("identifier not a named type: %s", name) 66 | } 67 | str, ok := dec.Underlying().(*types.Struct) 68 | if !ok { 69 | return nil, nil, fmt.Errorf("identifier not a named struct: %s", name) 70 | } 71 | return dec, str, nil 72 | } 73 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_header_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadHeader) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 32 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 15 | 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *ExecutionPayloadHeader) DefineSSZ(codec *ssz.Codec) { 21 | // Define the static data (fields and dynamic offsets) 22 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 23 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 24 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 25 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 26 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 27 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 28 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 29 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 30 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 31 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 32 | ssz.DefineDynamicBytesOffset(codec, &obj.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 33 | ssz.DefineStaticBytes(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 34 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 35 | ssz.DefineStaticBytes(codec, &obj.TransactionsRoot) // Field (13) - TransactionsRoot - 32 bytes 36 | 37 | // Define the dynamic data (fields) 38 | ssz.DefineDynamicBytesContent(codec, &obj.ExtraData, 32) // Field (10) - ExtraData - ? bytes 39 | } 40 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_header_capella_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadHeaderCapella) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 32 + 32 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 15 | 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *ExecutionPayloadHeaderCapella) DefineSSZ(codec *ssz.Codec) { 21 | // Define the static data (fields and dynamic offsets) 22 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 23 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 24 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 25 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 26 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 27 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 28 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 29 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 30 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 31 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 32 | ssz.DefineDynamicBytesOffset(codec, &obj.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 33 | ssz.DefineStaticBytes(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 34 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 35 | ssz.DefineStaticBytes(codec, &obj.TransactionsRoot) // Field (13) - TransactionsRoot - 32 bytes 36 | ssz.DefineStaticBytes(codec, &obj.WithdrawalRoot) // Field (14) - WithdrawalRoot - 32 bytes 37 | 38 | // Define the dynamic data (fields) 39 | ssz.DefineDynamicBytesContent(codec, &obj.ExtraData, 32) // Field (10) - ExtraData - ? bytes 40 | } 41 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_header_deneb_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadHeaderDeneb) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 32 + 32 + 8 + 8 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 15 | 16 | return size 17 | } 18 | 19 | // DefineSSZ defines how an object is encoded/decoded. 20 | func (obj *ExecutionPayloadHeaderDeneb) DefineSSZ(codec *ssz.Codec) { 21 | // Define the static data (fields and dynamic offsets) 22 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 23 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 24 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 25 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 26 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 27 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 28 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 29 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 30 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 31 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 32 | ssz.DefineDynamicBytesOffset(codec, &obj.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 33 | ssz.DefineStaticBytes(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 34 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 35 | ssz.DefineStaticBytes(codec, &obj.TransactionsRoot) // Field (13) - TransactionsRoot - 32 bytes 36 | ssz.DefineStaticBytes(codec, &obj.WithdrawalRoot) // Field (14) - WithdrawalRoot - 32 bytes 37 | ssz.DefineUint64(codec, &obj.BlobGasUsed) // Field (15) - BlobGasUsed - 8 bytes 38 | ssz.DefineUint64(codec, &obj.ExcessBlobGas) // Field (16) - ExcessBlobGas - 8 bytes 39 | 40 | // Define the dynamic data (fields) 41 | ssz.DefineDynamicBytesContent(codec, &obj.ExtraData, 32) // Field (10) - ExtraData - ? bytes 42 | } 43 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayload) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 4 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 15 | size += ssz.SizeSliceOfDynamicBytes(sizer, obj.Transactions) 16 | 17 | return size 18 | } 19 | 20 | // DefineSSZ defines how an object is encoded/decoded. 21 | func (obj *ExecutionPayload) DefineSSZ(codec *ssz.Codec) { 22 | // Define the static data (fields and dynamic offsets) 23 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 24 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 25 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 26 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 27 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 28 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 29 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 30 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 31 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 32 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 33 | ssz.DefineDynamicBytesOffset(codec, &obj.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 34 | ssz.DefineUint256(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 35 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 36 | ssz.DefineSliceOfDynamicBytesOffset(codec, &obj.Transactions, 1048576, 1073741824) // Offset (13) - Transactions - 4 bytes 37 | 38 | // Define the dynamic data (fields) 39 | ssz.DefineDynamicBytesContent(codec, &obj.ExtraData, 32) // Field (10) - ExtraData - ? bytes 40 | ssz.DefineSliceOfDynamicBytesContent(codec, &obj.Transactions, 1048576, 1073741824) // Field (13) - Transactions - ? bytes 41 | } 42 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_variation_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadVariation) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 4 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 15 | size += ssz.SizeSliceOfDynamicBytes(sizer, obj.Transactions) 16 | 17 | return size 18 | } 19 | 20 | // DefineSSZ defines how an object is encoded/decoded. 21 | func (obj *ExecutionPayloadVariation) DefineSSZ(codec *ssz.Codec) { 22 | // Define the static data (fields and dynamic offsets) 23 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 24 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 25 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 26 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 27 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 28 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 29 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 30 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 31 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 32 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 33 | ssz.DefineDynamicBytesOffset(codec, &obj.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 34 | ssz.DefineUint256BigInt(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 35 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 36 | ssz.DefineSliceOfDynamicBytesOffset(codec, &obj.Transactions, 1048576, 1073741824) // Offset (13) - Transactions - 4 bytes 37 | 38 | // Define the dynamic data (fields) 39 | ssz.DefineDynamicBytesContent(codec, &obj.ExtraData, 32) // Field (10) - ExtraData - ? bytes 40 | ssz.DefineSliceOfDynamicBytesContent(codec, &obj.Transactions, 1048576, 1073741824) // Field (13) - Transactions - ? bytes 41 | } 42 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_body_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconBlockBody = ssz.PrecomputeStaticSizeCache((*BeaconBlockBody)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconBlockBody) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconBlockBody) { 15 | size = staticSizeCacheBeaconBlockBody[fork] 16 | } else { 17 | size = 96 + (*Eth1Data)(nil).SizeSSZ(sizer) + 32 + 4 + 4 + 4 + 4 + 4 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.ProposerSlashings) 24 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.AttesterSlashings) 25 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.Attestations) 26 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Deposits) 27 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.VoluntaryExits) 28 | 29 | return size 30 | } 31 | 32 | // DefineSSZ defines how an object is encoded/decoded. 33 | func (obj *BeaconBlockBody) DefineSSZ(codec *ssz.Codec) { 34 | // Define the static data (fields and dynamic offsets) 35 | ssz.DefineStaticBytes(codec, &obj.RandaoReveal) // Field (0) - RandaoReveal - 96 bytes 36 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field (1) - Eth1Data - ? bytes (Eth1Data) 37 | ssz.DefineStaticBytes(codec, &obj.Graffiti) // Field (2) - Graffiti - 32 bytes 38 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.ProposerSlashings, 16) // Offset (3) - ProposerSlashings - 4 bytes 39 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.AttesterSlashings, 2) // Offset (4) - AttesterSlashings - 4 bytes 40 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.Attestations, 128) // Offset (5) - Attestations - 4 bytes 41 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Deposits, 16) // Offset (6) - Deposits - 4 bytes 42 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.VoluntaryExits, 16) // Offset (7) - VoluntaryExits - 4 bytes 43 | 44 | // Define the dynamic data (fields) 45 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.ProposerSlashings, 16) // Field (3) - ProposerSlashings - ? bytes 46 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.AttesterSlashings, 2) // Field (4) - AttesterSlashings - ? bytes 47 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.Attestations, 128) // Field (5) - Attestations - ? bytes 48 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Deposits, 16) // Field (6) - Deposits - ? bytes 49 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.VoluntaryExits, 16) // Field (7) - VoluntaryExits - ? bytes 50 | } 51 | -------------------------------------------------------------------------------- /sizer.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz 6 | 7 | import ( 8 | "github.com/prysmaticlabs/go-bitfield" 9 | ) 10 | 11 | // Sizer is an SSZ static and dynamic size computer. 12 | type Sizer struct { 13 | codec *Codec // Self-referencing to have access to fork contexts 14 | } 15 | 16 | // Fork retrieves the current fork (if any) that the sizer is operating in. 17 | func (siz *Sizer) Fork() Fork { 18 | return siz.codec.fork 19 | } 20 | 21 | // SizeDynamicBytes returns the serialized size of the dynamic part of a dynamic 22 | // blob. 23 | func SizeDynamicBytes(siz *Sizer, blobs []byte) uint32 { 24 | return uint32(len(blobs)) 25 | } 26 | 27 | // SizeSliceOfBits returns the serialized size of the dynamic part of a slice of 28 | // bits. 29 | // 30 | // Note, a nil slice of bits is sized as an empty bit list. 31 | func SizeSliceOfBits(siz *Sizer, bits bitfield.Bitlist) uint32 { 32 | if bits != nil { 33 | return uint32(len(bits)) 34 | } 35 | return uint32(len(bitlistZero)) 36 | } 37 | 38 | // SizeSliceOfUint64s returns the serialized size of the dynamic part of a dynamic 39 | // list of uint64s. 40 | func SizeSliceOfUint64s[T ~uint64](siz *Sizer, ns []T) uint32 { 41 | return uint32(len(ns)) * 8 42 | } 43 | 44 | // SizeDynamicObject returns the serialized size of the dynamic part of a dynamic 45 | // object. 46 | func SizeDynamicObject[T newableDynamicObject[U], U any](siz *Sizer, obj T) uint32 { 47 | if obj == nil { 48 | // If the object is nil, pull up it's zero value. This will be very slow, 49 | // but it should not happen in production, only during tests mostly. 50 | obj = zeroValueDynamic[T, U]() 51 | } 52 | return obj.SizeSSZ(siz, false) 53 | } 54 | 55 | // SizeSliceOfStaticBytes returns the serialized size of the dynamic part of a dynamic 56 | // list of static blobs. 57 | func SizeSliceOfStaticBytes[T commonBytesLengths](siz *Sizer, blobs []T) uint32 { 58 | if len(blobs) == 0 { 59 | return 0 60 | } 61 | return uint32(len(blobs) * len(blobs[0])) 62 | } 63 | 64 | // SizeSliceOfDynamicBytes returns the serialized size of the dynamic part of a dynamic 65 | // list of dynamic blobs. 66 | func SizeSliceOfDynamicBytes(siz *Sizer, blobs [][]byte) uint32 { 67 | var size uint32 68 | for _, blob := range blobs { 69 | size += uint32(4 + len(blob)) // 4-byte offset + dynamic data later 70 | } 71 | return size 72 | } 73 | 74 | // SizeSliceOfStaticObjects returns the serialized size of the dynamic part of a dynamic 75 | // list of static objects. 76 | func SizeSliceOfStaticObjects[T StaticObject](siz *Sizer, objects []T) uint32 { 77 | if len(objects) == 0 { 78 | return 0 79 | } 80 | return uint32(len(objects)) * objects[0].SizeSSZ(siz) 81 | } 82 | 83 | // SizeSliceOfDynamicObjects returns the serialized size of the dynamic part of 84 | // a dynamic list of dynamic objects. 85 | func SizeSliceOfDynamicObjects[T DynamicObject](siz *Sizer, objects []T) uint32 { 86 | var size uint32 87 | for _, obj := range objects { 88 | size += 4 + obj.SizeSSZ(siz, false) // 4-byte offset + dynamic data later 89 | } 90 | return size 91 | } 92 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_capella_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadCapella) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 4 + 4 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 15 | size += ssz.SizeSliceOfDynamicBytes(sizer, obj.Transactions) 16 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Withdrawals) 17 | 18 | return size 19 | } 20 | 21 | // DefineSSZ defines how an object is encoded/decoded. 22 | func (obj *ExecutionPayloadCapella) DefineSSZ(codec *ssz.Codec) { 23 | // Define the static data (fields and dynamic offsets) 24 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 25 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 26 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 27 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 28 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 29 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 30 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 31 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 32 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 33 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 34 | ssz.DefineDynamicBytesOffset(codec, &obj.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 35 | ssz.DefineUint256(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 36 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 37 | ssz.DefineSliceOfDynamicBytesOffset(codec, &obj.Transactions, 1048576, 1073741824) // Offset (13) - Transactions - 4 bytes 38 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Withdrawals, 16) // Offset (14) - Withdrawals - 4 bytes 39 | 40 | // Define the dynamic data (fields) 41 | ssz.DefineDynamicBytesContent(codec, &obj.ExtraData, 32) // Field (10) - ExtraData - ? bytes 42 | ssz.DefineSliceOfDynamicBytesContent(codec, &obj.Transactions, 1048576, 1073741824) // Field (13) - Transactions - ? bytes 43 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Withdrawals, 16) // Field (14) - Withdrawals - ? bytes 44 | } 45 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_body_altair_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconBlockBodyAltair = ssz.PrecomputeStaticSizeCache((*BeaconBlockBodyAltair)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconBlockBodyAltair) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconBlockBodyAltair) { 15 | size = staticSizeCacheBeaconBlockBodyAltair[fork] 16 | } else { 17 | size = 96 + (*Eth1Data)(nil).SizeSSZ(sizer) + 32 + 4 + 4 + 4 + 4 + 4 + (*SyncAggregate)(nil).SizeSSZ(sizer) 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.ProposerSlashings) 24 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.AttesterSlashings) 25 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.Attestations) 26 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Deposits) 27 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.VoluntaryExits) 28 | 29 | return size 30 | } 31 | 32 | // DefineSSZ defines how an object is encoded/decoded. 33 | func (obj *BeaconBlockBodyAltair) DefineSSZ(codec *ssz.Codec) { 34 | // Define the static data (fields and dynamic offsets) 35 | ssz.DefineStaticBytes(codec, &obj.RandaoReveal) // Field (0) - RandaoReveal - 96 bytes 36 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field (1) - Eth1Data - ? bytes (Eth1Data) 37 | ssz.DefineStaticBytes(codec, &obj.Graffiti) // Field (2) - Graffiti - 32 bytes 38 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.ProposerSlashings, 16) // Offset (3) - ProposerSlashings - 4 bytes 39 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.AttesterSlashings, 2) // Offset (4) - AttesterSlashings - 4 bytes 40 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.Attestations, 128) // Offset (5) - Attestations - 4 bytes 41 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Deposits, 16) // Offset (6) - Deposits - 4 bytes 42 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.VoluntaryExits, 16) // Offset (7) - VoluntaryExits - 4 bytes 43 | ssz.DefineStaticObject(codec, &obj.SyncAggregate) // Field (8) - SyncAggregate - ? bytes (SyncAggregate) 44 | 45 | // Define the dynamic data (fields) 46 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.ProposerSlashings, 16) // Field (3) - ProposerSlashings - ? bytes 47 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.AttesterSlashings, 2) // Field (4) - AttesterSlashings - ? bytes 48 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.Attestations, 128) // Field (5) - Attestations - ? bytes 49 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Deposits, 16) // Field (6) - Deposits - ? bytes 50 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.VoluntaryExits, 16) // Field (7) - VoluntaryExits - ? bytes 51 | } 52 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz 6 | 7 | import "errors" 8 | 9 | // ErrBufferTooSmall is returned from encoding if the provided output byte buffer 10 | // is too small to hold the encoding of the object. 11 | var ErrBufferTooSmall = errors.New("ssz: output buffer too small") 12 | 13 | // ErrFirstOffsetMismatch is returned when parsing dynamic types and the first 14 | // offset (which is supposed to signal the start of the dynamic area) does not 15 | // match with the computed fixed area size. 16 | var ErrFirstOffsetMismatch = errors.New("ssz: first offset mismatch") 17 | 18 | // ErrBadOffsetProgression is returned when an offset is parsed, and is smaller 19 | // than a previously seen offset (meaning negative dynamic data size). 20 | var ErrBadOffsetProgression = errors.New("ssz: offset smaller than previous") 21 | 22 | // ErrOffsetBeyondCapacity is returned when an offset is parsed, and is larger 23 | // than the total capacity allowed by the decoder (i.e. message size) 24 | var ErrOffsetBeyondCapacity = errors.New("ssz: offset beyond capacity") 25 | 26 | // ErrMaxLengthExceeded is returned when the size calculated for a dynamic type 27 | // is larger than permitted. 28 | var ErrMaxLengthExceeded = errors.New("ssz: maximum item size exceeded") 29 | 30 | // ErrMaxItemsExceeded is returned when the number of items in a dynamic list 31 | // type is later than permitted. 32 | var ErrMaxItemsExceeded = errors.New("ssz: maximum item count exceeded") 33 | 34 | // ErrShortCounterOffset is returned if a counter offset it attempted to be read 35 | // but there are fewer bytes available on the stream. 36 | var ErrShortCounterOffset = errors.New("ssz: insufficient data for 4-byte counter offset") 37 | 38 | // ErrZeroCounterOffset is returned when a list of offsets are consumed and the 39 | // first offset is zero, which means the list should not have existed. 40 | var ErrZeroCounterOffset = errors.New("ssz: counter offset zero") 41 | 42 | // ErrBadCounterOffset is returned when a list of offsets are consumed and the 43 | // first offset is not a multiple of 4-bytes. 44 | var ErrBadCounterOffset = errors.New("ssz: counter offset not multiple of 4-bytes") 45 | 46 | // ErrDynamicStaticsIndivisible is returned when a list of static objects is to 47 | // be decoded, but the list's total length is not divisible by the item size. 48 | var ErrDynamicStaticsIndivisible = errors.New("ssz: list of fixed objects not divisible") 49 | 50 | // ErrObjectSlotSizeMismatch is returned from decoding if an object's slot in the 51 | // ssz stream contains more data than the object cares to consume. 52 | var ErrObjectSlotSizeMismatch = errors.New("ssz: object didn't consume all designated data") 53 | 54 | // ErrInvalidBoolean is returned from decoding if a boolean slot contains some 55 | // other byte than 0x00 or 0x01. 56 | var ErrInvalidBoolean = errors.New("ssz: invalid boolean") 57 | 58 | // ErrJunkInBitvector is returned from decoding if the high (unused) bits of a 59 | // bitvector contains junk, instead of being all 0. 60 | var ErrJunkInBitvector = errors.New("ssz: junk in bitvector unused bits") 61 | 62 | // ErrJunkInBitlist is returned from decoding if the high (unused) bits of a 63 | // bitlist contains junk, instead of being all 0. 64 | var ErrJunkInBitlist = errors.New("ssz: junk in bitlist unused bits") 65 | -------------------------------------------------------------------------------- /tests/zeroval_test.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package tests 6 | 7 | import ( 8 | "bytes" 9 | "reflect" 10 | "testing" 11 | 12 | "github.com/karalabe/ssz" 13 | ) 14 | 15 | // testZeroValue does a bunch of encoding/decoding/hashing variations on the zero 16 | // value of input types to check that the SSZ implementation can correctly handle 17 | // the different uninitialized fields. 18 | func testZeroValue[T newableObject[U], U any](t *testing.T, fork ssz.Fork) { 19 | // Verify that streaming/buffering encoding of a zero value results in the 20 | // same binary (maybe incorrect, we just want to see that they're the same). 21 | str1 := new(bytes.Buffer) 22 | if err := ssz.EncodeToStreamOnFork(str1, T(new(U)), fork); err != nil { 23 | t.Fatalf("failed to stream-encode zero-value object: %v", err) 24 | } 25 | bin1 := make([]byte, ssz.SizeOnFork(T(new(U)), fork)) 26 | if err := ssz.EncodeToBytesOnFork(bin1, T(new(U)), fork); err != nil { 27 | t.Fatalf("failed to buffer-encode zero-value object: %v", err) 28 | } 29 | if !bytes.Equal(str1.Bytes(), bin1) { 30 | t.Fatalf("zero-value encoding mismatch: stream %x, buffer %x", str1, bin1) 31 | } 32 | // Decode the previous encoding in both streaming/buffering mode and check 33 | // that the produced objects are the same. 34 | obj1 := T(new(U)) 35 | if err := ssz.DecodeFromStreamOnFork(bytes.NewReader(bin1), T(new(U)), uint32(len(bin1)), fork); err != nil { 36 | t.Fatalf("failed to stream-decode zero-value object: %v", err) 37 | } 38 | obj2 := T(new(U)) 39 | if err := ssz.DecodeFromBytesOnFork(bin1, T(new(U)), fork); err != nil { 40 | t.Fatalf("failed to buffer-decode zero-value object: %v", err) 41 | } 42 | if !reflect.DeepEqual(obj1, obj2) { 43 | t.Fatalf("zero-value decoding mismatch: stream %+v, buffer %+v", obj1, obj2) 44 | } 45 | // We can't compare the decoded zero-value to the true zero-values as pointer 46 | // nil-ness might be different. To verify that the decoding was successful, do 47 | // yet another round of encodings and check that to the original ones. 48 | str2 := new(bytes.Buffer) 49 | if err := ssz.EncodeToStreamOnFork(str2, obj1, fork); err != nil { 50 | t.Fatalf("failed to stream-encode decoded object: %v", err) 51 | } 52 | bin2 := make([]byte, ssz.SizeOnFork(obj1, fork)) 53 | if err := ssz.EncodeToBytesOnFork(bin2, obj1, fork); err != nil { 54 | t.Fatalf("failed to buffer-encode decoded object: %v", err) 55 | } 56 | if !bytes.Equal(str2.Bytes(), bin2) { 57 | t.Fatalf("re-encoding mismatch: stream %x, buffer %x", str2, bin2) 58 | } 59 | if !bytes.Equal(bin1, bin2) { 60 | t.Fatalf("re-encoding mismatch: zero-value %x, decoded %x", bin1, bin2) 61 | } 62 | // Encoding/decoding seems to work, hash the zero-value and re-encoded value 63 | // in both sequential/concurrent more and verify the results. 64 | hashes := map[string][32]byte{ 65 | "zero-value-sequential": ssz.HashSequentialOnFork(T(new(U)), fork), 66 | "zero-value-concurrent": ssz.HashConcurrentOnFork(T(new(U)), fork), 67 | "decoded-sequential": ssz.HashSequentialOnFork(obj1, fork), 68 | "decoded-concurrent": ssz.HashSequentialOnFork(obj1, fork), 69 | } 70 | for key1, hash1 := range hashes { 71 | for key2, hash2 := range hashes { 72 | if hash1 != hash2 { 73 | t.Errorf("hash mismatch: %s %x, %s %x", key1, hash1, key2, hash2) 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /cmd/sszgen/main.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "flag" 10 | "fmt" 11 | "go/format" 12 | "go/types" 13 | "log" 14 | "os" 15 | "strings" 16 | 17 | "golang.org/x/tools/go/packages" 18 | ) 19 | 20 | func main() { 21 | var ( 22 | pkgdir = flag.String("dir", ".", "input package") 23 | output = flag.String("out", "-", "output file (default is stdout)") 24 | typename = flag.String("type", "", "type to generate methods for") 25 | ) 26 | flag.Parse() 27 | 28 | cfg := Config{Dir: *pkgdir} 29 | if len(*typename) > 0 { 30 | cfg.Types = strings.Split(*typename, ",") 31 | } 32 | code, err := cfg.process() 33 | if err != nil { 34 | fatal(err) 35 | } 36 | if *output == "-" { 37 | os.Stdout.Write(code) 38 | } else if err := os.WriteFile(*output, code, 0600); err != nil { 39 | fatal(err) 40 | } 41 | } 42 | 43 | func fatal(args ...interface{}) { 44 | fmt.Fprintln(os.Stderr, args...) 45 | os.Exit(1) 46 | } 47 | 48 | type Config struct { 49 | Dir string // input package directory 50 | Types []string 51 | } 52 | 53 | // process generates the Go code. 54 | func (cfg *Config) process() ([]byte, error) { 55 | // Display a single log for mass generates 56 | log.Printf("Generating SSZ bindings for: %v", cfg.Types) 57 | 58 | // Load the ssz library package and the target package to generate into 59 | pcfg := &packages.Config{ 60 | Mode: packages.NeedName | packages.NeedTypes | packages.NeedImports | packages.NeedDeps, 61 | Dir: cfg.Dir, 62 | } 63 | ps, err := packages.Load(pcfg, sszPkgPath, ".") 64 | if err != nil { 65 | return nil, err 66 | } 67 | if len(ps) == 0 { 68 | return nil, fmt.Errorf("no Go package found in %s", cfg.Dir) 69 | } 70 | if len(ps) != 2 { 71 | return nil, fmt.Errorf("at most one package can be processed at the same time") 72 | } 73 | packages.PrintErrors(ps) 74 | 75 | // Pick out the library package for interfaces and the target package for types 76 | var ( 77 | library *types.Package 78 | target *types.Package 79 | ) 80 | for _, p := range ps { 81 | if len(p.Errors) > 0 { 82 | return nil, fmt.Errorf("package %s has errors", p.PkgPath) 83 | } 84 | if p.PkgPath == sszPkgPath { 85 | library = p.Types 86 | } else { 87 | target = p.Types 88 | } 89 | } 90 | // Parse the package in the context of the ssz library 91 | parser := newParseContext(library) 92 | 93 | types, err := parser.parsePackage(target, cfg.Types) 94 | if err != nil { 95 | return nil, err 96 | } 97 | var ( 98 | ctx = newGenContext(target) 99 | chunks [][]byte 100 | ) 101 | for _, typ := range types { 102 | ret, err := generate(ctx, typ) 103 | if err != nil { 104 | return nil, err 105 | } 106 | chunks = append(chunks, ret) 107 | } 108 | code := bytes.Join(chunks, []byte("\n\n")) 109 | 110 | // Add package and imports definition and format code 111 | code = append(ctx.header(), code...) 112 | code, err = format.Source(code) 113 | if err != nil { 114 | return nil, err 115 | } 116 | // Add build comments. 117 | // This is done here to avoid processing these lines with gofmt. 118 | var header bytes.Buffer 119 | fmt.Fprint(&header, "// Code generated by github.com/karalabe/ssz. DO NOT EDIT.\n\n") 120 | return append(header.Bytes(), code...), nil 121 | } 122 | -------------------------------------------------------------------------------- /generics.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz 6 | 7 | // newableStaticObject is a generic type whose purpose is to enforce that the 8 | // ssz.StaticObject is specifically implemented on a struct pointer. That is 9 | // needed to allow to instantiate new structs via `new` when parsing. 10 | type newableStaticObject[U any] interface { 11 | StaticObject 12 | *U 13 | } 14 | 15 | // newableDynamicObject is a generic type whose purpose is to enforce that the 16 | // ssz.DynamicObject is specifically implemented on a struct pointer. That is 17 | // needed to allow to instantiate new structs via `new` when parsing. 18 | type newableDynamicObject[U any] interface { 19 | DynamicObject 20 | *U 21 | } 22 | 23 | // commonBytesLengths is a generic type whose purpose is to permit that fixed- 24 | // sized binary blobs can be passed to different methods. Although a slice of 25 | // the array would work for simple cases, there are scenarios when a new array 26 | // needs to be instantiated (e.g. optional field), and in that case we cannot 27 | // operate on slices anymore as there's nothing yet to slice. 28 | // 29 | // You can add any size to this list really, it's just a limitation of the Go 30 | // generics compiler that it cannot represent arrays of arbitrary sizes with 31 | // one shorthand notation. 32 | type commonBytesLengths interface { 33 | // fork | nonce | address | verkle-stem | hash | pubkey | committee | signature | bloom 34 | ~[4]byte | ~[8]byte | ~[20]byte | ~[31]byte | ~[32]byte | ~[48]byte | ~[64]byte | ~[96]byte | ~[256]byte 35 | } 36 | 37 | // commonUint64sLengths is a generic type whose purpose is to permit that fixed- 38 | // sized uint64 arrays can be passed to different methods. Although a slice of 39 | // the array would work for simple cases, there are scenarios when a new array 40 | // needs to be instantiated (e.g. optional field), and in that case we cannot 41 | // operate on slices anymore as there's nothing yet to slice. 42 | // 43 | // You can add any size to this list really, it's just a limitation of the Go 44 | // generics compiler that it cannot represent arrays of arbitrary sizes with 45 | // one shorthand notation. 46 | type commonUint64sLengths interface { 47 | // slashing 48 | ~[8192]uint64 49 | } 50 | 51 | // commonBitsLengths is a generic type whose purpose is to permit that fixed- 52 | // sized bit-vectors can be passed to different methods. Although a slice of 53 | // the array would work for simple cases, there are scenarios when a new array 54 | // needs to be instantiated (e.g. optional field), and in that case we cannot 55 | // operate on slices anymore as there's nothing yet to slice. 56 | // 57 | // You can add any size to this list really, it's just a limitation of the Go 58 | // generics compiler that it cannot represent arrays of arbitrary sizes with 59 | // one shorthand notation. 60 | type commonBitsLengths interface { 61 | // justification 62 | ~[1]byte 63 | } 64 | 65 | // commonBytesArrayLengths is a generic type whose purpose is to permit that 66 | // lists of different fixed-sized binary blob arrays can be passed to methods. 67 | // 68 | // You can add any size to this list really, it's just a limitation of the Go 69 | // generics compiler that it cannot represent arrays of arbitrary sizes with 70 | // one shorthand notation. 71 | type commonBytesArrayLengths[U commonBytesLengths] interface { 72 | // verkle IPA vectors | proof | committee | history | randao 73 | ~[8]U | ~[33]U | ~[512]U | ~[8192]U | ~[65536]U 74 | } 75 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_deneb_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadDeneb) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 + 4 + 32 + 32 + 4 + 4 + 8 + 8 11 | if fixed { 12 | return size 13 | } 14 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 15 | size += ssz.SizeSliceOfDynamicBytes(sizer, obj.Transactions) 16 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Withdrawals) 17 | 18 | return size 19 | } 20 | 21 | // DefineSSZ defines how an object is encoded/decoded. 22 | func (obj *ExecutionPayloadDeneb) DefineSSZ(codec *ssz.Codec) { 23 | // Define the static data (fields and dynamic offsets) 24 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 25 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 26 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 27 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 28 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 29 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 30 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 31 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 32 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 33 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 34 | ssz.DefineDynamicBytesOffset(codec, &obj.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 35 | ssz.DefineUint256(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 36 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 37 | ssz.DefineSliceOfDynamicBytesOffset(codec, &obj.Transactions, 1048576, 1073741824) // Offset (13) - Transactions - 4 bytes 38 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Withdrawals, 16) // Offset (14) - Withdrawals - 4 bytes 39 | ssz.DefineUint64(codec, &obj.BlobGasUsed) // Field (15) - BlobGasUsed - 8 bytes 40 | ssz.DefineUint64(codec, &obj.ExcessBlobGas) // Field (16) - ExcessBlobGas - 8 bytes 41 | 42 | // Define the dynamic data (fields) 43 | ssz.DefineDynamicBytesContent(codec, &obj.ExtraData, 32) // Field (10) - ExtraData - ? bytes 44 | ssz.DefineSliceOfDynamicBytesContent(codec, &obj.Transactions, 1048576, 1073741824) // Field (13) - Transactions - ? bytes 45 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Withdrawals, 16) // Field (14) - Withdrawals - ? bytes 46 | } 47 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_body_bellatrix_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconBlockBodyBellatrix = ssz.PrecomputeStaticSizeCache((*BeaconBlockBodyBellatrix)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconBlockBodyBellatrix) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconBlockBodyBellatrix) { 15 | size = staticSizeCacheBeaconBlockBodyBellatrix[fork] 16 | } else { 17 | size = 96 + (*Eth1Data)(nil).SizeSSZ(sizer) + 32 + 4 + 4 + 4 + 4 + 4 + (*SyncAggregate)(nil).SizeSSZ(sizer) + 4 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.ProposerSlashings) 24 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.AttesterSlashings) 25 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.Attestations) 26 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Deposits) 27 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.VoluntaryExits) 28 | size += ssz.SizeDynamicObject(sizer, obj.ExecutionPayload) 29 | 30 | return size 31 | } 32 | 33 | // DefineSSZ defines how an object is encoded/decoded. 34 | func (obj *BeaconBlockBodyBellatrix) DefineSSZ(codec *ssz.Codec) { 35 | // Define the static data (fields and dynamic offsets) 36 | ssz.DefineStaticBytes(codec, &obj.RandaoReveal) // Field (0) - RandaoReveal - 96 bytes 37 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field (1) - Eth1Data - ? bytes (Eth1Data) 38 | ssz.DefineStaticBytes(codec, &obj.Graffiti) // Field (2) - Graffiti - 32 bytes 39 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.ProposerSlashings, 16) // Offset (3) - ProposerSlashings - 4 bytes 40 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.AttesterSlashings, 2) // Offset (4) - AttesterSlashings - 4 bytes 41 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.Attestations, 128) // Offset (5) - Attestations - 4 bytes 42 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Deposits, 16) // Offset (6) - Deposits - 4 bytes 43 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.VoluntaryExits, 16) // Offset (7) - VoluntaryExits - 4 bytes 44 | ssz.DefineStaticObject(codec, &obj.SyncAggregate) // Field (8) - SyncAggregate - ? bytes (SyncAggregate) 45 | ssz.DefineDynamicObjectOffset(codec, &obj.ExecutionPayload) // Offset (9) - ExecutionPayload - 4 bytes 46 | 47 | // Define the dynamic data (fields) 48 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.ProposerSlashings, 16) // Field (3) - ProposerSlashings - ? bytes 49 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.AttesterSlashings, 2) // Field (4) - AttesterSlashings - ? bytes 50 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.Attestations, 128) // Field (5) - Attestations - ? bytes 51 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Deposits, 16) // Field (6) - Deposits - ? bytes 52 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.VoluntaryExits, 16) // Field (7) - VoluntaryExits - ? bytes 53 | ssz.DefineDynamicObjectContent(codec, &obj.ExecutionPayload) // Field (9) - ExecutionPayload - ? bytes 54 | } 55 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_header_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadHeaderMonolith) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 11 | if sizer.Fork() >= ssz.ForkFrontier { 12 | size += 4 13 | } 14 | size += 32 + 32 + 32 15 | if sizer.Fork() >= ssz.ForkShanghai { 16 | size += 32 17 | } 18 | if sizer.Fork() >= ssz.ForkCancun { 19 | size += 8 + 8 20 | } 21 | if fixed { 22 | return size 23 | } 24 | if sizer.Fork() >= ssz.ForkFrontier { 25 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 26 | } 27 | return size 28 | } 29 | 30 | // DefineSSZ defines how an object is encoded/decoded. 31 | func (obj *ExecutionPayloadHeaderMonolith) DefineSSZ(codec *ssz.Codec) { 32 | // Define the static data (fields and dynamic offsets) 33 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 34 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 35 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 36 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 37 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 38 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 39 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 40 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 41 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 42 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 43 | ssz.DefineDynamicBytesOffsetOnFork(codec, &obj.ExtraData, 32, ssz.ForkFilter{Added: ssz.ForkFrontier}) // Offset (10) - ExtraData - 4 bytes 44 | ssz.DefineStaticBytes(codec, &obj.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 45 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 46 | ssz.DefineStaticBytes(codec, &obj.TransactionsRoot) // Field (13) - TransactionsRoot - 32 bytes 47 | ssz.DefineStaticBytesPointerOnFork(codec, &obj.WithdrawalRoot, ssz.ForkFilter{Added: ssz.ForkShanghai}) // Field (14) - WithdrawalRoot - 32 bytes 48 | ssz.DefineUint64PointerOnFork(codec, &obj.BlobGasUsed, ssz.ForkFilter{Added: ssz.ForkCancun}) // Field (15) - BlobGasUsed - 8 bytes 49 | ssz.DefineUint64PointerOnFork(codec, &obj.ExcessBlobGas, ssz.ForkFilter{Added: ssz.ForkCancun}) // Field (16) - ExcessBlobGas - 8 bytes 50 | 51 | // Define the dynamic data (fields) 52 | ssz.DefineDynamicBytesContentOnFork(codec, &obj.ExtraData, 32, ssz.ForkFilter{Added: ssz.ForkFrontier}) // Field (10) - ExtraData - ? bytes 53 | } 54 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/types_variation.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package consensus_spec_tests 6 | 7 | import ( 8 | "math/big" 9 | 10 | "github.com/prysmaticlabs/go-bitfield" 11 | ) 12 | 13 | //go:generate go run -cover ../../../cmd/sszgen -type WithdrawalVariation -out gen_withdrawal_variation_ssz.go 14 | //go:generate go run -cover ../../../cmd/sszgen -type HistoricalBatchVariation -out gen_historical_batch_variation_ssz.go 15 | //go:generate go run -cover ../../../cmd/sszgen -type ExecutionPayloadVariation -out gen_execution_payload_variation_ssz.go 16 | //go:generate go run -cover ../../../cmd/sszgen -type AttestationVariation1 -out gen_attestation_variation_1_ssz.go 17 | //go:generate go run -cover ../../../cmd/sszgen -type AttestationVariation2 -out gen_attestation_variation_2_ssz.go 18 | //go:generate go run -cover ../../../cmd/sszgen -type AttestationVariation3 -out gen_attestation_variation_3_ssz.go 19 | //go:generate go run -cover ../../../cmd/sszgen -type AttestationDataVariation1 -out gen_attestation_data_variation_1_ssz.go 20 | //go:generate go run -cover ../../../cmd/sszgen -type AttestationDataVariation2 -out gen_attestation_data_variation_2_ssz.go 21 | //go:generate go run -cover ../../../cmd/sszgen -type AttestationDataVariation3 -out gen_attestation_data_variation_3_ssz.go 22 | 23 | type WithdrawalVariation struct { 24 | Index uint64 25 | Validator uint64 26 | Address []byte `ssz-size:"20"` // Static bytes defined via ssz-size tag 27 | Amount uint64 28 | } 29 | 30 | type HistoricalBatchVariation struct { 31 | BlockRoots [8192]Hash 32 | StateRoots []Hash `ssz-size:"8192"` // Static array defined via ssz-size tag 33 | } 34 | 35 | type ExecutionPayloadVariation struct { 36 | ParentHash Hash 37 | FeeRecipient Address 38 | StateRoot Hash 39 | ReceiptsRoot Hash 40 | LogsBloom LogsBloom 41 | PrevRandao Hash 42 | BlockNumber uint64 43 | GasLimit uint64 44 | GasUsed uint64 45 | Timestamp uint64 46 | ExtraData []byte `ssz-max:"32"` 47 | BaseFeePerGas *big.Int // Big.Int instead of the recommended uint256.Int 48 | BlockHash Hash 49 | Transactions [][]byte `ssz-max:"1048576,1073741824"` 50 | } 51 | 52 | // The types below test that fork constraints generate correct code for runtime 53 | // types (i.e. static objects embedded) for various positions. 54 | 55 | type AttestationVariation1 struct { 56 | Future *uint64 `ssz-fork:"future"` // Currently unused field 57 | AggregationBits bitfield.Bitlist `ssz-max:"2048"` 58 | Data *AttestationData 59 | Signature [96]byte 60 | } 61 | type AttestationVariation2 struct { 62 | AggregationBits bitfield.Bitlist `ssz-max:"2048"` 63 | Data *AttestationData 64 | Future *uint64 `ssz-fork:"future"` // Currently unused field 65 | Signature [96]byte 66 | } 67 | type AttestationVariation3 struct { 68 | AggregationBits bitfield.Bitlist `ssz-max:"2048"` 69 | Data *AttestationData 70 | Signature [96]byte 71 | Future *uint64 `ssz-fork:"future"` // Currently unused field 72 | } 73 | 74 | type AttestationDataVariation1 struct { 75 | Future *uint64 `ssz-fork:"future"` // Currently unused field 76 | Slot Slot 77 | Index uint64 78 | BeaconBlockHash Hash 79 | Source *Checkpoint 80 | Target *Checkpoint 81 | } 82 | type AttestationDataVariation2 struct { 83 | Slot Slot 84 | Index uint64 85 | BeaconBlockHash Hash 86 | Future *uint64 `ssz-fork:"future"` // Currently unused field 87 | Source *Checkpoint 88 | Target *Checkpoint 89 | } 90 | type AttestationDataVariation3 struct { 91 | Slot Slot 92 | Index uint64 93 | BeaconBlockHash Hash 94 | Source *Checkpoint 95 | Target *Checkpoint 96 | Future *uint64 `ssz-fork:"future"` // Currently unused field 97 | } 98 | -------------------------------------------------------------------------------- /forks.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz 6 | 7 | // Fork is an enum with all the hard forks that Ethereum mainnet went through, 8 | // which can be used to multiplex monolith types that can encode/decode across 9 | // a range of forks, not just for one specific. 10 | // 11 | // These enums are only meaningful in relation to one another, but are completely 12 | // meaningless numbers otherwise. Do not persist them across code versions. 13 | type Fork int 14 | 15 | const ( 16 | ForkUnknown Fork = iota // Placeholder if forks haven't been specified (must be index 0) 17 | 18 | ForkFrontier // https://ethereum.org/en/history/#frontier 19 | ForkHomestead // https://ethereum.org/en/history/#homestead 20 | ForkDAO // https://ethereum.org/en/history/#dao-fork 21 | ForkTangerine // https://ethereum.org/en/history/#tangerine-whistle 22 | ForkSpurious // https://ethereum.org/en/history/#spurious-dragon 23 | ForkByzantium // https://ethereum.org/en/history/#byzantium 24 | ForkConstantinople // https://ethereum.org/en/history/#constantinople 25 | ForkIstanbul // https://ethereum.org/en/history/#istanbul 26 | ForkMuir // https://ethereum.org/en/history/#muir-glacier 27 | ForkPhase0 // https://ethereum.org/en/history/#beacon-chain-genesis 28 | ForkBerlin // https://ethereum.org/en/history/#berlin 29 | ForkLondon // https://ethereum.org/en/history/#london 30 | ForkAltair // https://ethereum.org/en/history/#altair 31 | ForkArrow // https://ethereum.org/en/history/#arrow-glacier 32 | ForkGray // https://ethereum.org/en/history/#gray-glacier 33 | ForkBellatrix // https://ethereum.org/en/history/#bellatrix 34 | ForkParis // https://ethereum.org/en/history/#paris 35 | ForkShapella // https://ethereum.org/en/history/#shapella 36 | ForkDencun // https://ethereum.org/en/history/#dencun 37 | ForkPectra // https://ethereum.org/en/history/#pectra 38 | 39 | ForkFuture // Use this for specifying future features (must be last index, no gaps) 40 | 41 | ForkMerge = ForkParis // Common alias for Paris 42 | ForkShanghai = ForkShapella // EL alias for Shapella 43 | ForkCapella = ForkShapella // CL alias for Shapella 44 | ForkCancun = ForkDencun // EL alias for Dencun 45 | ForkDeneb = ForkDencun // CL alias for Dencun 46 | ForkPrague = ForkPectra // EL alias for Pectra 47 | ForkElectra = ForkPectra // CL alias for Pectra 48 | ) 49 | 50 | // ForkMapping maps fork names to fork values. This is used internally by the 51 | // ssz codec generator to convert tags to values. 52 | var ForkMapping = map[string]Fork{ 53 | "unknown": ForkUnknown, 54 | "frontier": ForkFrontier, 55 | "homestead": ForkHomestead, 56 | "dao": ForkDAO, 57 | "tangerine": ForkTangerine, 58 | "spurious": ForkSpurious, 59 | "byzantium": ForkByzantium, 60 | "constantinople": ForkConstantinople, 61 | "istanbul": ForkIstanbul, 62 | "muir": ForkMuir, 63 | "phase0": ForkPhase0, 64 | "berlin": ForkBerlin, 65 | "london": ForkLondon, 66 | "altair": ForkAltair, 67 | "arrow": ForkArrow, 68 | "gray": ForkGray, 69 | "bellatrix": ForkBellatrix, 70 | "paris": ForkParis, 71 | "merge": ForkMerge, 72 | "shapella": ForkShapella, 73 | "shanghai": ForkShanghai, 74 | "capella": ForkCapella, 75 | "dencun": ForkDencun, 76 | "cancun": ForkCancun, 77 | "deneb": ForkDeneb, 78 | "pectra": ForkPectra, 79 | "prague": ForkPrague, 80 | "electra": ForkElectra, 81 | "future": ForkFuture, 82 | } 83 | 84 | // ForkFilter can be used by the XXXOnFork methods inside monolithic types to 85 | // define certain fields appearing only in certain forks. 86 | type ForkFilter struct { 87 | Added Fork 88 | Removed Fork 89 | } 90 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_body_capella_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconBlockBodyCapella = ssz.PrecomputeStaticSizeCache((*BeaconBlockBodyCapella)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconBlockBodyCapella) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconBlockBodyCapella) { 15 | size = staticSizeCacheBeaconBlockBodyCapella[fork] 16 | } else { 17 | size = 96 + (*Eth1Data)(nil).SizeSSZ(sizer) + 32 + 4 + 4 + 4 + 4 + 4 + (*SyncAggregate)(nil).SizeSSZ(sizer) + 4 + 4 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.ProposerSlashings) 24 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.AttesterSlashings) 25 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.Attestations) 26 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Deposits) 27 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.VoluntaryExits) 28 | size += ssz.SizeDynamicObject(sizer, obj.ExecutionPayload) 29 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.BlsToExecutionChanges) 30 | 31 | return size 32 | } 33 | 34 | // DefineSSZ defines how an object is encoded/decoded. 35 | func (obj *BeaconBlockBodyCapella) DefineSSZ(codec *ssz.Codec) { 36 | // Define the static data (fields and dynamic offsets) 37 | ssz.DefineStaticBytes(codec, &obj.RandaoReveal) // Field ( 0) - RandaoReveal - 96 bytes 38 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 1) - Eth1Data - ? bytes (Eth1Data) 39 | ssz.DefineStaticBytes(codec, &obj.Graffiti) // Field ( 2) - Graffiti - 32 bytes 40 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.ProposerSlashings, 16) // Offset ( 3) - ProposerSlashings - 4 bytes 41 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.AttesterSlashings, 2) // Offset ( 4) - AttesterSlashings - 4 bytes 42 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.Attestations, 128) // Offset ( 5) - Attestations - 4 bytes 43 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Deposits, 16) // Offset ( 6) - Deposits - 4 bytes 44 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.VoluntaryExits, 16) // Offset ( 7) - VoluntaryExits - 4 bytes 45 | ssz.DefineStaticObject(codec, &obj.SyncAggregate) // Field ( 8) - SyncAggregate - ? bytes (SyncAggregate) 46 | ssz.DefineDynamicObjectOffset(codec, &obj.ExecutionPayload) // Offset ( 9) - ExecutionPayload - 4 bytes 47 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.BlsToExecutionChanges, 16) // Offset (10) - BlsToExecutionChanges - 4 bytes 48 | 49 | // Define the dynamic data (fields) 50 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.ProposerSlashings, 16) // Field ( 3) - ProposerSlashings - ? bytes 51 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.AttesterSlashings, 2) // Field ( 4) - AttesterSlashings - ? bytes 52 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.Attestations, 128) // Field ( 5) - Attestations - ? bytes 53 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Deposits, 16) // Field ( 6) - Deposits - ? bytes 54 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.VoluntaryExits, 16) // Field ( 7) - VoluntaryExits - ? bytes 55 | ssz.DefineDynamicObjectContent(codec, &obj.ExecutionPayload) // Field ( 9) - ExecutionPayload - ? bytes 56 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.BlsToExecutionChanges, 16) // Field (10) - BlsToExecutionChanges - ? bytes 57 | } 58 | -------------------------------------------------------------------------------- /cmd/sszgen/types.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "go/types" 10 | ) 11 | 12 | type sszContainer struct { 13 | *types.Struct 14 | named *types.Named 15 | static bool 16 | fields []string // Name of the struct field 17 | types []types.Type // Type of the struct field 18 | opsets []opset // Opset for the struct field 19 | forks []string // Fork constraint for the struct field 20 | } 21 | 22 | // makeContainer iterates over the fields of the struct and attempt to match each 23 | // field with an opset for encoding/decoding ssz. 24 | func (p *parseContext) makeContainer(named *types.Named, typ *types.Struct) (*sszContainer, error) { 25 | var ( 26 | static = true 27 | fields []string 28 | types []types.Type 29 | opsets []opset 30 | forks []string 31 | ) 32 | // Iterate over all the fields of the struct 33 | for i := 0; i < typ.NumFields(); i++ { 34 | // Skip private fields, and skip ignored ssz fields 35 | f := typ.Field(i) 36 | if !f.Exported() { 37 | continue 38 | } 39 | ignore, tags, fork, err := parseTags(typ.Tag(i)) 40 | if err != nil { 41 | return nil, fmt.Errorf("failed to parse field %s.%s tags: %v", named.Obj().Name(), f.Name(), err) 42 | } 43 | if ignore { 44 | continue 45 | } 46 | // Required field found, validate type with tag content 47 | opset, err := p.resolveOpset(f.Type(), tags, false) 48 | if err != nil { 49 | return nil, fmt.Errorf("failed to validate field %s.%s: %v", named.Obj().Name(), f.Name(), err) 50 | } 51 | if _, ok := (opset).(*opsetDynamic); ok { 52 | static = false 53 | } 54 | fields = append(fields, f.Name()) 55 | types = append(types, f.Type()) 56 | opsets = append(opsets, opset) 57 | forks = append(forks, fork) 58 | } 59 | return &sszContainer{ 60 | Struct: typ, 61 | named: named, 62 | static: static, 63 | fields: fields, 64 | types: types, 65 | opsets: opsets, 66 | forks: forks, 67 | }, nil 68 | } 69 | 70 | // resolveOpset compares the type of the field to the provided tags and returns 71 | // whether there's a collision between them, or if more tags are needed to fully 72 | // derive the size. If the type/tags are in sync and well-defined, an opset will 73 | // be returned that the generator can use to create the code. 74 | func (p *parseContext) resolveOpset(typ types.Type, tags *sizeTag, pointer bool) (opset, error) { 75 | switch t := typ.(type) { 76 | case *types.Named: 77 | if isBitlist(typ) { 78 | return p.resolveBitlistOpset(tags) 79 | } 80 | return p.resolveOpset(t.Underlying(), tags, pointer) 81 | 82 | case *types.Basic: 83 | return p.resolveBasicOpset(t, tags, pointer) 84 | 85 | case *types.Array: 86 | return p.resolveArrayOpset(t.Elem(), int(t.Len()), tags, pointer) 87 | 88 | case *types.Slice: 89 | return p.resolveSliceOpset(t.Elem(), tags) 90 | 91 | case *types.Pointer: 92 | switch tt := t.Elem().(type) { 93 | case *types.Basic: 94 | return p.resolveBasicOpset(tt, tags, true) 95 | 96 | case *types.Array: 97 | return p.resolveArrayOpset(tt.Elem(), int(tt.Len()), tags, true) 98 | 99 | } 100 | return p.resolvePointerOpset(t, tags) 101 | } 102 | return nil, fmt.Errorf("unsupported type %s", typ.String()) 103 | } 104 | 105 | // isBigInt checks whether 'typ' is "math/big".Int. 106 | func isBigInt(typ types.Type) bool { 107 | named, ok := typ.(*types.Named) 108 | if !ok { 109 | return false 110 | } 111 | name := named.Obj() 112 | return name.Pkg().Path() == "math/big" && name.Name() == "Int" 113 | } 114 | 115 | // isUint256 checks whether 'typ' is "github.com/holiman/uint256".Int. 116 | func isUint256(typ types.Type) bool { 117 | named, ok := typ.(*types.Named) 118 | if !ok { 119 | return false 120 | } 121 | name := named.Obj() 122 | return name.Pkg().Path() == "github.com/holiman/uint256" && name.Name() == "Int" 123 | } 124 | 125 | // isBitlist checks whether 'typ' is "github.com/prysmaticlabs/go-bitfield".Bitlist. 126 | func isBitlist(typ types.Type) bool { 127 | named, ok := typ.(*types.Named) 128 | if !ok { 129 | return false 130 | } 131 | name := named.Obj() 132 | return name.Pkg().Path() == "github.com/prysmaticlabs/go-bitfield" && name.Name() == "Bitlist" 133 | } 134 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_body_deneb_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconBlockBodyDeneb = ssz.PrecomputeStaticSizeCache((*BeaconBlockBodyDeneb)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconBlockBodyDeneb) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconBlockBodyDeneb) { 15 | size = staticSizeCacheBeaconBlockBodyDeneb[fork] 16 | } else { 17 | size = 96 + (*Eth1Data)(nil).SizeSSZ(sizer) + 32 + 4 + 4 + 4 + 4 + 4 + (*SyncAggregate)(nil).SizeSSZ(sizer) + 4 + 4 + 4 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.ProposerSlashings) 24 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.AttesterSlashings) 25 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.Attestations) 26 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Deposits) 27 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.VoluntaryExits) 28 | size += ssz.SizeDynamicObject(sizer, obj.ExecutionPayload) 29 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.BlsToExecutionChanges) 30 | size += ssz.SizeSliceOfStaticBytes(sizer, obj.BlobKzgCommitments) 31 | 32 | return size 33 | } 34 | 35 | // DefineSSZ defines how an object is encoded/decoded. 36 | func (obj *BeaconBlockBodyDeneb) DefineSSZ(codec *ssz.Codec) { 37 | // Define the static data (fields and dynamic offsets) 38 | ssz.DefineStaticBytes(codec, &obj.RandaoReveal) // Field ( 0) - RandaoReveal - 96 bytes 39 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 1) - Eth1Data - ? bytes (Eth1Data) 40 | ssz.DefineStaticBytes(codec, &obj.Graffiti) // Field ( 2) - Graffiti - 32 bytes 41 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.ProposerSlashings, 16) // Offset ( 3) - ProposerSlashings - 4 bytes 42 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.AttesterSlashings, 2) // Offset ( 4) - AttesterSlashings - 4 bytes 43 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.Attestations, 128) // Offset ( 5) - Attestations - 4 bytes 44 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Deposits, 16) // Offset ( 6) - Deposits - 4 bytes 45 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.VoluntaryExits, 16) // Offset ( 7) - VoluntaryExits - 4 bytes 46 | ssz.DefineStaticObject(codec, &obj.SyncAggregate) // Field ( 8) - SyncAggregate - ? bytes (SyncAggregate) 47 | ssz.DefineDynamicObjectOffset(codec, &obj.ExecutionPayload) // Offset ( 9) - ExecutionPayload - 4 bytes 48 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.BlsToExecutionChanges, 16) // Offset (10) - BlsToExecutionChanges - 4 bytes 49 | ssz.DefineSliceOfStaticBytesOffset(codec, &obj.BlobKzgCommitments, 4096) // Offset (11) - BlobKzgCommitments - 4 bytes 50 | 51 | // Define the dynamic data (fields) 52 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.ProposerSlashings, 16) // Field ( 3) - ProposerSlashings - ? bytes 53 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.AttesterSlashings, 2) // Field ( 4) - AttesterSlashings - ? bytes 54 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.Attestations, 128) // Field ( 5) - Attestations - ? bytes 55 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Deposits, 16) // Field ( 6) - Deposits - ? bytes 56 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.VoluntaryExits, 16) // Field ( 7) - VoluntaryExits - ? bytes 57 | ssz.DefineDynamicObjectContent(codec, &obj.ExecutionPayload) // Field ( 9) - ExecutionPayload - ? bytes 58 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.BlsToExecutionChanges, 16) // Field (10) - BlsToExecutionChanges - ? bytes 59 | ssz.DefineSliceOfStaticBytesContent(codec, &obj.BlobKzgCommitments, 4096) // Field (11) - BlobKzgCommitments - ? bytes 60 | } 61 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_monolith_2_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadMonolith2) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 11 | if sizer.Fork() >= ssz.ForkFrontier { 12 | size += 4 13 | } 14 | if sizer.Fork() >= ssz.ForkUnknown { 15 | size += 32 16 | } 17 | size += 32 + 4 18 | if sizer.Fork() >= ssz.ForkShanghai { 19 | size += 4 20 | } 21 | if sizer.Fork() >= ssz.ForkCancun { 22 | size += 8 + 8 23 | } 24 | if fixed { 25 | return size 26 | } 27 | if sizer.Fork() >= ssz.ForkFrontier { 28 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 29 | } 30 | size += ssz.SizeSliceOfDynamicBytes(sizer, obj.Transactions) 31 | if sizer.Fork() >= ssz.ForkShanghai { 32 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Withdrawals) 33 | } 34 | return size 35 | } 36 | 37 | // DefineSSZ defines how an object is encoded/decoded. 38 | func (obj *ExecutionPayloadMonolith2) DefineSSZ(codec *ssz.Codec) { 39 | // Define the static data (fields and dynamic offsets) 40 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 41 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 42 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 43 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 44 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 45 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 46 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 47 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 48 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 49 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 50 | ssz.DefineDynamicBytesOffsetOnFork(codec, &obj.ExtraData, 32, ssz.ForkFilter{Added: ssz.ForkFrontier}) // Offset (10) - ExtraData - 4 bytes 51 | ssz.DefineUint256BigIntOnFork(codec, &obj.BaseFeePerGas, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (11) - BaseFeePerGas - 32 bytes 52 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 53 | ssz.DefineSliceOfDynamicBytesOffset(codec, &obj.Transactions, 1048576, 1073741824) // Offset (13) - Transactions - 4 bytes 54 | ssz.DefineSliceOfStaticObjectsOffsetOnFork(codec, &obj.Withdrawals, 16, ssz.ForkFilter{Added: ssz.ForkShanghai}) // Offset (14) - Withdrawals - 4 bytes 55 | ssz.DefineUint64PointerOnFork(codec, &obj.BlobGasUsed, ssz.ForkFilter{Added: ssz.ForkCancun}) // Field (15) - BlobGasUsed - 8 bytes 56 | ssz.DefineUint64PointerOnFork(codec, &obj.ExcessBlobGas, ssz.ForkFilter{Added: ssz.ForkCancun}) // Field (16) - ExcessBlobGas - 8 bytes 57 | 58 | // Define the dynamic data (fields) 59 | ssz.DefineDynamicBytesContentOnFork(codec, &obj.ExtraData, 32, ssz.ForkFilter{Added: ssz.ForkFrontier}) // Field (10) - ExtraData - ? bytes 60 | ssz.DefineSliceOfDynamicBytesContent(codec, &obj.Transactions, 1048576, 1073741824) // Field (13) - Transactions - ? bytes 61 | ssz.DefineSliceOfStaticObjectsContentOnFork(codec, &obj.Withdrawals, 16, ssz.ForkFilter{Added: ssz.ForkShanghai}) // Field (14) - Withdrawals - ? bytes 62 | } 63 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_execution_payload_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // SizeSSZ returns either the static size of the object if fixed == true, or 8 | // the total size otherwise. 9 | func (obj *ExecutionPayloadMonolith) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 10 | size = 32 + 20 + 32 + 32 + 256 + 32 + 8 + 8 + 8 + 8 11 | if sizer.Fork() >= ssz.ForkFrontier { 12 | size += 4 13 | } 14 | if sizer.Fork() >= ssz.ForkUnknown { 15 | size += 32 16 | } 17 | size += 32 18 | if sizer.Fork() >= ssz.ForkUnknown { 19 | size += 4 20 | } 21 | if sizer.Fork() >= ssz.ForkShanghai { 22 | size += 4 23 | } 24 | if sizer.Fork() >= ssz.ForkCancun { 25 | size += 8 + 8 26 | } 27 | if fixed { 28 | return size 29 | } 30 | if sizer.Fork() >= ssz.ForkFrontier { 31 | size += ssz.SizeDynamicBytes(sizer, obj.ExtraData) 32 | } 33 | if sizer.Fork() >= ssz.ForkUnknown { 34 | size += ssz.SizeSliceOfDynamicBytes(sizer, obj.Transactions) 35 | } 36 | if sizer.Fork() >= ssz.ForkShanghai { 37 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Withdrawals) 38 | } 39 | return size 40 | } 41 | 42 | // DefineSSZ defines how an object is encoded/decoded. 43 | func (obj *ExecutionPayloadMonolith) DefineSSZ(codec *ssz.Codec) { 44 | // Define the static data (fields and dynamic offsets) 45 | ssz.DefineStaticBytes(codec, &obj.ParentHash) // Field ( 0) - ParentHash - 32 bytes 46 | ssz.DefineStaticBytes(codec, &obj.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 47 | ssz.DefineStaticBytes(codec, &obj.StateRoot) // Field ( 2) - StateRoot - 32 bytes 48 | ssz.DefineStaticBytes(codec, &obj.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 49 | ssz.DefineStaticBytes(codec, &obj.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 50 | ssz.DefineStaticBytes(codec, &obj.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 51 | ssz.DefineUint64(codec, &obj.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 52 | ssz.DefineUint64(codec, &obj.GasLimit) // Field ( 7) - GasLimit - 8 bytes 53 | ssz.DefineUint64(codec, &obj.GasUsed) // Field ( 8) - GasUsed - 8 bytes 54 | ssz.DefineUint64(codec, &obj.Timestamp) // Field ( 9) - Timestamp - 8 bytes 55 | ssz.DefineDynamicBytesOffsetOnFork(codec, &obj.ExtraData, 32, ssz.ForkFilter{Added: ssz.ForkFrontier}) // Offset (10) - ExtraData - 4 bytes 56 | ssz.DefineUint256OnFork(codec, &obj.BaseFeePerGas, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (11) - BaseFeePerGas - 32 bytes 57 | ssz.DefineStaticBytes(codec, &obj.BlockHash) // Field (12) - BlockHash - 32 bytes 58 | ssz.DefineSliceOfDynamicBytesOffsetOnFork(codec, &obj.Transactions, 1048576, 1073741824, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Offset (13) - Transactions - 4 bytes 59 | ssz.DefineSliceOfStaticObjectsOffsetOnFork(codec, &obj.Withdrawals, 16, ssz.ForkFilter{Added: ssz.ForkShanghai}) // Offset (14) - Withdrawals - 4 bytes 60 | ssz.DefineUint64PointerOnFork(codec, &obj.BlobGasUsed, ssz.ForkFilter{Added: ssz.ForkCancun}) // Field (15) - BlobGasUsed - 8 bytes 61 | ssz.DefineUint64PointerOnFork(codec, &obj.ExcessBlobGas, ssz.ForkFilter{Added: ssz.ForkCancun}) // Field (16) - ExcessBlobGas - 8 bytes 62 | 63 | // Define the dynamic data (fields) 64 | ssz.DefineDynamicBytesContentOnFork(codec, &obj.ExtraData, 32, ssz.ForkFilter{Added: ssz.ForkFrontier}) // Field (10) - ExtraData - ? bytes 65 | ssz.DefineSliceOfDynamicBytesContentOnFork(codec, &obj.Transactions, 1048576, 1073741824, ssz.ForkFilter{Added: ssz.ForkUnknown}) // Field (13) - Transactions - ? bytes 66 | ssz.DefineSliceOfStaticObjectsContentOnFork(codec, &obj.Withdrawals, 16, ssz.ForkFilter{Added: ssz.ForkShanghai}) // Field (14) - Withdrawals - ? bytes 67 | } 68 | -------------------------------------------------------------------------------- /example_dynamic_test.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package ssz_test 6 | 7 | import ( 8 | "fmt" 9 | 10 | "github.com/holiman/uint256" 11 | "github.com/karalabe/ssz" 12 | ) 13 | 14 | type Hash [32]byte 15 | type LogsBLoom [256]byte 16 | 17 | type ExecutionPayload struct { 18 | ParentHash Hash `ssz-size:"32"` 19 | FeeRecipient Address `ssz-size:"20"` 20 | StateRoot Hash `ssz-size:"32"` 21 | ReceiptsRoot Hash `ssz-size:"32"` 22 | LogsBloom LogsBLoom `ssz-size:"256"` 23 | PrevRandao Hash `ssz-size:"32"` 24 | BlockNumber uint64 `ssz-size:"8"` 25 | GasLimit uint64 `ssz-size:"8"` 26 | GasUsed uint64 `ssz-size:"8"` 27 | Timestamp uint64 `ssz-size:"8"` 28 | ExtraData []byte `ssz-max:"32"` 29 | BaseFeePerGas *uint256.Int `ssz-size:"32"` 30 | BlockHash Hash `ssz-size:"32"` 31 | Transactions [][]byte `ssz-max:"1048576,1073741824"` 32 | Withdrawals []*Withdrawal `ssz-max:"16"` 33 | } 34 | 35 | func (e *ExecutionPayload) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { 36 | // Start out with the static size 37 | size := uint32(512) 38 | if fixed { 39 | return size 40 | } 41 | // Append all the dynamic sizes 42 | size += ssz.SizeDynamicBytes(siz, e.ExtraData) // Field (10) - ExtraData - max 32 bytes (not enforced) 43 | size += ssz.SizeSliceOfDynamicBytes(siz, e.Transactions) // Field (13) - Transactions - max 1048576 items, 1073741824 bytes each (not enforced) 44 | size += ssz.SizeSliceOfStaticObjects(siz, e.Withdrawals) // Field (14) - Withdrawals - max 16 items, 44 bytes each (not enforced) 45 | 46 | return size 47 | } 48 | func (e *ExecutionPayload) DefineSSZ(codec *ssz.Codec) { 49 | // Define the static data (fields and dynamic offsets) 50 | ssz.DefineStaticBytes(codec, &e.ParentHash) // Field ( 0) - ParentHash - 32 bytes 51 | ssz.DefineStaticBytes(codec, &e.FeeRecipient) // Field ( 1) - FeeRecipient - 20 bytes 52 | ssz.DefineStaticBytes(codec, &e.StateRoot) // Field ( 2) - StateRoot - 32 bytes 53 | ssz.DefineStaticBytes(codec, &e.ReceiptsRoot) // Field ( 3) - ReceiptsRoot - 32 bytes 54 | ssz.DefineStaticBytes(codec, &e.LogsBloom) // Field ( 4) - LogsBloom - 256 bytes 55 | ssz.DefineStaticBytes(codec, &e.PrevRandao) // Field ( 5) - PrevRandao - 32 bytes 56 | ssz.DefineUint64(codec, &e.BlockNumber) // Field ( 6) - BlockNumber - 8 bytes 57 | ssz.DefineUint64(codec, &e.GasLimit) // Field ( 7) - GasLimit - 8 bytes 58 | ssz.DefineUint64(codec, &e.GasUsed) // Field ( 8) - GasUsed - 8 bytes 59 | ssz.DefineUint64(codec, &e.Timestamp) // Field ( 9) - Timestamp - 8 bytes 60 | ssz.DefineDynamicBytesOffset(codec, &e.ExtraData, 32) // Offset (10) - ExtraData - 4 bytes 61 | ssz.DefineUint256(codec, &e.BaseFeePerGas) // Field (11) - BaseFeePerGas - 32 bytes 62 | ssz.DefineStaticBytes(codec, &e.BlockHash) // Field (12) - BlockHash - 32 bytes 63 | ssz.DefineSliceOfDynamicBytesOffset(codec, &e.Transactions, 1_048_576, 1_073_741_824) // Offset (13) - Transactions - 4 bytes 64 | ssz.DefineSliceOfStaticObjectsOffset(codec, &e.Withdrawals, 16) // Offset (14) - Withdrawals - 4 bytes 65 | 66 | // Define the dynamic data (fields) 67 | ssz.DefineDynamicBytesContent(codec, &e.ExtraData, 32) // Field (10) - ExtraData 68 | ssz.DefineSliceOfDynamicBytesContent(codec, &e.Transactions, 1_048_576, 1_073_741_824) // Field (13) - Transactions 69 | ssz.DefineSliceOfStaticObjectsContent(codec, &e.Withdrawals, 16) // Field (14) - Withdrawals 70 | } 71 | 72 | func ExampleEncodeDynamicObject() { 73 | obj := new(ExecutionPayload) 74 | 75 | blob := make([]byte, ssz.Size(obj)) 76 | if err := ssz.EncodeToBytes(blob, obj); err != nil { 77 | panic(err) 78 | } 79 | fmt.Printf("ssz: %#x\n", blob) 80 | // Output: 81 | // ssz: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000020000 82 | } 83 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_block_body_monolith_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconBlockBodyMonolith = ssz.PrecomputeStaticSizeCache((*BeaconBlockBodyMonolith)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconBlockBodyMonolith) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconBlockBodyMonolith) { 15 | size = staticSizeCacheBeaconBlockBodyMonolith[fork] 16 | } else { 17 | size = 96 + (*Eth1Data)(nil).SizeSSZ(sizer) + 32 + 4 + 4 + 4 + 4 + 4 18 | if sizer.Fork() >= ssz.ForkAltair { 19 | size += (*SyncAggregate)(nil).SizeSSZ(sizer) 20 | } 21 | if sizer.Fork() >= ssz.ForkBellatrix { 22 | size += 4 23 | } 24 | if sizer.Fork() >= ssz.ForkCapella { 25 | size += 4 26 | } 27 | if sizer.Fork() >= ssz.ForkDeneb { 28 | size += 4 29 | } 30 | } 31 | // Either return the static size or accumulate the dynamic too 32 | if fixed { 33 | return size 34 | } 35 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.ProposerSlashings) 36 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.AttesterSlashings) 37 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.Attestations) 38 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Deposits) 39 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.VoluntaryExits) 40 | if sizer.Fork() >= ssz.ForkBellatrix { 41 | size += ssz.SizeDynamicObject(sizer, obj.ExecutionPayload) 42 | } 43 | if sizer.Fork() >= ssz.ForkCapella { 44 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.BlsToExecutionChanges) 45 | } 46 | if sizer.Fork() >= ssz.ForkDeneb { 47 | size += ssz.SizeSliceOfStaticBytes(sizer, obj.BlobKzgCommitments) 48 | } 49 | return size 50 | } 51 | 52 | // DefineSSZ defines how an object is encoded/decoded. 53 | func (obj *BeaconBlockBodyMonolith) DefineSSZ(codec *ssz.Codec) { 54 | // Define the static data (fields and dynamic offsets) 55 | ssz.DefineStaticBytes(codec, &obj.RandaoReveal) // Field ( 0) - RandaoReveal - 96 bytes 56 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 1) - Eth1Data - ? bytes (Eth1Data) 57 | ssz.DefineStaticBytes(codec, &obj.Graffiti) // Field ( 2) - Graffiti - 32 bytes 58 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.ProposerSlashings, 16) // Offset ( 3) - ProposerSlashings - 4 bytes 59 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.AttesterSlashings, 2) // Offset ( 4) - AttesterSlashings - 4 bytes 60 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.Attestations, 128) // Offset ( 5) - Attestations - 4 bytes 61 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Deposits, 16) // Offset ( 6) - Deposits - 4 bytes 62 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.VoluntaryExits, 16) // Offset ( 7) - VoluntaryExits - 4 bytes 63 | ssz.DefineStaticObjectOnFork(codec, &obj.SyncAggregate, ssz.ForkFilter{Added: ssz.ForkAltair}) // Field ( 8) - SyncAggregate - ? bytes (SyncAggregate) 64 | ssz.DefineDynamicObjectOffsetOnFork(codec, &obj.ExecutionPayload, ssz.ForkFilter{Added: ssz.ForkBellatrix}) // Offset ( 9) - ExecutionPayload - 4 bytes 65 | ssz.DefineSliceOfStaticObjectsOffsetOnFork(codec, &obj.BlsToExecutionChanges, 16, ssz.ForkFilter{Added: ssz.ForkCapella}) // Offset (10) - BlsToExecutionChanges - 4 bytes 66 | ssz.DefineSliceOfStaticBytesOffsetOnFork(codec, &obj.BlobKzgCommitments, 4096, ssz.ForkFilter{Added: ssz.ForkDeneb}) // Offset (11) - BlobKzgCommitments - 4 bytes 67 | 68 | // Define the dynamic data (fields) 69 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.ProposerSlashings, 16) // Field ( 3) - ProposerSlashings - ? bytes 70 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.AttesterSlashings, 2) // Field ( 4) - AttesterSlashings - ? bytes 71 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.Attestations, 128) // Field ( 5) - Attestations - ? bytes 72 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Deposits, 16) // Field ( 6) - Deposits - ? bytes 73 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.VoluntaryExits, 16) // Field ( 7) - VoluntaryExits - ? bytes 74 | ssz.DefineDynamicObjectContentOnFork(codec, &obj.ExecutionPayload, ssz.ForkFilter{Added: ssz.ForkBellatrix}) // Field ( 9) - ExecutionPayload - ? bytes 75 | ssz.DefineSliceOfStaticObjectsContentOnFork(codec, &obj.BlsToExecutionChanges, 16, ssz.ForkFilter{Added: ssz.ForkCapella}) // Field (10) - BlsToExecutionChanges - ? bytes 76 | ssz.DefineSliceOfStaticBytesContentOnFork(codec, &obj.BlobKzgCommitments, 4096, ssz.ForkFilter{Added: ssz.ForkDeneb}) // Field (11) - BlobKzgCommitments - ? bytes 77 | } 78 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_state_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconState = ssz.PrecomputeStaticSizeCache((*BeaconState)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconState) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconState) { 15 | size = staticSizeCacheBeaconState[fork] 16 | } else { 17 | size = 8 + 32 + 8 + (*Fork)(nil).SizeSSZ(sizer) + (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 8192*32 + 8192*32 + 4 + (*Eth1Data)(nil).SizeSSZ(sizer) + 4 + 8 + 4 + 4 + 65536*32 + 8192*8 + 4 + 4 + 1 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticBytes(sizer, obj.HistoricalRoots) 24 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Eth1DataVotes) 25 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Validators) 26 | size += ssz.SizeSliceOfUint64s(sizer, obj.Balances) 27 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.PreviousEpochAttestations) 28 | size += ssz.SizeSliceOfDynamicObjects(sizer, obj.CurrentEpochAttestations) 29 | 30 | return size 31 | } 32 | 33 | // DefineSSZ defines how an object is encoded/decoded. 34 | func (obj *BeaconState) DefineSSZ(codec *ssz.Codec) { 35 | // Define the static data (fields and dynamic offsets) 36 | ssz.DefineUint64(codec, &obj.GenesisTime) // Field ( 0) - GenesisTime - 8 bytes 37 | ssz.DefineStaticBytes(codec, &obj.GenesisValidatorsRoot) // Field ( 1) - GenesisValidatorsRoot - 32 bytes 38 | ssz.DefineUint64(codec, &obj.Slot) // Field ( 2) - Slot - 8 bytes 39 | ssz.DefineStaticObject(codec, &obj.Fork) // Field ( 3) - Fork - ? bytes (Fork) 40 | ssz.DefineStaticObject(codec, &obj.LatestBlockHeader) // Field ( 4) - LatestBlockHeader - ? bytes (BeaconBlockHeader) 41 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field ( 5) - BlockRoots - 262144 bytes 42 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.StateRoots[:]) // Field ( 6) - StateRoots - 262144 bytes 43 | ssz.DefineSliceOfStaticBytesOffset(codec, &obj.HistoricalRoots, 16777216) // Offset ( 7) - HistoricalRoots - 4 bytes 44 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 8) - Eth1Data - ? bytes (Eth1Data) 45 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Eth1DataVotes, 2048) // Offset ( 9) - Eth1DataVotes - 4 bytes 46 | ssz.DefineUint64(codec, &obj.Eth1DepositIndex) // Field (10) - Eth1DepositIndex - 8 bytes 47 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Validators, 1099511627776) // Offset (11) - Validators - 4 bytes 48 | ssz.DefineSliceOfUint64sOffset(codec, &obj.Balances, 1099511627776) // Offset (12) - Balances - 4 bytes 49 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.RandaoMixes[:]) // Field (13) - RandaoMixes - 2097152 bytes 50 | ssz.DefineArrayOfUint64s(codec, &obj.Slashings) // Field (14) - Slashings - 65536 bytes 51 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.PreviousEpochAttestations, 4096) // Offset (15) - PreviousEpochAttestations - 4 bytes 52 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &obj.CurrentEpochAttestations, 4096) // Offset (16) - CurrentEpochAttestations - 4 bytes 53 | ssz.DefineArrayOfBits(codec, &obj.JustificationBits, 4) // Field (17) - JustificationBits - 1 bytes 54 | ssz.DefineStaticObject(codec, &obj.PreviousJustifiedCheckpoint) // Field (18) - PreviousJustifiedCheckpoint - ? bytes (Checkpoint) 55 | ssz.DefineStaticObject(codec, &obj.CurrentJustifiedCheckpoint) // Field (19) - CurrentJustifiedCheckpoint - ? bytes (Checkpoint) 56 | ssz.DefineStaticObject(codec, &obj.FinalizedCheckpoint) // Field (20) - FinalizedCheckpoint - ? bytes (Checkpoint) 57 | 58 | // Define the dynamic data (fields) 59 | ssz.DefineSliceOfStaticBytesContent(codec, &obj.HistoricalRoots, 16777216) // Field ( 7) - HistoricalRoots - ? bytes 60 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Eth1DataVotes, 2048) // Field ( 9) - Eth1DataVotes - ? bytes 61 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Validators, 1099511627776) // Field (11) - Validators - ? bytes 62 | ssz.DefineSliceOfUint64sContent(codec, &obj.Balances, 1099511627776) // Field (12) - Balances - ? bytes 63 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.PreviousEpochAttestations, 4096) // Field (15) - PreviousEpochAttestations - ? bytes 64 | ssz.DefineSliceOfDynamicObjectsContent(codec, &obj.CurrentEpochAttestations, 4096) // Field (16) - CurrentEpochAttestations - ? bytes 65 | } 66 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_state_altair_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconStateAltair = ssz.PrecomputeStaticSizeCache((*BeaconStateAltair)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconStateAltair) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconStateAltair) { 15 | size = staticSizeCacheBeaconStateAltair[fork] 16 | } else { 17 | size = 8 + 32 + 8 + (*Fork)(nil).SizeSSZ(sizer) + (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 8192*32 + 8192*32 + 4 + (*Eth1Data)(nil).SizeSSZ(sizer) + 4 + 8 + 4 + 4 + 65536*32 + 8192*8 + 4 + 4 + 1 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + 4 + (*SyncCommittee)(nil).SizeSSZ(sizer) + (*SyncCommittee)(nil).SizeSSZ(sizer) 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticBytes(sizer, obj.HistoricalRoots) 24 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Eth1DataVotes) 25 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Validators) 26 | size += ssz.SizeSliceOfUint64s(sizer, obj.Balances) 27 | size += ssz.SizeDynamicBytes(sizer, obj.PreviousEpochParticipation) 28 | size += ssz.SizeDynamicBytes(sizer, obj.CurrentEpochParticipation) 29 | size += ssz.SizeSliceOfUint64s(sizer, obj.InactivityScores) 30 | 31 | return size 32 | } 33 | 34 | // DefineSSZ defines how an object is encoded/decoded. 35 | func (obj *BeaconStateAltair) DefineSSZ(codec *ssz.Codec) { 36 | // Define the static data (fields and dynamic offsets) 37 | ssz.DefineUint64(codec, &obj.GenesisTime) // Field ( 0) - GenesisTime - 8 bytes 38 | ssz.DefineCheckedStaticBytes(codec, &obj.GenesisValidatorsRoot, 32) // Field ( 1) - GenesisValidatorsRoot - 32 bytes 39 | ssz.DefineUint64(codec, &obj.Slot) // Field ( 2) - Slot - 8 bytes 40 | ssz.DefineStaticObject(codec, &obj.Fork) // Field ( 3) - Fork - ? bytes (Fork) 41 | ssz.DefineStaticObject(codec, &obj.LatestBlockHeader) // Field ( 4) - LatestBlockHeader - ? bytes (BeaconBlockHeader) 42 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field ( 5) - BlockRoots - 262144 bytes 43 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.StateRoots[:]) // Field ( 6) - StateRoots - 262144 bytes 44 | ssz.DefineSliceOfStaticBytesOffset(codec, &obj.HistoricalRoots, 16777216) // Offset ( 7) - HistoricalRoots - 4 bytes 45 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 8) - Eth1Data - ? bytes (Eth1Data) 46 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Eth1DataVotes, 2048) // Offset ( 9) - Eth1DataVotes - 4 bytes 47 | ssz.DefineUint64(codec, &obj.Eth1DepositIndex) // Field (10) - Eth1DepositIndex - 8 bytes 48 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Validators, 1099511627776) // Offset (11) - Validators - 4 bytes 49 | ssz.DefineSliceOfUint64sOffset(codec, &obj.Balances, 1099511627776) // Offset (12) - Balances - 4 bytes 50 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.RandaoMixes[:]) // Field (13) - RandaoMixes - 2097152 bytes 51 | ssz.DefineArrayOfUint64s(codec, &obj.Slashings) // Field (14) - Slashings - 65536 bytes 52 | ssz.DefineDynamicBytesOffset(codec, &obj.PreviousEpochParticipation, 1099511627776) // Offset (15) - PreviousEpochParticipation - 4 bytes 53 | ssz.DefineDynamicBytesOffset(codec, &obj.CurrentEpochParticipation, 1099511627776) // Offset (16) - CurrentEpochParticipation - 4 bytes 54 | ssz.DefineArrayOfBits(codec, &obj.JustificationBits, 4) // Field (17) - JustificationBits - 1 bytes 55 | ssz.DefineStaticObject(codec, &obj.PreviousJustifiedCheckpoint) // Field (18) - PreviousJustifiedCheckpoint - ? bytes (Checkpoint) 56 | ssz.DefineStaticObject(codec, &obj.CurrentJustifiedCheckpoint) // Field (19) - CurrentJustifiedCheckpoint - ? bytes (Checkpoint) 57 | ssz.DefineStaticObject(codec, &obj.FinalizedCheckpoint) // Field (20) - FinalizedCheckpoint - ? bytes (Checkpoint) 58 | ssz.DefineSliceOfUint64sOffset(codec, &obj.InactivityScores, 1099511627776) // Offset (21) - InactivityScores - 4 bytes 59 | ssz.DefineStaticObject(codec, &obj.CurrentSyncCommittee) // Field (22) - CurrentSyncCommittee - ? bytes (SyncCommittee) 60 | ssz.DefineStaticObject(codec, &obj.NextSyncCommittee) // Field (23) - NextSyncCommittee - ? bytes (SyncCommittee) 61 | 62 | // Define the dynamic data (fields) 63 | ssz.DefineSliceOfStaticBytesContent(codec, &obj.HistoricalRoots, 16777216) // Field ( 7) - HistoricalRoots - ? bytes 64 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Eth1DataVotes, 2048) // Field ( 9) - Eth1DataVotes - ? bytes 65 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Validators, 1099511627776) // Field (11) - Validators - ? bytes 66 | ssz.DefineSliceOfUint64sContent(codec, &obj.Balances, 1099511627776) // Field (12) - Balances - ? bytes 67 | ssz.DefineDynamicBytesContent(codec, &obj.PreviousEpochParticipation, 1099511627776) // Field (15) - PreviousEpochParticipation - ? bytes 68 | ssz.DefineDynamicBytesContent(codec, &obj.CurrentEpochParticipation, 1099511627776) // Field (16) - CurrentEpochParticipation - ? bytes 69 | ssz.DefineSliceOfUint64sContent(codec, &obj.InactivityScores, 1099511627776) // Field (21) - InactivityScores - ? bytes 70 | } 71 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_state_bellatrix_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconStateBellatrix = ssz.PrecomputeStaticSizeCache((*BeaconStateBellatrix)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconStateBellatrix) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconStateBellatrix) { 15 | size = staticSizeCacheBeaconStateBellatrix[fork] 16 | } else { 17 | size = 8 + 32 + 8 + (*Fork)(nil).SizeSSZ(sizer) + (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 8192*32 + 8192*32 + 4 + (*Eth1Data)(nil).SizeSSZ(sizer) + 4 + 8 + 4 + 4 + 65536*32 + 8192*8 + 4 + 4 + 1 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + 4 + (*SyncCommittee)(nil).SizeSSZ(sizer) + (*SyncCommittee)(nil).SizeSSZ(sizer) + 4 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticBytes(sizer, obj.HistoricalRoots) 24 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Eth1DataVotes) 25 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Validators) 26 | size += ssz.SizeSliceOfUint64s(sizer, obj.Balances) 27 | size += ssz.SizeDynamicBytes(sizer, obj.PreviousEpochParticipation) 28 | size += ssz.SizeDynamicBytes(sizer, obj.CurrentEpochParticipation) 29 | size += ssz.SizeSliceOfUint64s(sizer, obj.InactivityScores) 30 | size += ssz.SizeDynamicObject(sizer, obj.LatestExecutionPayloadHeader) 31 | 32 | return size 33 | } 34 | 35 | // DefineSSZ defines how an object is encoded/decoded. 36 | func (obj *BeaconStateBellatrix) DefineSSZ(codec *ssz.Codec) { 37 | // Define the static data (fields and dynamic offsets) 38 | ssz.DefineUint64(codec, &obj.GenesisTime) // Field ( 0) - GenesisTime - 8 bytes 39 | ssz.DefineStaticBytes(codec, &obj.GenesisValidatorsRoot) // Field ( 1) - GenesisValidatorsRoot - 32 bytes 40 | ssz.DefineUint64(codec, &obj.Slot) // Field ( 2) - Slot - 8 bytes 41 | ssz.DefineStaticObject(codec, &obj.Fork) // Field ( 3) - Fork - ? bytes (Fork) 42 | ssz.DefineStaticObject(codec, &obj.LatestBlockHeader) // Field ( 4) - LatestBlockHeader - ? bytes (BeaconBlockHeader) 43 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field ( 5) - BlockRoots - 262144 bytes 44 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.StateRoots[:]) // Field ( 6) - StateRoots - 262144 bytes 45 | ssz.DefineSliceOfStaticBytesOffset(codec, &obj.HistoricalRoots, 16777216) // Offset ( 7) - HistoricalRoots - 4 bytes 46 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 8) - Eth1Data - ? bytes (Eth1Data) 47 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Eth1DataVotes, 2048) // Offset ( 9) - Eth1DataVotes - 4 bytes 48 | ssz.DefineUint64(codec, &obj.Eth1DepositIndex) // Field (10) - Eth1DepositIndex - 8 bytes 49 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Validators, 1099511627776) // Offset (11) - Validators - 4 bytes 50 | ssz.DefineSliceOfUint64sOffset(codec, &obj.Balances, 1099511627776) // Offset (12) - Balances - 4 bytes 51 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.RandaoMixes[:]) // Field (13) - RandaoMixes - 2097152 bytes 52 | ssz.DefineArrayOfUint64s(codec, &obj.Slashings) // Field (14) - Slashings - 65536 bytes 53 | ssz.DefineDynamicBytesOffset(codec, &obj.PreviousEpochParticipation, 1099511627776) // Offset (15) - PreviousEpochParticipation - 4 bytes 54 | ssz.DefineDynamicBytesOffset(codec, &obj.CurrentEpochParticipation, 1099511627776) // Offset (16) - CurrentEpochParticipation - 4 bytes 55 | ssz.DefineArrayOfBits(codec, &obj.JustificationBits, 4) // Field (17) - JustificationBits - 1 bytes 56 | ssz.DefineStaticObject(codec, &obj.PreviousJustifiedCheckpoint) // Field (18) - PreviousJustifiedCheckpoint - ? bytes (Checkpoint) 57 | ssz.DefineStaticObject(codec, &obj.CurrentJustifiedCheckpoint) // Field (19) - CurrentJustifiedCheckpoint - ? bytes (Checkpoint) 58 | ssz.DefineStaticObject(codec, &obj.FinalizedCheckpoint) // Field (20) - FinalizedCheckpoint - ? bytes (Checkpoint) 59 | ssz.DefineSliceOfUint64sOffset(codec, &obj.InactivityScores, 1099511627776) // Offset (21) - InactivityScores - 4 bytes 60 | ssz.DefineStaticObject(codec, &obj.CurrentSyncCommittee) // Field (22) - CurrentSyncCommittee - ? bytes (SyncCommittee) 61 | ssz.DefineStaticObject(codec, &obj.NextSyncCommittee) // Field (23) - NextSyncCommittee - ? bytes (SyncCommittee) 62 | ssz.DefineDynamicObjectOffset(codec, &obj.LatestExecutionPayloadHeader) // Offset (24) - LatestExecutionPayloadHeader - 4 bytes 63 | 64 | // Define the dynamic data (fields) 65 | ssz.DefineSliceOfStaticBytesContent(codec, &obj.HistoricalRoots, 16777216) // Field ( 7) - HistoricalRoots - ? bytes 66 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Eth1DataVotes, 2048) // Field ( 9) - Eth1DataVotes - ? bytes 67 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Validators, 1099511627776) // Field (11) - Validators - ? bytes 68 | ssz.DefineSliceOfUint64sContent(codec, &obj.Balances, 1099511627776) // Field (12) - Balances - ? bytes 69 | ssz.DefineDynamicBytesContent(codec, &obj.PreviousEpochParticipation, 1099511627776) // Field (15) - PreviousEpochParticipation - ? bytes 70 | ssz.DefineDynamicBytesContent(codec, &obj.CurrentEpochParticipation, 1099511627776) // Field (16) - CurrentEpochParticipation - ? bytes 71 | ssz.DefineSliceOfUint64sContent(codec, &obj.InactivityScores, 1099511627776) // Field (21) - InactivityScores - ? bytes 72 | ssz.DefineDynamicObjectContent(codec, &obj.LatestExecutionPayloadHeader) // Field (24) - LatestExecutionPayloadHeader - ? bytes 73 | } 74 | -------------------------------------------------------------------------------- /tests/corner_cases_test.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package tests 6 | 7 | import ( 8 | "bytes" 9 | "encoding/hex" 10 | "errors" 11 | "io" 12 | "testing" 13 | 14 | "github.com/karalabe/ssz" 15 | types "github.com/karalabe/ssz/tests/testtypes/consensus-spec-tests" 16 | ) 17 | 18 | // Tests that decoding less or more data than requested will result in a failure. 19 | func TestDecodeMissized(t *testing.T) { 20 | obj := new(testMissizedType) 21 | 22 | blob := make([]byte, ssz.Size(obj)+1) 23 | if err := ssz.DecodeFromBytes(blob, obj); !errors.Is(err, ssz.ErrObjectSlotSizeMismatch) { 24 | t.Errorf("decode from bytes error mismatch: have %v, want %v", err, ssz.ErrObjectSlotSizeMismatch) 25 | } 26 | if err := ssz.DecodeFromStream(bytes.NewReader(blob), obj, uint32(len(blob))); !errors.Is(err, ssz.ErrObjectSlotSizeMismatch) { 27 | t.Errorf("decode from stream error mismatch: have %v, want %v", err, ssz.ErrObjectSlotSizeMismatch) 28 | } 29 | 30 | blob = make([]byte, ssz.Size(obj)-1) 31 | if err := ssz.DecodeFromBytes(blob, obj); !errors.Is(err, io.ErrUnexpectedEOF) { 32 | t.Errorf("decode from bytes error mismatch: have %v, want %v", err, io.ErrUnexpectedEOF) 33 | } 34 | if err := ssz.DecodeFromStream(bytes.NewReader(blob), obj, uint32(len(blob))); !errors.Is(err, io.ErrUnexpectedEOF) { 35 | t.Errorf("decode from stream error mismatch: have %v, want %v", err, io.ErrUnexpectedEOF) 36 | } 37 | } 38 | 39 | type testMissizedType struct { 40 | A, B uint64 41 | } 42 | 43 | func (t *testMissizedType) SizeSSZ(sizer *ssz.Sizer) uint32 { return 16 } 44 | func (t *testMissizedType) DefineSSZ(codec *ssz.Codec) { 45 | ssz.DefineUint64(codec, &t.A) 46 | ssz.DefineUint64(codec, &t.B) 47 | } 48 | 49 | // Tests that encoding more data than available space will result in a failure. 50 | func TestEncodeOversized(t *testing.T) { 51 | obj := new(testMissizedType) 52 | 53 | blob := make([]byte, ssz.Size(obj)-1) 54 | if err := ssz.EncodeToBytes(blob, obj); !errors.Is(err, ssz.ErrBufferTooSmall) { 55 | t.Errorf("encode to bytes error mismatch: have %v, want %v", err, ssz.ErrBufferTooSmall) 56 | } 57 | if err := ssz.EncodeToStream(&testEncodeOversizedStream{blob}, obj); err == nil { 58 | t.Errorf("encode to stream error mismatch: have nil, want stream full") // wonky, but should be fine 59 | } 60 | } 61 | 62 | type testEncodeOversizedStream struct { 63 | sink []byte 64 | } 65 | 66 | func (s *testEncodeOversizedStream) Write(p []byte) (n int, err error) { 67 | // Keep writing until space runs out, then reject it 68 | copy(s.sink, p) 69 | 70 | n = len(p) 71 | if len(s.sink) < len(p) { 72 | n = len(s.sink) 73 | } 74 | s.sink = s.sink[n:] 75 | if n < len(p) { 76 | err = errors.New("stream full") 77 | } 78 | return n, err 79 | } 80 | 81 | // Tests that decoding an empty dynamic list via a non-empty container with an 82 | // empty counter offset is rejected. 83 | func TestZeroCounterOffset(t *testing.T) { 84 | inSSZ, err := hex.DecodeString("30303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030fc01000030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030fe010000303000000000") 85 | if err != nil { 86 | panic(err) 87 | } 88 | err = ssz.DecodeFromBytes(inSSZ, new(types.ExecutionPayload)) 89 | if !errors.Is(err, ssz.ErrZeroCounterOffset) { 90 | t.Errorf("decode error mismatch: have %v, want %v", err, ssz.ErrZeroCounterOffset) 91 | } 92 | } 93 | 94 | // Tests that decoding a boolean with an invalid encoding is rejected. 95 | func TestInvalidBoolean(t *testing.T) { 96 | inSSZ, err := hex.DecodeString("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000") 97 | if err != nil { 98 | panic(err) 99 | } 100 | err = ssz.DecodeFromBytes(inSSZ, new(types.Validator)) 101 | if !errors.Is(err, ssz.ErrInvalidBoolean) { 102 | t.Errorf("decode error mismatch: have %v, want %v", err, ssz.ErrInvalidBoolean) 103 | } 104 | } 105 | 106 | // Tests that decoding empty slices will init them instead of leaving as nil. 107 | func TestEmptySliceInit(t *testing.T) { 108 | obj := new(testEmptySlicesType) 109 | buf := new(bytes.Buffer) 110 | 111 | if err := ssz.EncodeToStream(buf, obj); err != nil { 112 | panic(err) 113 | } 114 | if err := ssz.DecodeFromBytes(buf.Bytes(), obj); err != nil { 115 | panic(err) 116 | } 117 | if obj.A == nil { 118 | t.Errorf("failed to init empty uint64 slice") 119 | } 120 | if obj.B == nil { 121 | t.Errorf("failed to init empty statc bytes slice") 122 | } 123 | if obj.C == nil { 124 | t.Errorf("failed to init empty dynamic bytes slice") 125 | } 126 | if obj.D == nil { 127 | t.Errorf("failed to init empty static objects slice") 128 | } 129 | if obj.E == nil { 130 | t.Errorf("failed to init empty dynamic objects slice") 131 | } 132 | } 133 | 134 | type testEmptySlicesType struct { 135 | A []uint64 // Slice of uint64 136 | B [][32]byte // Slice of static bytes 137 | C [][]byte // Slice of dynamic bytes 138 | D []*types.Withdrawal // Slice of static objects 139 | E []*types.ExecutionPayload // Slice of dynamic objects 140 | } 141 | 142 | func (t *testEmptySlicesType) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 143 | size = 5 * 4 144 | if fixed { 145 | return size 146 | } 147 | size += ssz.SizeSliceOfUint64s(sizer, t.A) 148 | size += ssz.SizeSliceOfStaticBytes(sizer, t.B) 149 | size += ssz.SizeSliceOfDynamicBytes(sizer, t.C) 150 | size += ssz.SizeSliceOfStaticObjects(sizer, t.D) 151 | size += ssz.SizeSliceOfDynamicObjects(sizer, t.E) 152 | 153 | return size 154 | } 155 | func (t *testEmptySlicesType) DefineSSZ(codec *ssz.Codec) { 156 | ssz.DefineSliceOfUint64sOffset(codec, &t.A, 16) 157 | ssz.DefineSliceOfStaticBytesOffset(codec, &t.B, 16) 158 | ssz.DefineSliceOfDynamicBytesOffset(codec, &t.C, 16, 16) 159 | ssz.DefineSliceOfStaticObjectsOffset(codec, &t.D, 16) 160 | ssz.DefineSliceOfDynamicObjectsOffset(codec, &t.E, 16) 161 | 162 | ssz.DefineSliceOfUint64sContent(codec, &t.A, 16) 163 | ssz.DefineSliceOfStaticBytesContent(codec, &t.B, 16) 164 | ssz.DefineSliceOfDynamicBytesContent(codec, &t.C, 16, 16) 165 | ssz.DefineSliceOfStaticObjectsContent(codec, &t.D, 16) 166 | ssz.DefineSliceOfDynamicObjectsContent(codec, &t.E, 16) 167 | } 168 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_state_deneb_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconStateDeneb = ssz.PrecomputeStaticSizeCache((*BeaconStateDeneb)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconStateDeneb) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconStateDeneb) { 15 | size = staticSizeCacheBeaconStateDeneb[fork] 16 | } else { 17 | size = 8 + 32 + 8 + (*Fork)(nil).SizeSSZ(sizer) + (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 8192*32 + 8192*32 + 4 + (*Eth1Data)(nil).SizeSSZ(sizer) + 4 + 8 + 4 + 4 + 65536*32 + 8192*8 + 4 + 4 + 1 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + 4 + (*SyncCommittee)(nil).SizeSSZ(sizer) + (*SyncCommittee)(nil).SizeSSZ(sizer) + 4 + 8 + 8 + 4 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticBytes(sizer, obj.HistoricalRoots) 24 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Eth1DataVotes) 25 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Validators) 26 | size += ssz.SizeSliceOfUint64s(sizer, obj.Balances) 27 | size += ssz.SizeDynamicBytes(sizer, obj.PreviousEpochParticipation) 28 | size += ssz.SizeDynamicBytes(sizer, obj.CurrentEpochParticipation) 29 | size += ssz.SizeSliceOfUint64s(sizer, obj.InactivityScores) 30 | size += ssz.SizeDynamicObject(sizer, obj.LatestExecutionPayloadHeader) 31 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.HistoricalSummaries) 32 | 33 | return size 34 | } 35 | 36 | // DefineSSZ defines how an object is encoded/decoded. 37 | func (obj *BeaconStateDeneb) DefineSSZ(codec *ssz.Codec) { 38 | // Define the static data (fields and dynamic offsets) 39 | ssz.DefineUint64(codec, &obj.GenesisTime) // Field ( 0) - GenesisTime - 8 bytes 40 | ssz.DefineStaticBytes(codec, &obj.GenesisValidatorsRoot) // Field ( 1) - GenesisValidatorsRoot - 32 bytes 41 | ssz.DefineUint64(codec, &obj.Slot) // Field ( 2) - Slot - 8 bytes 42 | ssz.DefineStaticObject(codec, &obj.Fork) // Field ( 3) - Fork - ? bytes (Fork) 43 | ssz.DefineStaticObject(codec, &obj.LatestBlockHeader) // Field ( 4) - LatestBlockHeader - ? bytes (BeaconBlockHeader) 44 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field ( 5) - BlockRoots - 262144 bytes 45 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.StateRoots[:]) // Field ( 6) - StateRoots - 262144 bytes 46 | ssz.DefineSliceOfStaticBytesOffset(codec, &obj.HistoricalRoots, 16777216) // Offset ( 7) - HistoricalRoots - 4 bytes 47 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 8) - Eth1Data - ? bytes (Eth1Data) 48 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Eth1DataVotes, 2048) // Offset ( 9) - Eth1DataVotes - 4 bytes 49 | ssz.DefineUint64(codec, &obj.Eth1DepositIndex) // Field (10) - Eth1DepositIndex - 8 bytes 50 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Validators, 1099511627776) // Offset (11) - Validators - 4 bytes 51 | ssz.DefineSliceOfUint64sOffset(codec, &obj.Balances, 1099511627776) // Offset (12) - Balances - 4 bytes 52 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.RandaoMixes[:]) // Field (13) - RandaoMixes - 2097152 bytes 53 | ssz.DefineArrayOfUint64s(codec, &obj.Slashings) // Field (14) - Slashings - 65536 bytes 54 | ssz.DefineDynamicBytesOffset(codec, &obj.PreviousEpochParticipation, 1099511627776) // Offset (15) - PreviousEpochParticipation - 4 bytes 55 | ssz.DefineDynamicBytesOffset(codec, &obj.CurrentEpochParticipation, 1099511627776) // Offset (16) - CurrentEpochParticipation - 4 bytes 56 | ssz.DefineArrayOfBits(codec, &obj.JustificationBits, 4) // Field (17) - JustificationBits - 1 bytes 57 | ssz.DefineStaticObject(codec, &obj.PreviousJustifiedCheckpoint) // Field (18) - PreviousJustifiedCheckpoint - ? bytes (Checkpoint) 58 | ssz.DefineStaticObject(codec, &obj.CurrentJustifiedCheckpoint) // Field (19) - CurrentJustifiedCheckpoint - ? bytes (Checkpoint) 59 | ssz.DefineStaticObject(codec, &obj.FinalizedCheckpoint) // Field (20) - FinalizedCheckpoint - ? bytes (Checkpoint) 60 | ssz.DefineSliceOfUint64sOffset(codec, &obj.InactivityScores, 1099511627776) // Offset (21) - InactivityScores - 4 bytes 61 | ssz.DefineStaticObject(codec, &obj.CurrentSyncCommittee) // Field (22) - CurrentSyncCommittee - ? bytes (SyncCommittee) 62 | ssz.DefineStaticObject(codec, &obj.NextSyncCommittee) // Field (23) - NextSyncCommittee - ? bytes (SyncCommittee) 63 | ssz.DefineDynamicObjectOffset(codec, &obj.LatestExecutionPayloadHeader) // Offset (24) - LatestExecutionPayloadHeader - 4 bytes 64 | ssz.DefineUint64(codec, &obj.NextWithdrawalIndex) // Field (25) - NextWithdrawalIndex - 8 bytes 65 | ssz.DefineUint64(codec, &obj.NextWithdrawalValidatorIndex) // Field (26) - NextWithdrawalValidatorIndex - 8 bytes 66 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.HistoricalSummaries, 16777216) // Offset (27) - HistoricalSummaries - 4 bytes 67 | 68 | // Define the dynamic data (fields) 69 | ssz.DefineSliceOfStaticBytesContent(codec, &obj.HistoricalRoots, 16777216) // Field ( 7) - HistoricalRoots - ? bytes 70 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Eth1DataVotes, 2048) // Field ( 9) - Eth1DataVotes - ? bytes 71 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Validators, 1099511627776) // Field (11) - Validators - ? bytes 72 | ssz.DefineSliceOfUint64sContent(codec, &obj.Balances, 1099511627776) // Field (12) - Balances - ? bytes 73 | ssz.DefineDynamicBytesContent(codec, &obj.PreviousEpochParticipation, 1099511627776) // Field (15) - PreviousEpochParticipation - ? bytes 74 | ssz.DefineDynamicBytesContent(codec, &obj.CurrentEpochParticipation, 1099511627776) // Field (16) - CurrentEpochParticipation - ? bytes 75 | ssz.DefineSliceOfUint64sContent(codec, &obj.InactivityScores, 1099511627776) // Field (21) - InactivityScores - ? bytes 76 | ssz.DefineDynamicObjectContent(codec, &obj.LatestExecutionPayloadHeader) // Field (24) - LatestExecutionPayloadHeader - ? bytes 77 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.HistoricalSummaries, 16777216) // Field (27) - HistoricalSummaries - ? bytes 78 | } 79 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/gen_beacon_state_capella_ssz.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/karalabe/ssz. DO NOT EDIT. 2 | 3 | package consensus_spec_tests 4 | 5 | import "github.com/karalabe/ssz" 6 | 7 | // Cached static size computed on package init. 8 | var staticSizeCacheBeaconStateCapella = ssz.PrecomputeStaticSizeCache((*BeaconStateCapella)(nil)) 9 | 10 | // SizeSSZ returns either the static size of the object if fixed == true, or 11 | // the total size otherwise. 12 | func (obj *BeaconStateCapella) SizeSSZ(sizer *ssz.Sizer, fixed bool) (size uint32) { 13 | // Load static size if already precomputed, calculate otherwise 14 | if fork := int(sizer.Fork()); fork < len(staticSizeCacheBeaconStateCapella) { 15 | size = staticSizeCacheBeaconStateCapella[fork] 16 | } else { 17 | size = 8 + 32 + 8 + (*Fork)(nil).SizeSSZ(sizer) + (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 8192*32 + 8192*32 + 4 + (*Eth1Data)(nil).SizeSSZ(sizer) + 4 + 8 + 4 + 4 + 65536*32 + 8192*8 + 4 + 4 + 1 + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + (*Checkpoint)(nil).SizeSSZ(sizer) + 4 + (*SyncCommittee)(nil).SizeSSZ(sizer) + (*SyncCommittee)(nil).SizeSSZ(sizer) + 4 + 8 + 8 + 4 18 | } 19 | // Either return the static size or accumulate the dynamic too 20 | if fixed { 21 | return size 22 | } 23 | size += ssz.SizeSliceOfStaticBytes(sizer, obj.HistoricalRoots) 24 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Eth1DataVotes) 25 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.Validators) 26 | size += ssz.SizeSliceOfUint64s(sizer, obj.Balances) 27 | size += ssz.SizeDynamicBytes(sizer, obj.PreviousEpochParticipation) 28 | size += ssz.SizeDynamicBytes(sizer, obj.CurrentEpochParticipation) 29 | size += ssz.SizeSliceOfUint64s(sizer, obj.InactivityScores) 30 | size += ssz.SizeDynamicObject(sizer, obj.LatestExecutionPayloadHeader) 31 | size += ssz.SizeSliceOfStaticObjects(sizer, obj.HistoricalSummaries) 32 | 33 | return size 34 | } 35 | 36 | // DefineSSZ defines how an object is encoded/decoded. 37 | func (obj *BeaconStateCapella) DefineSSZ(codec *ssz.Codec) { 38 | // Define the static data (fields and dynamic offsets) 39 | ssz.DefineUint64(codec, &obj.GenesisTime) // Field ( 0) - GenesisTime - 8 bytes 40 | ssz.DefineStaticBytes(codec, &obj.GenesisValidatorsRoot) // Field ( 1) - GenesisValidatorsRoot - 32 bytes 41 | ssz.DefineUint64(codec, &obj.Slot) // Field ( 2) - Slot - 8 bytes 42 | ssz.DefineStaticObject(codec, &obj.Fork) // Field ( 3) - Fork - ? bytes (Fork) 43 | ssz.DefineStaticObject(codec, &obj.LatestBlockHeader) // Field ( 4) - LatestBlockHeader - ? bytes (BeaconBlockHeader) 44 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.BlockRoots[:]) // Field ( 5) - BlockRoots - 262144 bytes 45 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.StateRoots[:]) // Field ( 6) - StateRoots - 262144 bytes 46 | ssz.DefineSliceOfStaticBytesOffset(codec, &obj.HistoricalRoots, 16777216) // Offset ( 7) - HistoricalRoots - 4 bytes 47 | ssz.DefineStaticObject(codec, &obj.Eth1Data) // Field ( 8) - Eth1Data - ? bytes (Eth1Data) 48 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Eth1DataVotes, 2048) // Offset ( 9) - Eth1DataVotes - 4 bytes 49 | ssz.DefineUint64(codec, &obj.Eth1DepositIndex) // Field (10) - Eth1DepositIndex - 8 bytes 50 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.Validators, 1099511627776) // Offset (11) - Validators - 4 bytes 51 | ssz.DefineSliceOfUint64sOffset(codec, &obj.Balances, 1099511627776) // Offset (12) - Balances - 4 bytes 52 | ssz.DefineUnsafeArrayOfStaticBytes(codec, obj.RandaoMixes[:]) // Field (13) - RandaoMixes - 2097152 bytes 53 | ssz.DefineArrayOfUint64s(codec, &obj.Slashings) // Field (14) - Slashings - 65536 bytes 54 | ssz.DefineDynamicBytesOffset(codec, &obj.PreviousEpochParticipation, 1099511627776) // Offset (15) - PreviousEpochParticipation - 4 bytes 55 | ssz.DefineDynamicBytesOffset(codec, &obj.CurrentEpochParticipation, 1099511627776) // Offset (16) - CurrentEpochParticipation - 4 bytes 56 | ssz.DefineArrayOfBits(codec, &obj.JustificationBits, 4) // Field (17) - JustificationBits - 1 bytes 57 | ssz.DefineStaticObject(codec, &obj.PreviousJustifiedCheckpoint) // Field (18) - PreviousJustifiedCheckpoint - ? bytes (Checkpoint) 58 | ssz.DefineStaticObject(codec, &obj.CurrentJustifiedCheckpoint) // Field (19) - CurrentJustifiedCheckpoint - ? bytes (Checkpoint) 59 | ssz.DefineStaticObject(codec, &obj.FinalizedCheckpoint) // Field (20) - FinalizedCheckpoint - ? bytes (Checkpoint) 60 | ssz.DefineSliceOfUint64sOffset(codec, &obj.InactivityScores, 1099511627776) // Offset (21) - InactivityScores - 4 bytes 61 | ssz.DefineStaticObject(codec, &obj.CurrentSyncCommittee) // Field (22) - CurrentSyncCommittee - ? bytes (SyncCommittee) 62 | ssz.DefineStaticObject(codec, &obj.NextSyncCommittee) // Field (23) - NextSyncCommittee - ? bytes (SyncCommittee) 63 | ssz.DefineDynamicObjectOffset(codec, &obj.LatestExecutionPayloadHeader) // Offset (24) - LatestExecutionPayloadHeader - 4 bytes 64 | ssz.DefineUint64(codec, &obj.NextWithdrawalIndex) // Field (25) - NextWithdrawalIndex - 8 bytes 65 | ssz.DefineUint64(codec, &obj.NextWithdrawalValidatorIndex) // Field (26) - NextWithdrawalValidatorIndex - 8 bytes 66 | ssz.DefineSliceOfStaticObjectsOffset(codec, &obj.HistoricalSummaries, 16777216) // Offset (27) - HistoricalSummaries - 4 bytes 67 | 68 | // Define the dynamic data (fields) 69 | ssz.DefineSliceOfStaticBytesContent(codec, &obj.HistoricalRoots, 16777216) // Field ( 7) - HistoricalRoots - ? bytes 70 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Eth1DataVotes, 2048) // Field ( 9) - Eth1DataVotes - ? bytes 71 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.Validators, 1099511627776) // Field (11) - Validators - ? bytes 72 | ssz.DefineSliceOfUint64sContent(codec, &obj.Balances, 1099511627776) // Field (12) - Balances - ? bytes 73 | ssz.DefineDynamicBytesContent(codec, &obj.PreviousEpochParticipation, 1099511627776) // Field (15) - PreviousEpochParticipation - ? bytes 74 | ssz.DefineDynamicBytesContent(codec, &obj.CurrentEpochParticipation, 1099511627776) // Field (16) - CurrentEpochParticipation - ? bytes 75 | ssz.DefineSliceOfUint64sContent(codec, &obj.InactivityScores, 1099511627776) // Field (21) - InactivityScores - ? bytes 76 | ssz.DefineDynamicObjectContent(codec, &obj.LatestExecutionPayloadHeader) // Field (24) - LatestExecutionPayloadHeader - ? bytes 77 | ssz.DefineSliceOfStaticObjectsContent(codec, &obj.HistoricalSummaries, 16777216) // Field (27) - HistoricalSummaries - ? bytes 78 | } 79 | -------------------------------------------------------------------------------- /tests/testtypes/consensus-spec-tests/types_monoliths.go: -------------------------------------------------------------------------------- 1 | // ssz: Go Simple Serialize (SSZ) codec library 2 | // Copyright 2024 ssz Authors 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | 5 | package consensus_spec_tests 6 | 7 | import ( 8 | "math/big" 9 | 10 | "github.com/holiman/uint256" 11 | "github.com/prysmaticlabs/go-bitfield" 12 | ) 13 | 14 | //go:generate go run -cover ../../../cmd/sszgen -type SingleFieldTestStructMonolith -out gen_single_field_test_struct_monolith_ssz.go 15 | //go:generate go run -cover ../../../cmd/sszgen -type SmallTestStructMonolith -out gen_small_test_struct_monolith_ssz.go 16 | //go:generate go run -cover ../../../cmd/sszgen -type FixedTestStructMonolith -out gen_fixed_test_struct_monolith_ssz.go 17 | //go:generate go run -cover ../../../cmd/sszgen -type BitsStructMonolith -out gen_bits_struct_monolith_ssz.go 18 | 19 | //go:generate go run -cover ../../../cmd/sszgen -type ExecutionPayloadMonolith -out gen_execution_payload_monolith_ssz.go 20 | //go:generate go run -cover ../../../cmd/sszgen -type ExecutionPayloadMonolith2 -out gen_execution_payload_monolith_2_ssz.go 21 | //go:generate go run -cover ../../../cmd/sszgen -type ExecutionPayloadHeaderMonolith -out gen_execution_payload_header_monolith_ssz.go 22 | //go:generate go run -cover ../../../cmd/sszgen -type BeaconBlockBodyMonolith -out gen_beacon_block_body_monolith_ssz.go 23 | //go:generate go run -cover ../../../cmd/sszgen -type BeaconStateMonolith -out gen_beacon_state_monolith_ssz.go 24 | //go:generate go run -cover ../../../cmd/sszgen -type ValidatorMonolith -out gen_validator_monolith_ssz.go 25 | 26 | type SingleFieldTestStructMonolith struct { 27 | A *byte `ssz-fork:"unknown"` 28 | } 29 | 30 | type SmallTestStructMonolith struct { 31 | A *uint16 `ssz-fork:"unknown"` 32 | B uint16 33 | } 34 | 35 | type FixedTestStructMonolith struct { 36 | A *uint8 `ssz-fork:"unknown"` 37 | B *uint64 `ssz-fork:"unknown"` 38 | C *uint32 `ssz-fork:"unknown"` 39 | } 40 | 41 | type BitsStructMonolith struct { 42 | A bitfield.Bitlist `ssz-max:"5" ssz-fork:"unknown"` 43 | B *[1]byte `ssz-size:"2" ssz:"bits" ssz-fork:"unknown"` 44 | C [1]byte `ssz-size:"1" ssz:"bits"` 45 | D bitfield.Bitlist `ssz-max:"6"` 46 | E [1]byte `ssz-size:"8" ssz:"bits"` 47 | } 48 | 49 | type BeaconBlockBodyMonolith struct { 50 | RandaoReveal [96]byte 51 | Eth1Data *Eth1Data 52 | Graffiti [32]byte 53 | ProposerSlashings []*ProposerSlashing `ssz-max:"16"` 54 | AttesterSlashings []*AttesterSlashing `ssz-max:"2"` 55 | Attestations []*Attestation `ssz-max:"128"` 56 | Deposits []*Deposit `ssz-max:"16"` 57 | VoluntaryExits []*SignedVoluntaryExit `ssz-max:"16"` 58 | SyncAggregate *SyncAggregate ` ssz-fork:"altair"` 59 | ExecutionPayload *ExecutionPayloadMonolith ` ssz-fork:"bellatrix"` 60 | BlsToExecutionChanges []*SignedBLSToExecutionChange `ssz-max:"16" ssz-fork:"capella"` 61 | BlobKzgCommitments [][48]byte `ssz-max:"4096" ssz-fork:"deneb"` 62 | } 63 | 64 | type BeaconStateMonolith struct { 65 | GenesisTime uint64 66 | GenesisValidatorsRoot [32]byte 67 | Slot uint64 68 | Fork *Fork 69 | LatestBlockHeader *BeaconBlockHeader 70 | BlockRoots [8192][32]byte 71 | StateRoots [8192][32]byte 72 | HistoricalRoots [][32]byte `ssz-max:"16777216"` 73 | Eth1Data *Eth1Data 74 | Eth1DataVotes []*Eth1Data `ssz-max:"2048"` 75 | Eth1DepositIndex uint64 76 | Validators []*Validator `ssz-max:"1099511627776"` 77 | Balances []uint64 `ssz-max:"1099511627776"` 78 | RandaoMixes [65536][32]byte 79 | Slashings *[8192]uint64 `ssz-fork:"unknown"` 80 | PreviousEpochAttestations []*PendingAttestation `ssz-max:"4096" ssz-fork:"!altair"` 81 | CurrentEpochAttestations []*PendingAttestation `ssz-max:"4096" ssz-fork:"!altair"` 82 | PreviousEpochParticipation []byte `ssz-max:"1099511627776" ssz-fork:"altair"` 83 | CurrentEpochParticipation []byte `ssz-max:"1099511627776" ssz-fork:"altair"` 84 | JustificationBits [1]byte `ssz-size:"4" ssz:"bits"` 85 | PreviousJustifiedCheckpoint *Checkpoint 86 | CurrentJustifiedCheckpoint *Checkpoint 87 | FinalizedCheckpoint *Checkpoint 88 | InactivityScores []uint64 `ssz-max:"1099511627776" ssz-fork:"altair"` 89 | CurrentSyncCommittee *SyncCommittee ` ssz-fork:"altair"` 90 | NextSyncCommittee *SyncCommittee ` ssz-fork:"altair"` 91 | LatestExecutionPayloadHeader *ExecutionPayloadHeaderMonolith ` ssz-fork:"bellatrix"` 92 | NextWithdrawalIndex *uint64 ` ssz-fork:"capella"` 93 | NextWithdrawalValidatorIndex *uint64 ` ssz-fork:"capella"` 94 | HistoricalSummaries []*HistoricalSummary `ssz-max:"16777216" ssz-fork:"capella"` 95 | } 96 | 97 | type ExecutionPayloadMonolith struct { 98 | ParentHash Hash 99 | FeeRecipient Address 100 | StateRoot Hash 101 | ReceiptsRoot Hash 102 | LogsBloom LogsBloom 103 | PrevRandao Hash 104 | BlockNumber uint64 105 | GasLimit uint64 106 | GasUsed uint64 107 | Timestamp uint64 108 | ExtraData []byte `ssz-max:"32" ssz-fork:"frontier"` 109 | BaseFeePerGas *uint256.Int `ssz-fork:"unknown"` 110 | BlockHash Hash 111 | Transactions [][]byte `ssz-max:"1048576,1073741824" ssz-fork:"unknown"` 112 | Withdrawals []*Withdrawal `ssz-max:"16" ssz-fork:"shanghai"` 113 | BlobGasUsed *uint64 ` ssz-fork:"cancun"` 114 | ExcessBlobGas *uint64 ` ssz-fork:"cancun"` 115 | } 116 | 117 | type ExecutionPayloadMonolith2 struct { 118 | ParentHash Hash 119 | FeeRecipient Address 120 | StateRoot Hash 121 | ReceiptsRoot Hash 122 | LogsBloom LogsBloom 123 | PrevRandao Hash 124 | BlockNumber uint64 125 | GasLimit uint64 126 | GasUsed uint64 127 | Timestamp uint64 128 | ExtraData []byte `ssz-max:"32" ssz-fork:"frontier"` 129 | BaseFeePerGas *big.Int `ssz-fork:"unknown"` 130 | BlockHash Hash 131 | Transactions [][]byte `ssz-max:"1048576,1073741824"` 132 | Withdrawals []*Withdrawal `ssz-max:"16" ssz-fork:"shanghai"` 133 | BlobGasUsed *uint64 ` ssz-fork:"cancun"` 134 | ExcessBlobGas *uint64 ` ssz-fork:"cancun"` 135 | } 136 | 137 | type ExecutionPayloadHeaderMonolith struct { 138 | ParentHash [32]byte 139 | FeeRecipient [20]byte 140 | StateRoot [32]byte 141 | ReceiptsRoot [32]byte 142 | LogsBloom [256]byte 143 | PrevRandao [32]byte 144 | BlockNumber uint64 145 | GasLimit uint64 146 | GasUsed uint64 147 | Timestamp uint64 148 | ExtraData []byte `ssz-max:"32" ssz-fork:"frontier"` 149 | BaseFeePerGas [32]byte 150 | BlockHash [32]byte 151 | TransactionsRoot [32]byte 152 | WithdrawalRoot *[32]byte `ssz-fork:"shanghai"` 153 | BlobGasUsed *uint64 `ssz-fork:"cancun"` 154 | ExcessBlobGas *uint64 `ssz-fork:"cancun"` 155 | } 156 | 157 | type ValidatorMonolith struct { 158 | Pubkey [48]byte 159 | WithdrawalCredentials [32]byte 160 | EffectiveBalance uint64 161 | Slashed *bool `ssz-fork:"unknown"` 162 | ActivationEligibilityEpoch uint64 163 | ActivationEpoch uint64 164 | ExitEpoch uint64 165 | WithdrawableEpoch uint64 166 | } 167 | --------------------------------------------------------------------------------