diff --git a/cl/beacon/handler/block_production.go b/cl/beacon/handler/block_production.go index 586412f1300..447f4e088e9 100644 --- a/cl/beacon/handler/block_production.go +++ b/cl/beacon/handler/block_production.go @@ -208,16 +208,9 @@ func (a *ApiHandler) GetEthV3ValidatorBlock( } // do state transition - if block.IsBlinded() { - if err := machine.ProcessBlindedBlock(transition.DefaultMachine, baseState, block.ToBlinded()); err != nil { - log.Warn("Failed to process blinded block", "err", err, "slot", targetSlot) - return nil, err - } - } else { - if err := machine.ProcessBlock(transition.DefaultMachine, baseState, block.ToExecution().Block); err != nil { - log.Warn("Failed to process execution block", "err", err, "slot", targetSlot) - return nil, err - } + if err := machine.ProcessBlock(transition.DefaultMachine, baseState, block.ToGeneric()); err != nil { + log.Warn("Failed to process execution block", "err", err, "slot", targetSlot) + return nil, err } block.StateRoot, err = baseState.HashSSZ() if err != nil { diff --git a/cl/cltypes/beacon_block.go b/cl/cltypes/beacon_block.go index acf01cbc830..6156c4355ba 100644 --- a/cl/cltypes/beacon_block.go +++ b/cl/cltypes/beacon_block.go @@ -48,52 +48,19 @@ const ( MaxBlobsCommittmentsPerBlock = 4096 ) +var ( + _ GenericBeaconBlock = (*BeaconBlock)(nil) + _ GenericBeaconBlock = (*DenebBeaconBlock)(nil) + + _ GenericBeaconBody = (*BeaconBody)(nil) +) + +// Definition of SignedBeaconBlock type SignedBeaconBlock struct { Signature libcommon.Bytes96 `json:"signature"` Block *BeaconBlock `json:"message"` } -type BeaconBlock struct { - Slot uint64 `json:"slot,string"` - ProposerIndex uint64 `json:"proposer_index,string"` - ParentRoot libcommon.Hash `json:"parent_root"` - StateRoot libcommon.Hash `json:"state_root"` - Body *BeaconBody `json:"body"` -} - -type BeaconBody struct { - // A byte array used for randomness in the beacon chain - RandaoReveal libcommon.Bytes96 `json:"randao_reveal"` - // Data related to the Ethereum 1.0 chain - Eth1Data *Eth1Data `json:"eth1_data"` - // A byte array used to customize validators' behavior - Graffiti libcommon.Hash `json:"graffiti"` - // A list of slashing events for validators who included invalid blocks in the chain - ProposerSlashings *solid.ListSSZ[*ProposerSlashing] `json:"proposer_slashings"` - // A list of slashing events for validators who included invalid attestations in the chain - AttesterSlashings *solid.ListSSZ[*AttesterSlashing] `json:"attester_slashings"` - // A list of attestations included in the block - Attestations *solid.ListSSZ[*solid.Attestation] `json:"attestations"` - // A list of deposits made to the Ethereum 1.0 chain - Deposits *solid.ListSSZ[*Deposit] `json:"deposits"` - // A list of validators who have voluntarily exited the beacon chain - VoluntaryExits *solid.ListSSZ[*SignedVoluntaryExit] `json:"voluntary_exits"` - // A summary of the current state of the beacon chain - SyncAggregate *SyncAggregate `json:"sync_aggregate,omitempty"` - // Data related to crosslink records and executing operations on the Ethereum 2.0 chain - ExecutionPayload *Eth1Block `json:"execution_payload,omitempty"` - // Withdrawals Diffs for Execution Layer - ExecutionChanges *solid.ListSSZ[*SignedBLSToExecutionChange] `json:"bls_to_execution_changes,omitempty"` - // The commitments for beacon chain blobs - // With a max of 4 per block - BlobKzgCommitments *solid.ListSSZ[*KZGCommitment] `json:"blob_kzg_commitments,omitempty"` - // The version of the beacon chain - Version clparams.StateVersion `json:"-"` - beaconCfg *clparams.BeaconChainConfig -} - -// Getters - func NewSignedBeaconBlock(beaconCfg *clparams.BeaconChainConfig) *SignedBeaconBlock { return &SignedBeaconBlock{Block: NewBeaconBlock(beaconCfg)} } @@ -126,6 +93,43 @@ func (s *SignedBeaconBlock) SignedBeaconBlockHeader() *SignedBeaconBlockHeader { } } +// Version returns beacon block version. +func (b *SignedBeaconBlock) Version() clparams.StateVersion { + return b.Block.Body.Version +} + +func (b *SignedBeaconBlock) EncodeSSZ(buf []byte) ([]byte, error) { + return ssz2.MarshalSSZ(buf, b.Block, b.Signature[:]) +} + +func (b *SignedBeaconBlock) EncodingSizeSSZ() int { + if b.Block == nil { + return 100 + } + return 100 + b.Block.EncodingSizeSSZ() +} + +func (b *SignedBeaconBlock) DecodeSSZ(buf []byte, s int) error { + return ssz2.UnmarshalSSZ(buf, s, b.Block, b.Signature[:]) +} + +func (b *SignedBeaconBlock) HashSSZ() ([32]byte, error) { + return merkle_tree.HashTreeRoot(b.Block, b.Signature[:]) +} + +func (b *SignedBeaconBlock) Static() bool { + return false +} + +// Definition of BeaconBlock +type BeaconBlock struct { + Slot uint64 `json:"slot,string"` + ProposerIndex uint64 `json:"proposer_index,string"` + ParentRoot libcommon.Hash `json:"parent_root"` + StateRoot libcommon.Hash `json:"state_root"` + Body *BeaconBody `json:"body"` +} + func NewBeaconBlock(beaconCfg *clparams.BeaconChainConfig) *BeaconBlock { return &BeaconBlock{Body: NewBeaconBody(beaconCfg)} } @@ -144,6 +148,86 @@ func (b *BeaconBlock) Blinded() (*BlindedBeaconBlock, error) { }, nil } +// Version returns beacon block version. +func (b *BeaconBlock) Version() clparams.StateVersion { + return b.Body.Version +} + +func (b *BeaconBlock) SetVersion(version clparams.StateVersion) { + b.Body.SetVersion(version) +} + +func (b *BeaconBlock) EncodeSSZ(buf []byte) (dst []byte, err error) { + return ssz2.MarshalSSZ(buf, b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +} + +func (b *BeaconBlock) EncodingSizeSSZ() int { + if b.Body == nil { + return 80 + } + return 80 + b.Body.EncodingSizeSSZ() +} + +func (b *BeaconBlock) DecodeSSZ(buf []byte, version int) error { + return ssz2.UnmarshalSSZ(buf, version, &b.Slot, &b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +} + +func (b *BeaconBlock) HashSSZ() ([32]byte, error) { + return merkle_tree.HashTreeRoot(b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +} + +func (*BeaconBlock) Static() bool { + return false +} + +func (b *BeaconBlock) GetSlot() uint64 { + return b.Slot +} + +func (b *BeaconBlock) GetProposerIndex() uint64 { + return b.ProposerIndex +} + +func (b *BeaconBlock) GetParentRoot() libcommon.Hash { + return b.ParentRoot +} + +func (b *BeaconBlock) GetBody() GenericBeaconBody { + return b.Body +} + +// Definition of BeaconBody +type BeaconBody struct { + // A byte array used for randomness in the beacon chain + RandaoReveal libcommon.Bytes96 `json:"randao_reveal"` + // Data related to the Ethereum 1.0 chain + Eth1Data *Eth1Data `json:"eth1_data"` + // A byte array used to customize validators' behavior + Graffiti libcommon.Hash `json:"graffiti"` + // A list of slashing events for validators who included invalid blocks in the chain + ProposerSlashings *solid.ListSSZ[*ProposerSlashing] `json:"proposer_slashings"` + // A list of slashing events for validators who included invalid attestations in the chain + AttesterSlashings *solid.ListSSZ[*AttesterSlashing] `json:"attester_slashings"` + // A list of attestations included in the block + Attestations *solid.ListSSZ[*solid.Attestation] `json:"attestations"` + // A list of deposits made to the Ethereum 1.0 chain + Deposits *solid.ListSSZ[*Deposit] `json:"deposits"` + // A list of validators who have voluntarily exited the beacon chain + VoluntaryExits *solid.ListSSZ[*SignedVoluntaryExit] `json:"voluntary_exits"` + // A summary of the current state of the beacon chain + SyncAggregate *SyncAggregate `json:"sync_aggregate,omitempty"` + // Data related to crosslink records and executing operations on the Ethereum 2.0 chain + ExecutionPayload *Eth1Block `json:"execution_payload,omitempty"` + // Withdrawals Diffs for Execution Layer + ExecutionChanges *solid.ListSSZ[*SignedBLSToExecutionChange] `json:"bls_to_execution_changes,omitempty"` + // The commitments for beacon chain blobs + // With a max of 4 per block + BlobKzgCommitments *solid.ListSSZ[*KZGCommitment] `json:"blob_kzg_commitments,omitempty"` + // The version of the beacon chain + Version clparams.StateVersion `json:"-"` + beaconCfg *clparams.BeaconChainConfig +} + func NewBeaconBody(beaconCfg *clparams.BeaconChainConfig) *BeaconBody { return &BeaconBody{ beaconCfg: beaconCfg, @@ -158,21 +242,6 @@ func NewBeaconBody(beaconCfg *clparams.BeaconChainConfig) *BeaconBody { BlobKzgCommitments: solid.NewStaticListSSZ[*KZGCommitment](MaxBlobsCommittmentsPerBlock, 48), } } - -// Version returns beacon block version. -func (b *SignedBeaconBlock) Version() clparams.StateVersion { - return b.Block.Body.Version -} - -// Version returns beacon block version. -func (b *BeaconBlock) Version() clparams.StateVersion { - return b.Body.Version -} - -func (b *BeaconBlock) SetVersion(version clparams.StateVersion) { - b.Body.SetVersion(version) -} - func (b *BeaconBody) SetVersion(version clparams.StateVersion) { b.Version = version b.ExecutionPayload.SetVersion(version) @@ -291,56 +360,9 @@ func (b *BeaconBody) getSchema(storage bool) []interface{} { return s } -func (b *BeaconBlock) EncodeSSZ(buf []byte) (dst []byte, err error) { - return ssz2.MarshalSSZ(buf, b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) -} - -func (b *BeaconBlock) EncodingSizeSSZ() int { - if b.Body == nil { - return 80 - } - return 80 + b.Body.EncodingSizeSSZ() -} - -func (b *BeaconBlock) DecodeSSZ(buf []byte, version int) error { - return ssz2.UnmarshalSSZ(buf, version, &b.Slot, &b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) -} - -func (b *BeaconBlock) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) -} - -func (b *SignedBeaconBlock) EncodeSSZ(buf []byte) ([]byte, error) { - return ssz2.MarshalSSZ(buf, b.Block, b.Signature[:]) -} - -func (b *SignedBeaconBlock) EncodingSizeSSZ() int { - if b.Block == nil { - return 100 - } - return 100 + b.Block.EncodingSizeSSZ() -} - -func (b *SignedBeaconBlock) DecodeSSZ(buf []byte, s int) error { - return ssz2.UnmarshalSSZ(buf, s, b.Block, b.Signature[:]) -} - -func (b *SignedBeaconBlock) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(b.Block, b.Signature[:]) -} - -func (b *SignedBeaconBlock) Static() bool { - return false -} - func (*BeaconBody) Static() bool { return false } - -func (*BeaconBlock) Static() bool { - return false -} - func (b *BeaconBody) ExecutionPayloadMerkleProof() ([][32]byte, error) { return merkle_tree.MerkleProof(4, 9, b.getSchema(false)...) } @@ -399,6 +421,50 @@ func (b *BeaconBody) UnmarshalJSON(buf []byte) error { return nil } +func (b *BeaconBody) GetPayloadHeader() (*Eth1Header, error) { + return b.ExecutionPayload.PayloadHeader() +} + +func (b *BeaconBody) GetRandaoReveal() libcommon.Bytes96 { + return b.RandaoReveal +} + +func (b *BeaconBody) GetEth1Data() *Eth1Data { + return b.Eth1Data +} + +func (b *BeaconBody) GetSyncAggregate() *SyncAggregate { + return b.SyncAggregate +} + +func (b *BeaconBody) GetProposerSlashings() *solid.ListSSZ[*ProposerSlashing] { + return b.ProposerSlashings +} + +func (b *BeaconBody) GetAttesterSlashings() *solid.ListSSZ[*AttesterSlashing] { + return b.AttesterSlashings +} + +func (b *BeaconBody) GetAttestations() *solid.ListSSZ[*solid.Attestation] { + return b.Attestations +} + +func (b *BeaconBody) GetDeposits() *solid.ListSSZ[*Deposit] { + return b.Deposits +} + +func (b *BeaconBody) GetVoluntaryExits() *solid.ListSSZ[*SignedVoluntaryExit] { + return b.VoluntaryExits +} + +func (b *BeaconBody) GetBlobKzgCommitments() *solid.ListSSZ[*KZGCommitment] { + return b.BlobKzgCommitments +} + +func (b *BeaconBody) GetExecutionChanges() *solid.ListSSZ[*SignedBLSToExecutionChange] { + return b.ExecutionChanges +} + type DenebBeaconBlock struct { Block *BeaconBlock `json:"block"` KZGProofs *solid.ListSSZ[*KZGProof] `json:"kzg_proofs"` @@ -436,6 +502,26 @@ func (b *DenebBeaconBlock) Static() bool { return false } +func (b *DenebBeaconBlock) Version() clparams.StateVersion { + return b.Block.Version() +} + +func (b *DenebBeaconBlock) GetSlot() uint64 { + return b.Block.GetSlot() +} + +func (b *DenebBeaconBlock) GetProposerIndex() uint64 { + return b.Block.GetProposerIndex() +} + +func (b *DenebBeaconBlock) GetParentRoot() libcommon.Hash { + return b.Block.GetParentRoot() +} + +func (b *DenebBeaconBlock) GetBody() GenericBeaconBody { + return b.Block.GetBody() +} + type DenebSignedBeaconBlock struct { SignedBlock *SignedBeaconBlock `json:"signed_block"` KZGProofs *solid.ListSSZ[*KZGProof] `json:"kzg_proofs"` diff --git a/cl/cltypes/blinded_beacon_block.go b/cl/cltypes/beacon_block_blinded.go similarity index 87% rename from cl/cltypes/blinded_beacon_block.go rename to cl/cltypes/beacon_block_blinded.go index 5cf1d8628c7..c86955f4154 100644 --- a/cl/cltypes/blinded_beacon_block.go +++ b/cl/cltypes/beacon_block_blinded.go @@ -29,52 +29,23 @@ import ( ssz2 "github.com/ledgerwatch/erigon/cl/ssz" ) +// make sure that the type implements the interface ssz2.ObjectSSZ +var ( + _ ssz2.ObjectSSZ = (*BlindedBeaconBody)(nil) + _ ssz2.ObjectSSZ = (*BlindedBeaconBlock)(nil) + _ ssz2.ObjectSSZ = (*SignedBlindedBeaconBlock)(nil) + + _ GenericBeaconBlock = (*BlindedBeaconBlock)(nil) + _ GenericBeaconBody = (*BlindedBeaconBody)(nil) +) + +// Definitions of SignedBlindedBeaconBlock +// SignedBlindedBeaconBlock contains a signature and a BlindedBeaconBlock. type SignedBlindedBeaconBlock struct { Signature libcommon.Bytes96 `json:"signature"` Block *BlindedBeaconBlock `json:"message"` } -type BlindedBeaconBlock struct { - Slot uint64 `json:"slot,string"` - ProposerIndex uint64 `json:"proposer_index,string"` - ParentRoot libcommon.Hash `json:"parent_root"` - StateRoot libcommon.Hash `json:"state_root"` - Body *BlindedBeaconBody `json:"body"` -} - -type BlindedBeaconBody struct { - // A byte array used for randomness in the beacon chain - RandaoReveal libcommon.Bytes96 `json:"randao_reveal"` - // Data related to the Ethereum 1.0 chain - Eth1Data *Eth1Data `json:"eth1_data"` - // A byte array used to customize validators' behavior - Graffiti libcommon.Hash `json:"graffiti"` - // A list of slashing events for validators who included invalid blocks in the chain - ProposerSlashings *solid.ListSSZ[*ProposerSlashing] `json:"proposer_slashings"` - // A list of slashing events for validators who included invalid attestations in the chain - AttesterSlashings *solid.ListSSZ[*AttesterSlashing] `json:"attester_slashings"` - // A list of attestations included in the block - Attestations *solid.ListSSZ[*solid.Attestation] `json:"attestations"` - // A list of deposits made to the Ethereum 1.0 chain - Deposits *solid.ListSSZ[*Deposit] `json:"deposits"` - // A list of validators who have voluntarily exited the beacon chain - VoluntaryExits *solid.ListSSZ[*SignedVoluntaryExit] `json:"voluntary_exits"` - // A summary of the current state of the beacon chain - SyncAggregate *SyncAggregate `json:"sync_aggregate,omitempty"` - // Data related to crosslink records and executing operations on the Ethereum 2.0 chain - ExecutionPayload *Eth1Header `json:"execution_payload_header,omitempty"` - // Withdrawals Diffs for Execution Layer - ExecutionChanges *solid.ListSSZ[*SignedBLSToExecutionChange] `json:"bls_to_execution_changes"` - // The commitments for beacon chain blobs - // With a max of 4 per block - BlobKzgCommitments *solid.ListSSZ[*KZGCommitment] `json:"blob_kzg_commitments"` - // The version of the beacon chain - Version clparams.StateVersion `json:"-"` - beaconCfg *clparams.BeaconChainConfig -} - -// Getters - func NewSignedBlindedBeaconBlock(beaconCfg *clparams.BeaconChainConfig) *SignedBlindedBeaconBlock { return &SignedBlindedBeaconBlock{ Signature: libcommon.Bytes96{}, @@ -99,32 +70,44 @@ func (s *SignedBlindedBeaconBlock) SignedBeaconBlockHeader() *SignedBeaconBlockH } } -func NewBlindedBeaconBlock(beaconCfg *clparams.BeaconChainConfig) *BlindedBeaconBlock { - return &BlindedBeaconBlock{ - Body: NewBlindedBeaconBody(beaconCfg), +func (b *SignedBlindedBeaconBlock) Clone() clonable.Clonable { + return NewSignedBlindedBeaconBlock(b.Block.Body.beaconCfg) +} + +func (b *SignedBlindedBeaconBlock) Unblind(blockPayload *Eth1Block) (*SignedBeaconBlock, error) { + if b == nil { + return nil, fmt.Errorf("nil block") + } + // check root + blindedRoot := b.Block.Body.ExecutionPayload.StateRoot + payloadRoot := blockPayload.StateRoot + if blindedRoot != payloadRoot { + return nil, fmt.Errorf("root mismatch: %s != %s", blindedRoot, payloadRoot) } + + signedBeaconBlock := b.Full(blockPayload.Transactions, blockPayload.Withdrawals) + return signedBeaconBlock, nil } -func NewBlindedBeaconBody(beaconCfg *clparams.BeaconChainConfig) *BlindedBeaconBody { - return &BlindedBeaconBody{ - RandaoReveal: libcommon.Bytes96{}, - Eth1Data: NewEth1Data(), - Graffiti: libcommon.Hash{}, - ProposerSlashings: solid.NewStaticListSSZ[*ProposerSlashing](MaxProposerSlashings, 416), - AttesterSlashings: solid.NewDynamicListSSZ[*AttesterSlashing](MaxAttesterSlashings), - Attestations: solid.NewDynamicListSSZ[*solid.Attestation](MaxAttestations), - Deposits: solid.NewStaticListSSZ[*Deposit](MaxDeposits, 1240), - VoluntaryExits: solid.NewStaticListSSZ[*SignedVoluntaryExit](MaxVoluntaryExits, 112), - SyncAggregate: NewSyncAggregate(), - ExecutionPayload: nil, - ExecutionChanges: solid.NewStaticListSSZ[*SignedBLSToExecutionChange](MaxExecutionChanges, 172), - BlobKzgCommitments: solid.NewStaticListSSZ[*KZGCommitment](MaxBlobsCommittmentsPerBlock, 48), - Version: 0, - beaconCfg: beaconCfg, +func (b *SignedBlindedBeaconBlock) EncodeSSZ(buf []byte) ([]byte, error) { + return ssz2.MarshalSSZ(buf, b.Block, b.Signature[:]) +} + +func (b *SignedBlindedBeaconBlock) EncodingSizeSSZ() int { + if b.Block == nil { + return 100 } + return 100 + b.Block.EncodingSizeSSZ() +} + +func (b *SignedBlindedBeaconBlock) DecodeSSZ(buf []byte, s int) error { + return ssz2.UnmarshalSSZ(buf, s, b.Block, b.Signature[:]) +} + +func (b *SignedBlindedBeaconBlock) HashSSZ() ([32]byte, error) { + return merkle_tree.HashTreeRoot(b.Block, b.Signature[:]) } -// Version returns beacon block version. func (b *SignedBlindedBeaconBlock) Version() clparams.StateVersion { return b.Block.Body.Version } @@ -136,9 +119,19 @@ func (b *SignedBlindedBeaconBlock) Full(txs *solid.TransactionsSSZ, withdrawals } } -// Version returns beacon block version. -func (b *BlindedBeaconBlock) Version() clparams.StateVersion { - return b.Body.Version +// Definitions of BlindedBeaconBlock +type BlindedBeaconBlock struct { + Slot uint64 `json:"slot,string"` + ProposerIndex uint64 `json:"proposer_index,string"` + ParentRoot libcommon.Hash `json:"parent_root"` + StateRoot libcommon.Hash `json:"state_root"` + Body *BlindedBeaconBody `json:"body"` +} + +func NewBlindedBeaconBlock(beaconCfg *clparams.BeaconChainConfig) *BlindedBeaconBlock { + return &BlindedBeaconBlock{ + Body: NewBlindedBeaconBody(beaconCfg), + } } func (b *BlindedBeaconBlock) Full(txs *solid.TransactionsSSZ, withdrawals *solid.ListSSZ[*Withdrawal]) *BeaconBlock { @@ -156,6 +149,103 @@ func (b *BlindedBeaconBlock) SetVersion(version clparams.StateVersion) *BlindedB return b } +func (b *BlindedBeaconBlock) EncodeSSZ(buf []byte) (dst []byte, err error) { + return ssz2.MarshalSSZ(buf, b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +} + +func (b *BlindedBeaconBlock) EncodingSizeSSZ() int { + if b.Body == nil { + return 80 + } + return 80 + b.Body.EncodingSizeSSZ() +} + +func (b *BlindedBeaconBlock) DecodeSSZ(buf []byte, version int) error { + return ssz2.UnmarshalSSZ(buf, version, &b.Slot, &b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +} + +func (b *BlindedBeaconBlock) HashSSZ() ([32]byte, error) { + return merkle_tree.HashTreeRoot(b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +} + +func (*BlindedBeaconBlock) Static() bool { + return false +} + +func (b *BlindedBeaconBlock) Clone() clonable.Clonable { + return NewBlindedBeaconBlock(b.Body.beaconCfg) +} + +func (b *BlindedBeaconBlock) Version() clparams.StateVersion { + return b.Body.Version +} + +func (b *BlindedBeaconBlock) GetProposerIndex() uint64 { + return b.ProposerIndex +} + +func (b *BlindedBeaconBlock) GetSlot() uint64 { + return b.Slot +} + +func (b *BlindedBeaconBlock) GetParentRoot() libcommon.Hash { + return b.ParentRoot +} + +func (b *BlindedBeaconBlock) GetBody() GenericBeaconBody { + return b.Body +} + +// Definitions of BlindedBeaconBody +type BlindedBeaconBody struct { + // A byte array used for randomness in the beacon chain + RandaoReveal libcommon.Bytes96 `json:"randao_reveal"` + // Data related to the Ethereum 1.0 chain + Eth1Data *Eth1Data `json:"eth1_data"` + // A byte array used to customize validators' behavior + Graffiti libcommon.Hash `json:"graffiti"` + // A list of slashing events for validators who included invalid blocks in the chain + ProposerSlashings *solid.ListSSZ[*ProposerSlashing] `json:"proposer_slashings"` + // A list of slashing events for validators who included invalid attestations in the chain + AttesterSlashings *solid.ListSSZ[*AttesterSlashing] `json:"attester_slashings"` + // A list of attestations included in the block + Attestations *solid.ListSSZ[*solid.Attestation] `json:"attestations"` + // A list of deposits made to the Ethereum 1.0 chain + Deposits *solid.ListSSZ[*Deposit] `json:"deposits"` + // A list of validators who have voluntarily exited the beacon chain + VoluntaryExits *solid.ListSSZ[*SignedVoluntaryExit] `json:"voluntary_exits"` + // A summary of the current state of the beacon chain + SyncAggregate *SyncAggregate `json:"sync_aggregate,omitempty"` + // Data related to crosslink records and executing operations on the Ethereum 2.0 chain + ExecutionPayload *Eth1Header `json:"execution_payload_header,omitempty"` + // Withdrawals Diffs for Execution Layer + ExecutionChanges *solid.ListSSZ[*SignedBLSToExecutionChange] `json:"bls_to_execution_changes"` + // The commitments for beacon chain blobs + // With a max of 4 per block + BlobKzgCommitments *solid.ListSSZ[*KZGCommitment] `json:"blob_kzg_commitments"` + // The version of the beacon chain + Version clparams.StateVersion `json:"-"` + beaconCfg *clparams.BeaconChainConfig +} + +func NewBlindedBeaconBody(beaconCfg *clparams.BeaconChainConfig) *BlindedBeaconBody { + return &BlindedBeaconBody{ + RandaoReveal: libcommon.Bytes96{}, + Eth1Data: NewEth1Data(), + Graffiti: libcommon.Hash{}, + ProposerSlashings: solid.NewStaticListSSZ[*ProposerSlashing](MaxProposerSlashings, 416), + AttesterSlashings: solid.NewDynamicListSSZ[*AttesterSlashing](MaxAttesterSlashings), + Attestations: solid.NewDynamicListSSZ[*solid.Attestation](MaxAttestations), + Deposits: solid.NewStaticListSSZ[*Deposit](MaxDeposits, 1240), + VoluntaryExits: solid.NewStaticListSSZ[*SignedVoluntaryExit](MaxVoluntaryExits, 112), + SyncAggregate: NewSyncAggregate(), + ExecutionPayload: nil, + ExecutionChanges: solid.NewStaticListSSZ[*SignedBLSToExecutionChange](MaxExecutionChanges, 172), + BlobKzgCommitments: solid.NewStaticListSSZ[*KZGCommitment](MaxBlobsCommittmentsPerBlock, 48), + Version: 0, + beaconCfg: beaconCfg, + } +} func (b *BlindedBeaconBody) SetVersion(version clparams.StateVersion) *BlindedBeaconBody { b.Version = version if b.ExecutionPayload == nil { @@ -310,84 +400,57 @@ func (b *BlindedBeaconBody) Full(txs *solid.TransactionsSSZ, withdrawals *solid. } } -func (b *BlindedBeaconBlock) EncodeSSZ(buf []byte) (dst []byte, err error) { - return ssz2.MarshalSSZ(buf, b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +func (*BlindedBeaconBody) Static() bool { + return false } - -func (b *BlindedBeaconBlock) EncodingSizeSSZ() int { - if b.Body == nil { - return 80 - } - return 80 + b.Body.EncodingSizeSSZ() +func (b *BlindedBeaconBody) Clone() clonable.Clonable { + return NewBlindedBeaconBody(b.beaconCfg) } -func (b *BlindedBeaconBlock) DecodeSSZ(buf []byte, version int) error { - return ssz2.UnmarshalSSZ(buf, version, &b.Slot, &b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +func (b *BlindedBeaconBody) ExecutionPayloadMerkleProof() ([][32]byte, error) { + return merkle_tree.MerkleProof(4, 9, b.getSchema(false)...) } -func (b *BlindedBeaconBlock) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(b.Slot, b.ProposerIndex, b.ParentRoot[:], b.StateRoot[:], b.Body) +func (b *BlindedBeaconBody) GetPayloadHeader() (*Eth1Header, error) { + return b.ExecutionPayload, nil } -func (b *SignedBlindedBeaconBlock) EncodeSSZ(buf []byte) ([]byte, error) { - return ssz2.MarshalSSZ(buf, b.Block, b.Signature[:]) +func (b *BlindedBeaconBody) GetRandaoReveal() libcommon.Bytes96 { + return b.RandaoReveal } -func (b *SignedBlindedBeaconBlock) EncodingSizeSSZ() int { - if b.Block == nil { - return 100 - } - return 100 + b.Block.EncodingSizeSSZ() +func (b *BlindedBeaconBody) GetEth1Data() *Eth1Data { + return b.Eth1Data } -func (b *SignedBlindedBeaconBlock) DecodeSSZ(buf []byte, s int) error { - return ssz2.UnmarshalSSZ(buf, s, b.Block, b.Signature[:]) +func (b *BlindedBeaconBody) GetSyncAggregate() *SyncAggregate { + return b.SyncAggregate } -func (b *SignedBlindedBeaconBlock) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(b.Block, b.Signature[:]) +func (b *BlindedBeaconBody) GetProposerSlashings() *solid.ListSSZ[*ProposerSlashing] { + return b.ProposerSlashings } -func (*BlindedBeaconBody) Static() bool { - return false +func (b *BlindedBeaconBody) GetAttesterSlashings() *solid.ListSSZ[*AttesterSlashing] { + return b.AttesterSlashings } -func (*BlindedBeaconBlock) Static() bool { - return false +func (b *BlindedBeaconBody) GetAttestations() *solid.ListSSZ[*solid.Attestation] { + return b.Attestations } -func (b *BlindedBeaconBody) Clone() clonable.Clonable { - return NewBlindedBeaconBody(b.beaconCfg) +func (b *BlindedBeaconBody) GetDeposits() *solid.ListSSZ[*Deposit] { + return b.Deposits } -func (b *BlindedBeaconBlock) Clone() clonable.Clonable { - return NewBlindedBeaconBlock(b.Body.beaconCfg) +func (b *BlindedBeaconBody) GetVoluntaryExits() *solid.ListSSZ[*SignedVoluntaryExit] { + return b.VoluntaryExits } -func (b *SignedBlindedBeaconBlock) Clone() clonable.Clonable { - return NewSignedBlindedBeaconBlock(b.Block.Body.beaconCfg) +func (b *BlindedBeaconBody) GetBlobKzgCommitments() *solid.ListSSZ[*KZGCommitment] { + return b.BlobKzgCommitments } -func (b *BlindedBeaconBody) ExecutionPayloadMerkleProof() ([][32]byte, error) { - return merkle_tree.MerkleProof(4, 9, b.getSchema(false)...) +func (b *BlindedBeaconBody) GetExecutionChanges() *solid.ListSSZ[*SignedBLSToExecutionChange] { + return b.ExecutionChanges } - -func (b *SignedBlindedBeaconBlock) Unblind(blockPayload *Eth1Block) (*SignedBeaconBlock, error) { - if b == nil { - return nil, fmt.Errorf("nil block") - } - // check root - blindedRoot := b.Block.Body.ExecutionPayload.StateRoot - payloadRoot := blockPayload.StateRoot - if blindedRoot != payloadRoot { - return nil, fmt.Errorf("root mismatch: %s != %s", blindedRoot, payloadRoot) - } - - signedBeaconBlock := b.Full(blockPayload.Transactions, blockPayload.Withdrawals) - return signedBeaconBlock, nil -} - -// make sure that the type implements the interface ssz2.ObjectSSZ -var _ ssz2.ObjectSSZ = (*BlindedBeaconBody)(nil) -var _ ssz2.ObjectSSZ = (*BlindedBeaconBlock)(nil) -var _ ssz2.ObjectSSZ = (*SignedBlindedBeaconBlock)(nil) diff --git a/cl/cltypes/beacon_block_interface.go b/cl/cltypes/beacon_block_interface.go new file mode 100644 index 00000000000..d2234c87d5e --- /dev/null +++ b/cl/cltypes/beacon_block_interface.go @@ -0,0 +1,31 @@ +package cltypes + +import ( + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/cl/clparams" + "github.com/ledgerwatch/erigon/cl/cltypes/solid" +) + +type GenericBeaconBlock interface { + Version() clparams.StateVersion + GetSlot() uint64 + GetProposerIndex() uint64 + GetParentRoot() libcommon.Hash + GetBody() GenericBeaconBody +} + +type GenericBeaconBody interface { + HashSSZ() ([32]byte, error) + GetPayloadHeader() (*Eth1Header, error) + GetRandaoReveal() libcommon.Bytes96 + GetEth1Data() *Eth1Data + GetSyncAggregate() *SyncAggregate + + GetProposerSlashings() *solid.ListSSZ[*ProposerSlashing] + GetAttesterSlashings() *solid.ListSSZ[*AttesterSlashing] + GetAttestations() *solid.ListSSZ[*solid.Attestation] + GetDeposits() *solid.ListSSZ[*Deposit] + GetVoluntaryExits() *solid.ListSSZ[*SignedVoluntaryExit] + GetBlobKzgCommitments() *solid.ListSSZ[*KZGCommitment] + GetExecutionChanges() *solid.ListSSZ[*SignedBLSToExecutionChange] +} diff --git a/cl/cltypes/block_production.go b/cl/cltypes/block_production.go index 4f7f1aa859e..cbb175308d3 100644 --- a/cl/cltypes/block_production.go +++ b/cl/cltypes/block_production.go @@ -42,6 +42,13 @@ type BlindOrExecutionBeaconBlock struct { Cfg *clparams.BeaconChainConfig } +func (b *BlindOrExecutionBeaconBlock) ToGeneric() GenericBeaconBlock { + if b.BlindedBeaconBody != nil { + return b.ToBlinded() + } + return b.ToExecution() +} + func (b *BlindOrExecutionBeaconBlock) ToBlinded() *BlindedBeaconBlock { return &BlindedBeaconBlock{ Slot: b.Slot, diff --git a/cl/transition/machine/block.go b/cl/transition/machine/block.go index 9449fc14d3b..171a433d6ee 100644 --- a/cl/transition/machine/block.go +++ b/cl/transition/machine/block.go @@ -17,12 +17,12 @@ package machine import ( - "errors" "fmt" "github.com/ledgerwatch/erigon-lib/metrics" "github.com/ledgerwatch/erigon/cl/abstract" "github.com/ledgerwatch/erigon/cl/phase1/core/state" + "github.com/pkg/errors" "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cl/cltypes" @@ -30,84 +30,30 @@ import ( ) // ProcessBlock processes a block with the block processor -func ProcessBlock(impl BlockProcessor, s abstract.BeaconState, block *cltypes.BeaconBlock) error { - version := s.Version() - // Check the state version is correct. - if block.Version() != version { - return fmt.Errorf("processBlock: wrong state version for block at slot %d", block.Slot) - } - h := metrics.NewHistTimer("beacon_process_block") - // Process the block header. - bodyRoot, err := block.Body.HashSSZ() - if err != nil { - return fmt.Errorf("processBlock: failed to hash block body: %v", err) - } - if err := impl.ProcessBlockHeader(s, block.Slot, block.ProposerIndex, block.ParentRoot, bodyRoot); err != nil { - return fmt.Errorf("processBlock: failed to process block header: %v", err) - } - // Process execution payload if enabled. - if version >= clparams.BellatrixVersion && executionEnabled(s, block.Body.ExecutionPayload.BlockHash) { - if s.Version() >= clparams.CapellaVersion { - // Process withdrawals in the execution payload. - if err := impl.ProcessWithdrawals(s, block.Body.ExecutionPayload.Withdrawals); err != nil { - return fmt.Errorf("processBlock: failed to process withdrawals: %v", err) - } - } - // Process the execution payload. - header, err := block.Body.ExecutionPayload.PayloadHeader() - if err != nil { - return fmt.Errorf("processBlock: failed to extract execution payload header: %v", err) - } - if err := impl.ProcessExecutionPayload(s, block.Body.ExecutionPayload.ParentHash, - block.Body.ExecutionPayload.PrevRandao, - block.Body.ExecutionPayload.Time, header); err != nil { - return fmt.Errorf("processBlock: failed to process execution payload: %v", err) - } - } - // Process RANDAO reveal. - if err := impl.ProcessRandao(s, block.Body.RandaoReveal, block.ProposerIndex); err != nil { - return fmt.Errorf("processBlock: failed to process RANDAO reveal: %v", err) - } - // Process Eth1 data. - if err := impl.ProcessEth1Data(s, block.Body.Eth1Data); err != nil { - return fmt.Errorf("processBlock: failed to process Eth1 data: %v", err) - } - // Process block body operations. - if err := ProcessOperations(impl, s, block.Body); err != nil { - return fmt.Errorf("processBlock: failed to process block body operations: %v", err) - } - // Process sync aggregate in case of Altair version. - if version >= clparams.AltairVersion { - if err := impl.ProcessSyncAggregate(s, block.Body.SyncAggregate); err != nil { - return fmt.Errorf("processBlock: failed to process sync aggregate: %v", err) - } - } - - h.PutSince() - return nil -} - -func ProcessBlindedBlock(impl BlockProcessor, s abstract.BeaconState, block *cltypes.BlindedBeaconBlock) error { +func ProcessBlock(impl BlockProcessor, s abstract.BeaconState, block cltypes.GenericBeaconBlock) error { var ( version = s.Version() - // Process the execution payload. Note that the execution payload does not contain txs and withdrawals. - partialExecutionBody = block.Body.Full(nil, nil) + body = block.GetBody() ) + payloadHeader, err := body.GetPayloadHeader() + if err != nil { + return errors.WithMessage(err, "processBlock: failed to extract execution payload header") + } // Check the state version is correct. if block.Version() != version { - return fmt.Errorf("processBlindedBlock: wrong state version for block at slot %d", block.Slot) + return fmt.Errorf("processBlindedBlock: wrong state version for block at slot %d", block.GetSlot()) } h := metrics.NewHistTimer("beacon_process_blinded_block") - bodyRoot, err := block.Body.HashSSZ() + bodyRoot, err := body.HashSSZ() if err != nil { - return fmt.Errorf("processBlindedBlock: failed to hash block body: %v", err) + return errors.WithMessagef(err, "processBlindedBlock: failed to hash block body") } - if err := impl.ProcessBlockHeader(s, block.Slot, block.ProposerIndex, block.ParentRoot, bodyRoot); err != nil { + if err := impl.ProcessBlockHeader(s, block.GetSlot(), block.GetProposerIndex(), block.GetParentRoot(), bodyRoot); err != nil { return fmt.Errorf("processBlindedBlock: failed to process block header: %v", err) } // Process execution payload if enabled. - if version >= clparams.BellatrixVersion && executionEnabled(s, block.Body.ExecutionPayload.BlockHash) { + if version >= clparams.BellatrixVersion && executionEnabled(s, payloadHeader.BlockHash) { if s.Version() >= clparams.CapellaVersion { // Process withdrawals in the execution payload. expect := state.ExpectedWithdrawals(s, state.Epoch(s)) @@ -119,30 +65,29 @@ func ProcessBlindedBlock(impl BlockProcessor, s abstract.BeaconState, block *clt return fmt.Errorf("processBlock: failed to process withdrawals: %v", err) } } - parentHash := block.Body.ExecutionPayload.ParentHash - prevRandao := block.Body.ExecutionPayload.PrevRandao - time := block.Body.ExecutionPayload.Time - header := block.Body.ExecutionPayload - if err := impl.ProcessExecutionPayload(s, parentHash, prevRandao, time, header); err != nil { + parentHash := payloadHeader.ParentHash + prevRandao := payloadHeader.PrevRandao + time := payloadHeader.Time + if err := impl.ProcessExecutionPayload(s, parentHash, prevRandao, time, payloadHeader); err != nil { return fmt.Errorf("processBlock: failed to process execution payload: %v", err) } } // Process RANDAO reveal. - if err := impl.ProcessRandao(s, block.Body.RandaoReveal, block.ProposerIndex); err != nil { + if err := impl.ProcessRandao(s, body.GetRandaoReveal(), block.GetProposerIndex()); err != nil { return fmt.Errorf("processBlock: failed to process RANDAO reveal: %v", err) } // Process Eth1 data. - if err := impl.ProcessEth1Data(s, block.Body.Eth1Data); err != nil { + if err := impl.ProcessEth1Data(s, body.GetEth1Data()); err != nil { return fmt.Errorf("processBlock: failed to process Eth1 data: %v", err) } // Process block body operations. - if err := ProcessOperations(impl, s, partialExecutionBody); err != nil { + if err := ProcessOperations(impl, s, body); err != nil { return fmt.Errorf("processBlock: failed to process block body operations: %v", err) } // Process sync aggregate in case of Altair version. if version >= clparams.AltairVersion { - if err := impl.ProcessSyncAggregate(s, block.Body.SyncAggregate); err != nil { + if err := impl.ProcessSyncAggregate(s, body.GetSyncAggregate()); err != nil { return fmt.Errorf("processBlock: failed to process sync aggregate: %v", err) } } @@ -152,13 +97,13 @@ func ProcessBlindedBlock(impl BlockProcessor, s abstract.BeaconState, block *clt } // ProcessOperations is called by ProcessBlock and prcesses the block body operations -func ProcessOperations(impl BlockOperationProcessor, s abstract.BeaconState, blockBody *cltypes.BeaconBody) error { - if blockBody.Deposits.Len() != int(maximumDeposits(s)) { +func ProcessOperations(impl BlockOperationProcessor, s abstract.BeaconState, blockBody cltypes.GenericBeaconBody) error { + if blockBody.GetDeposits().Len() != int(maximumDeposits(s)) { return errors.New("outstanding deposits do not match maximum deposits") } // Process each proposer slashing var err error - if err := solid.RangeErr[*cltypes.ProposerSlashing](blockBody.ProposerSlashings, func(index int, slashing *cltypes.ProposerSlashing, length int) error { + if err := solid.RangeErr[*cltypes.ProposerSlashing](blockBody.GetProposerSlashings(), func(index int, slashing *cltypes.ProposerSlashing, length int) error { if err = impl.ProcessProposerSlashing(s, slashing); err != nil { return fmt.Errorf("ProcessProposerSlashing: %s", err) } @@ -167,7 +112,7 @@ func ProcessOperations(impl BlockOperationProcessor, s abstract.BeaconState, blo return err } - if err := solid.RangeErr[*cltypes.AttesterSlashing](blockBody.AttesterSlashings, func(index int, slashing *cltypes.AttesterSlashing, length int) error { + if err := solid.RangeErr[*cltypes.AttesterSlashing](blockBody.GetAttesterSlashings(), func(index int, slashing *cltypes.AttesterSlashing, length int) error { if err = impl.ProcessAttesterSlashing(s, slashing); err != nil { return fmt.Errorf("ProcessAttesterSlashing: %s", err) } @@ -177,12 +122,12 @@ func ProcessOperations(impl BlockOperationProcessor, s abstract.BeaconState, blo } // Process each attestations - if err := impl.ProcessAttestations(s, blockBody.Attestations); err != nil { + if err := impl.ProcessAttestations(s, blockBody.GetAttestations()); err != nil { return fmt.Errorf("ProcessAttestation: %s", err) } // Process each deposit - if err := solid.RangeErr[*cltypes.Deposit](blockBody.Deposits, func(index int, deposit *cltypes.Deposit, length int) error { + if err := solid.RangeErr[*cltypes.Deposit](blockBody.GetDeposits(), func(index int, deposit *cltypes.Deposit, length int) error { if err = impl.ProcessDeposit(s, deposit); err != nil { return fmt.Errorf("ProcessDeposit: %s", err) } @@ -192,7 +137,7 @@ func ProcessOperations(impl BlockOperationProcessor, s abstract.BeaconState, blo } // Process each voluntary exit. - if err := solid.RangeErr[*cltypes.SignedVoluntaryExit](blockBody.VoluntaryExits, func(index int, exit *cltypes.SignedVoluntaryExit, length int) error { + if err := solid.RangeErr[*cltypes.SignedVoluntaryExit](blockBody.GetVoluntaryExits(), func(index int, exit *cltypes.SignedVoluntaryExit, length int) error { if err = impl.ProcessVoluntaryExit(s, exit); err != nil { return fmt.Errorf("ProcessVoluntaryExit: %s", err) } @@ -204,7 +149,7 @@ func ProcessOperations(impl BlockOperationProcessor, s abstract.BeaconState, blo return nil } // Process each execution change. this will only have entries after the capella fork. - if err := solid.RangeErr[*cltypes.SignedBLSToExecutionChange](blockBody.ExecutionChanges, func(index int, addressChange *cltypes.SignedBLSToExecutionChange, length int) error { + if err := solid.RangeErr[*cltypes.SignedBLSToExecutionChange](blockBody.GetExecutionChanges(), func(index int, addressChange *cltypes.SignedBLSToExecutionChange, length int) error { if err := impl.ProcessBlsToExecutionChange(s, addressChange); err != nil { return fmt.Errorf("ProcessBlsToExecutionChange: %s", err) } diff --git a/experiment/main.go b/experiment/main.go new file mode 100644 index 00000000000..22b1259b859 --- /dev/null +++ b/experiment/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/ledgerwatch/erigon/cl/beacon/builder" +) + +func main() { + /*content := "{\"version\":\"deneb\",\"data\":{\"message\":{\"header\":{\"parent_hash\":\"0xaf64e50fe1ca408ecb40950776389d83afc245492be31a1f44f6fb7aae8fd181\",\"fee_recipient\":\"0x184ba627DB853244c9f17f3Cb4378cB8B39bf147\",\"state_root\":\"0x38e8cac59b574e28b14488cd0f87deb32803d46a2261ef04e3fe1ca22f731916\",\"receipts_root\":\"0x46ec11d1408d4f119c9c1b9ef0833d9e845bf54ea0c4b009547f5c7a6f5de191\",\"logs_bloom\":\"0x6b1c01e883b841848d126462108c0064027399801c149440c800611c4364802c000a64000822012855160481063d18c132f071020ba088208804925136ac412144e7a04ac21d16a6f284897e922d10048de0520012886e015150018419b1141404281004aa4e16d82002570282131b000a1831e6304705a93218c338ddd220d6c724e10110ec5010f08100882221130081016404084104e6201140031dc742006b1aa02eb942300107c8c3228102040400c2818030180b0019838a0a803a3081688184a216bc06c8983502d55e6e40310600a48248584c1c0a06dbe1147527a4901d84002a46100cc06d914e30042006e048539428aa128b931300120820c302\",\"prev_randao\":\"0x17beee045f3ac5200ee00a46e99718e0d1f2052815bfc16cacf71d5770f51afe\",\"block_number\":\"6083749\",\"gas_limit\":\"30000000\",\"gas_used\":\"14411176\",\"timestamp\":\"1718085912\",\"extra_data\":\"0x4275696c644149202868747470733a2f2f6275696c6461692e6e657429\",\"base_fee_per_gas\":\"808216432\",\"block_hash\":\"0xd57bd68588624076f6048385c448a38a4fb66a889596059c43e69a24cc37a601\",\"transactions_root\":\"0x215221777776429bd8f0a6da793dd993238f2380ee59f399bcac87087a53533c\",\"withdrawals_root\":\"0x4256f16ab1918724d17d92da65cbf6068947394fcd9db147d6a50e2328a4fe4e\",\"blob_gas_used\":\"0\",\"excess_blob_gas\":\"131072\"},\"blob_kzg_commitments\":[],\"value\":\"14742875282164771\",\"pubkey\":\"0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110\"},\"signature\":\"0xb51472e1fd4e2e9c11b951a1f976e2f59cb02b6d167a44e157f33df5cf2a8c0e91eba7b4ee9e514e40ca06c240778294029625ef8ab9995e957fdf6ff34d4649d7bf5a0ab841184ebda025188e5fb51a4dc990c64e0a744a02cf669d1ee54059\"}}\n" + + payload := &builder.ExecutionPayloadHeader{} + if err := json.Unmarshal([]byte(content), payload); err != nil { + panic(err) + } + + fmt.Printf("Payload: %+v\n", payload) + // print value + fmt.Printf("Block value: %v\n", payload.BlockValue()) + + */ + payload := "{\"signature\":\"0x8efc8d6d98799edaa7ca08741238920ec3f4e92566e1f6744cd0b5e2bf6a158ed6d447f5255c4caee3d09bb0789149fe088547fff846cc96ac82e6300e70870fe28ed9965932d35fbb4b5ed0d990c87c0cd4d026e2f9717a9954cf8bd3047e96\",\"message\":{\"slot\":\"5196925\",\"proposer_index\":\"336\",\"parent_root\":\"0xb41c6db39095eb7f399a7e88952eb569bd8610d857fbd9c7e4f0554b04fc9576\",\"state_root\":\"0xeedc5e2e4287e51cc2a52a4838e85606d0e157c358a5a9f1f0d6fba2fc5f279e\",\"body\":{\"randao_reveal\":\"0x87ab2b98f8a7c0c8696a25f1ba5964dc6eb7fc253abc2dc44aaea962deb8ea237a7393e5e0c15a5f02f626050ab3887700d9c6d1380a6dd2a4bfb4b812f67ae1ff489993ceb8e22218e9bd198053250bbef9d4f182a6299f98efa4e61a8b3094\",\"eth1_data\":{\"deposit_root\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"deposit_count\":\"0\",\"block_hash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"},\"graffiti\":\"0x00000000000000000000000000000000000000000000000000004361706c696e\",\"proposer_slashings\":[],\"attester_slashings\":[],\"attestations\":[{\"aggregation_bits\":\"0xffffffdfffffff\",\"signature\":\"0xb5a8b0dc73676a25c69bea22e6a3f4078e6fd5dca505e9792c8bf7360f9afeed2206ed412102a161bf9844829467682d0703af2b4bcfcc8195423c258b32d91584ecead21e476c82a1d38c5786f2b6ab515991f6eeaf86533eb2ab06d925e6ef\",\"data\":{\"slot\":\"5196924\",\"index\":\"0\",\"beacon_block_root\":\"0xb41c6db39095eb7f399a7e88952eb569bd8610d857fbd9c7e4f0554b04fc9576\",\"source\":{\"epoch\":\"162402\",\"root\":\"0xebc218e8976c3b74a8bdf575c3a4a9c47d5ca409e220ed54a87bd20f9deac57f\"},\"target\":{\"epoch\":\"162403\",\"root\":\"0xbabf82fbc9495488d1e7a9307cc2d25561aa9dca4583fb18a55228218f9b3440\"}}}],\"deposits\":[],\"voluntary_exits\":[],\"sync_aggregate\":{\"sync_committee_bits\":\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\"sync_committee_signature\":\"0x96b024274ab5d35ed451ce5ce03264eb8d136fe59fc0dea3a6050843dcc1a5c40c95e2ea5b4df9eac8642c160ba32d3e18e93bdbfcd24426878a8e1306e7eb2ed35e81ebd08851897f54262448a0dc9914c4ed1a41c27d24c995b09623fc86b9\"},\"execution_payload_header\":{\"parent_hash\":\"0x4d0ddf85d6e5d668b356d300394555e63200cc44b46a75ac51ad7e25d03fe9d0\",\"fee_recipient\":\"0x184ba627db853244c9f17f3cb4378cb8b39bf147\",\"state_root\":\"0x59245e2821f0c9d225bbef287f0056e95db1ee604fd8d0e36316c143e1df9113\",\"receipts_root\":\"0x69cc739b4c156513c5c905b9a291df03ce9742e25500a1bfa73865346ff359bc\",\"logs_bloom\":\"0x281d80a818f05018c2d2440a0890c0248443314058008448028140086d89c208020c02b1610752401612412b190e0981421113060240480120851221976820506220200a18148316d116208e102a00031c63581520886240210682c10810000108a800802a020000062c850980000d10102891e9010a511880a6021142c02a102f47224d4154c0203062a50a2458152288480420d015583c019512a9ad141600520d0482c9000ad40add0003386084100642ca43005a240900822b8b160686cc0085630b9cb0460810a107739c225280106282a07490819006007b7dc1236c12c052529088c4080c810c7200b0402900085030284910150200003272000c4100\",\"prev_randao\":\"0xc7791b7f7810ded641f97911a1051a2b662e44e89652b1670d9bf9fc14a45e80\",\"block_number\":\"6084597\",\"gas_limit\":\"30000000\",\"gas_used\":\"11284879\",\"timestamp\":\"1718096700\",\"extra_data\":\"0x4275696c644149202868747470733a2f2f6275696c6461692e6e657429\",\"base_fee_per_gas\":\"3876390830\",\"block_hash\":\"0x62b295d485d259babdb4c8b8a43d5e036e1e65f90036b0faaf600dcd80fdf792\",\"transactions_root\":\"0x61ae8a6f8754c9d34ee2c9dacb38e2e586089895ce9dee5571b8479c9949901a\",\"withdrawals_root\":\"0x1608014cacc3d3e1e8abccf9d6ba491587725fcd4bc65c744033e7b7fb7bcf4a\",\"blob_gas_used\":\"262144\",\"excess_blob_gas\":\"524288\"},\"bls_to_execution_changes\":[],\"blob_kzg_commitments\":[\"0xb0c1022f552aede9aee79d81d3d3c76a0268d795c7cad08137ce9ca3217bc47e3e4c74552707b843ecf74d951f07a9ef\",\"0xb20310ed4d5251426842082db0db1d51331486445a9f0b90380253299981e9873617efe2ea8b6c74a7d98dbf3399d854\"]}}}" + + data := &builder.BlindedBlockResponse{} + if err := json.Unmarshal([]byte(payload), data); err != nil { + panic(err) + } + + fmt.Printf("Data: %+v\n", data) +}