diff --git a/cl/cltypes/aggregate.go b/cl/cltypes/aggregate.go index 8e1d53e5adf..5ea75835af8 100644 --- a/cl/cltypes/aggregate.go +++ b/cl/cltypes/aggregate.go @@ -64,20 +64,20 @@ type SignedAggregateAndProof struct { } func (a *SignedAggregateAndProof) EncodeSSZ(dst []byte) ([]byte, error) { - return ssz2.MarshalSSZ(dst, a.Message, a.Signature[:]) + return encodeSigned(dst, a.Message, a.Signature[:]) } func (a *SignedAggregateAndProof) DecodeSSZ(buf []byte, version int) error { a.Message = new(AggregateAndProof) - return ssz2.UnmarshalSSZ(buf, version, a.Message, a.Signature[:]) + return decodeSigned(buf, version, a.Message, a.Signature[:]) } func (a *SignedAggregateAndProof) EncodingSizeSSZ() int { - return 100 + a.Message.EncodingSizeSSZ() + return sizeSigned(a.Message) } func (a *SignedAggregateAndProof) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(a.Message, a.Signature[:]) + return hashSigned(a.Message, a.Signature[:]) } // Default mainnet sync committee bits size in bytes (512 / 8). diff --git a/cl/cltypes/beacon_header.go b/cl/cltypes/beacon_header.go index 4f0cbb4abed..ce605271f34 100644 --- a/cl/cltypes/beacon_header.go +++ b/cl/cltypes/beacon_header.go @@ -73,19 +73,18 @@ func (b *SignedBeaconBlockHeader) Static() bool { } func (b *SignedBeaconBlockHeader) EncodeSSZ(dst []byte) ([]byte, error) { - return ssz2.MarshalSSZ(dst, b.Header, b.Signature[:]) + return encodeSigned(dst, b.Header, b.Signature[:]) } func (b *SignedBeaconBlockHeader) DecodeSSZ(buf []byte, version int) error { b.Header = new(BeaconBlockHeader) - return ssz2.UnmarshalSSZ(buf, version, b.Header, b.Signature[:]) - + return decodeSigned(buf, version, b.Header, b.Signature[:]) } func (b *SignedBeaconBlockHeader) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(b.Header, b.Signature[:]) + return hashSigned(b.Header, b.Signature[:]) } func (b *SignedBeaconBlockHeader) EncodingSizeSSZ() int { - return b.Header.EncodingSizeSSZ() + 96 + return sizeSigned(b.Header) } diff --git a/cl/cltypes/bls_to_execution_change.go b/cl/cltypes/bls_to_execution_change.go index 92dd08bebda..2eebc4d7fc6 100644 --- a/cl/cltypes/bls_to_execution_change.go +++ b/cl/cltypes/bls_to_execution_change.go @@ -64,18 +64,18 @@ type SignedBLSToExecutionChange struct { } func (s *SignedBLSToExecutionChange) EncodeSSZ(buf []byte) ([]byte, error) { - return ssz2.MarshalSSZ(buf, s.Message, s.Signature[:]) + return encodeSigned(buf, s.Message, s.Signature[:]) } func (s *SignedBLSToExecutionChange) DecodeSSZ(buf []byte, version int) error { s.Message = new(BLSToExecutionChange) - return ssz2.UnmarshalSSZ(buf, version, s.Message, s.Signature[:]) + return decodeSigned(buf, version, s.Message, s.Signature[:]) } func (s *SignedBLSToExecutionChange) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(s.Message, s.Signature[:]) + return hashSigned(s.Message, s.Signature[:]) } func (s *SignedBLSToExecutionChange) EncodingSizeSSZ() int { - return 96 + s.Message.EncodingSizeSSZ() + return sizeSigned(s.Message) } diff --git a/cl/cltypes/contribution.go b/cl/cltypes/contribution.go index 439a4643181..c3593052408 100644 --- a/cl/cltypes/contribution.go +++ b/cl/cltypes/contribution.go @@ -67,7 +67,7 @@ type SignedContributionAndProof struct { } func (a *SignedContributionAndProof) EncodeSSZ(dst []byte) ([]byte, error) { - return ssz2.MarshalSSZ(dst, a.Message, a.Signature[:]) + return encodeSigned(dst, a.Message, a.Signature[:]) } func (a *SignedContributionAndProof) DecodeSSZ(buf []byte, version int) error { @@ -77,16 +77,15 @@ func (a *SignedContributionAndProof) DecodeSSZ(buf []byte, version int) error { if a.Message.Contribution == nil { a.Message.Contribution = new(Contribution) } - return ssz2.UnmarshalSSZ(buf, version, a.Message, a.Signature[:]) + return decodeSigned(buf, version, a.Message, a.Signature[:]) } func (a *SignedContributionAndProof) EncodingSizeSSZ() int { - return length.Bytes96 + a.Message.EncodingSizeSSZ() - // return 100 + a.Message.EncodingSizeSSZ() + return sizeSigned(a.Message) } func (a *SignedContributionAndProof) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(a.Message, a.Signature[:]) + return hashSigned(a.Message, a.Signature[:]) } // DefaultSyncCommitteeAggregationBitsSize is the mainnet default: 512/4/8 = 16 bytes. diff --git a/cl/cltypes/epbs_payload.go b/cl/cltypes/epbs_payload.go index 855e1fd1756..1c7d9ce3685 100644 --- a/cl/cltypes/epbs_payload.go +++ b/cl/cltypes/epbs_payload.go @@ -373,11 +373,11 @@ type SignedExecutionPayloadBid struct { } func (s *SignedExecutionPayloadBid) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(s.Message, s.Signature[:]) + return hashSigned(s.Message, s.Signature[:]) } func (s *SignedExecutionPayloadBid) EncodingSizeSSZ() int { - return 4 + s.Message.EncodingSizeSSZ() + length.Bytes96 // 4 is the offset for Message (variable-length field) + return sizeSigned(s.Message) } func (s *SignedExecutionPayloadBid) Static() bool { @@ -385,12 +385,12 @@ func (s *SignedExecutionPayloadBid) Static() bool { } func (s *SignedExecutionPayloadBid) EncodeSSZ(buf []byte) ([]byte, error) { - return ssz2.MarshalSSZ(buf, s.Message, s.Signature[:]) + return encodeSigned(buf, s.Message, s.Signature[:]) } func (s *SignedExecutionPayloadBid) DecodeSSZ(buf []byte, version int) error { s.Message = new(ExecutionPayloadBid) - return ssz2.UnmarshalSSZ(buf, version, s.Message, s.Signature[:]) + return decodeSigned(buf, version, s.Message, s.Signature[:]) } func (s *SignedExecutionPayloadBid) Clone() clonable.Clonable { @@ -494,7 +494,7 @@ type SignedExecutionPayloadEnvelope struct { } func (s *SignedExecutionPayloadEnvelope) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(s.Message, s.Signature[:]) + return hashSigned(s.Message, s.Signature[:]) } func (s *SignedExecutionPayloadEnvelope) Static() bool { @@ -502,18 +502,18 @@ func (s *SignedExecutionPayloadEnvelope) Static() bool { } func (s *SignedExecutionPayloadEnvelope) EncodeSSZ(buf []byte) ([]byte, error) { - return ssz2.MarshalSSZ(buf, s.Message, s.Signature[:]) + return encodeSigned(buf, s.Message, s.Signature[:]) } func (s *SignedExecutionPayloadEnvelope) DecodeSSZ(buf []byte, version int) error { if s.Message == nil { s.Message = NewExecutionPayloadEnvelope(s.beaconCfg) } - return ssz2.UnmarshalSSZ(buf, version, s.Message, s.Signature[:]) + return decodeSigned(buf, version, s.Message, s.Signature[:]) } func (s *SignedExecutionPayloadEnvelope) EncodingSizeSSZ() int { - return 4 + s.Message.EncodingSizeSSZ() + length.Bytes96 // 4 is the offset for Message (variable-length) + return sizeSigned(s.Message) } func (s *SignedExecutionPayloadEnvelope) Clone() clonable.Clonable { diff --git a/cl/cltypes/epbs_proposer.go b/cl/cltypes/epbs_proposer.go index 1a0e7e16aa9..71dcbc83275 100644 --- a/cl/cltypes/epbs_proposer.go +++ b/cl/cltypes/epbs_proposer.go @@ -91,7 +91,7 @@ func (s *SignedProposerPreferences) EncodingSizeSSZ() int { if s.Message == nil { return length.Bytes96 } - return s.Message.EncodingSizeSSZ() + length.Bytes96 + return sizeSigned(s.Message) } func (s *SignedProposerPreferences) Static() bool { @@ -99,16 +99,16 @@ func (s *SignedProposerPreferences) Static() bool { } func (s *SignedProposerPreferences) EncodeSSZ(buf []byte) ([]byte, error) { - return ssz2.MarshalSSZ(buf, s.Message, s.Signature[:]) + return encodeSigned(buf, s.Message, s.Signature[:]) } func (s *SignedProposerPreferences) DecodeSSZ(buf []byte, version int) error { s.Message = new(ProposerPreferences) - return ssz2.UnmarshalSSZ(buf, version, s.Message, s.Signature[:]) + return decodeSigned(buf, version, s.Message, s.Signature[:]) } func (s *SignedProposerPreferences) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(s.Message, s.Signature[:]) + return hashSigned(s.Message, s.Signature[:]) } func (s *SignedProposerPreferences) Clone() clonable.Clonable { diff --git a/cl/cltypes/signed_ssz.go b/cl/cltypes/signed_ssz.go new file mode 100644 index 00000000000..d62bee3d3ed --- /dev/null +++ b/cl/cltypes/signed_ssz.go @@ -0,0 +1,46 @@ +// Copyright 2026 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + +package cltypes + +import ( + "github.com/erigontech/erigon/cl/merkle_tree" + ssz2 "github.com/erigontech/erigon/cl/ssz" + "github.com/erigontech/erigon/common/length" + "github.com/erigontech/erigon/common/ssz" +) + +// SSZ quartet shared by the signed container types ({Message, Signature} pairs). + +func encodeSigned(buf []byte, msg ssz2.SizedObjectSSZ, sig []byte) ([]byte, error) { + return ssz2.MarshalSSZ(buf, msg, sig) +} + +func decodeSigned(buf []byte, version int, msg ssz2.SizedObjectSSZ, sig []byte) error { + return ssz2.UnmarshalSSZ(buf, version, msg, sig) +} + +func sizeSigned(msg ssz2.SizedObjectSSZ) int { + size := length.Bytes96 + msg.EncodingSizeSSZ() + if !msg.Static() { + size += 4 + } + return size +} + +func hashSigned(msg ssz.HashableSSZ, sig []byte) ([32]byte, error) { + return merkle_tree.HashTreeRoot(msg, sig) +} diff --git a/cl/cltypes/signed_ssz_golden_test.go b/cl/cltypes/signed_ssz_golden_test.go new file mode 100644 index 00000000000..47226900e92 --- /dev/null +++ b/cl/cltypes/signed_ssz_golden_test.go @@ -0,0 +1,299 @@ +// Copyright 2026 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + +package cltypes_test + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/erigontech/erigon/cl/clparams" + "github.com/erigontech/erigon/cl/cltypes" + "github.com/erigontech/erigon/cl/cltypes/solid" + "github.com/erigontech/erigon/common" +) + +// Golden tests pinning the exact SSZ encoding and hash tree root of every +// signed container type ({Message, Signature} pair). These types cross the +// network, so any refactor of their SSZ methods must stay byte-identical. + +type signedContainerSSZ interface { + EncodeSSZ([]byte) ([]byte, error) + DecodeSSZ([]byte, int) error + EncodingSizeSSZ() int + HashSSZ() ([32]byte, error) +} + +func requireGoldenSSZ(t *testing.T, obj signedContainerSSZ, wantEncHex, wantRootHex string, wantSize int) []byte { + t.Helper() + enc, err := obj.EncodeSSZ(nil) + require.NoError(t, err) + root, err := obj.HashSSZ() + require.NoError(t, err) + require.Equal(t, wantEncHex, hex.EncodeToString(enc)) + require.Equal(t, wantRootHex, hex.EncodeToString(root[:])) + require.Equal(t, wantSize, obj.EncodingSizeSSZ()) + return enc +} + +func requireSSZRoundTrip(t *testing.T, dec signedContainerSSZ, enc []byte, version clparams.StateVersion, wantRootHex string) { + t.Helper() + require.NoError(t, dec.DecodeSSZ(enc, int(version))) + reenc, err := dec.EncodeSSZ(nil) + require.NoError(t, err) + require.Equal(t, enc, reenc) + root, err := dec.HashSSZ() + require.NoError(t, err) + require.Equal(t, wantRootHex, hex.EncodeToString(root[:])) +} + +func patBytes(n int, seed byte) []byte { + b := make([]byte, n) + for i := range b { + b[i] = seed + byte(i) + } + return b +} + +func patHash(seed byte) (h common.Hash) { copy(h[:], patBytes(32, seed)); return } +func patAddress(seed byte) (a common.Address) { copy(a[:], patBytes(20, seed)); return } +func patBytes48(seed byte) (b common.Bytes48) { copy(b[:], patBytes(48, seed)); return } +func patBytes96(seed byte) (b common.Bytes96) { copy(b[:], patBytes(96, seed)); return } + +func TestSignedVoluntaryExitSSZGolden(t *testing.T) { + const ( + wantEnc = "181716151413121128272625242322213132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90" + wantRoot = "f7c4afc8ffc3f698628a2d0dc77a12e6f2d3ba63bc90ac3b39053c455a5d386b" + wantSize = 112 + ) + obj := &cltypes.SignedVoluntaryExit{ + VoluntaryExit: &cltypes.VoluntaryExit{ + Epoch: 0x1112131415161718, + ValidatorIndex: 0x2122232425262728, + }, + Signature: patBytes96(0x31), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + requireSSZRoundTrip(t, &cltypes.SignedVoluntaryExit{}, enc, clparams.Phase0Version, wantRoot) +} + +func TestSignedBeaconBlockHeaderSSZGolden(t *testing.T) { + const ( + wantEnc = "080706050403020118171615141312112122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4022232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0" + wantRoot = "fc32cf8253ad44adc094412642b7f924aea4b67f988b82b1b3824f93dbee26b3" + wantSize = 208 + ) + obj := &cltypes.SignedBeaconBlockHeader{ + Header: &cltypes.BeaconBlockHeader{ + Slot: 0x0102030405060708, + ProposerIndex: 0x1112131415161718, + ParentRoot: patHash(0x21), + Root: patHash(0x22), + BodyRoot: patHash(0x23), + }, + Signature: patBytes96(0x41), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + requireSSZRoundTrip(t, &cltypes.SignedBeaconBlockHeader{}, enc, clparams.Phase0Version, wantRoot) +} + +func TestSignedBLSToExecutionChangeSSZGolden(t *testing.T) { + const ( + wantEnc = "28272625242322215152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f806162636465666768696a6b6c6d6e6f70717273747172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0" + wantRoot = "3ef1e68971de9ac8b053d6e545cab6db895d8c5d0f79751a3789ee93b03bca87" + wantSize = 172 + ) + obj := &cltypes.SignedBLSToExecutionChange{ + Message: &cltypes.BLSToExecutionChange{ + ValidatorIndex: 0x2122232425262728, + From: patBytes48(0x51), + To: patAddress(0x61), + }, + Signature: patBytes96(0x71), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + requireSSZRoundTrip(t, &cltypes.SignedBLSToExecutionChange{}, enc, clparams.CapellaVersion, wantRoot) +} + +func TestSignedContributionAndProofSSZGolden(t *testing.T) { + const ( + wantEnc = "383736353433323148474645444342418182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa00a000000000000009192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f10c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20" + wantRoot = "9baea36083648238f3584861724f5dd876209361376ac98974c259be06823f94" + wantSize = 360 + ) + obj := &cltypes.SignedContributionAndProof{ + Message: &cltypes.ContributionAndProof{ + AggregatorIndex: 0x3132333435363738, + Contribution: &cltypes.Contribution{ + Slot: 0x4142434445464748, + BeaconBlockRoot: patHash(0x81), + SubcommitteeIndex: 0x0a, + AggregationBits: patBytes(cltypes.DefaultSyncCommitteeAggregationBitsSize, 0x91), + Signature: patBytes96(0xa1), + }, + SelectionProof: patBytes96(0xb1), + }, + Signature: patBytes96(0xc1), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + requireSSZRoundTrip(t, &cltypes.SignedContributionAndProof{}, enc, clparams.AltairVersion, wantRoot) +} + +func TestSignedAggregateAndProofSSZGolden(t *testing.T) { + const ( + wantEnc = "640000003132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9058575655545352516c0000002122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80e400000068676665646362610b00000000000000d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff00c00000000000000e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000d00000000000000f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70aabbcc2d" + wantRoot = "6d149aca2f316705051778de27c1ae274b318bf9d2980430d5a3c56b35b0463e" + wantSize = 440 + ) + obj := &cltypes.SignedAggregateAndProof{ + Message: &cltypes.AggregateAndProof{ + AggregatorIndex: 0x5152535455565758, + Aggregate: &solid.Attestation{ + AggregationBits: solid.BitlistFromBytes([]byte{0xaa, 0xbb, 0xcc, 0x2d}, 2048), + Data: &solid.AttestationData{ + Slot: 0x6162636465666768, + CommitteeIndex: 0x0b, + BeaconBlockRoot: patHash(0xd1), + Source: solid.Checkpoint{Epoch: 0x0c, Root: patHash(0xe1)}, + Target: solid.Checkpoint{Epoch: 0x0d, Root: patHash(0xf1)}, + }, + Signature: patBytes96(0x11), + }, + SelectionProof: patBytes96(0x21), + }, + Signature: patBytes96(0x31), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + requireSSZRoundTrip(t, &cltypes.SignedAggregateAndProof{}, enc, clparams.DenebVersion, wantRoot) +} + +func TestSignedProposerPreferencesSSZGolden(t *testing.T) { + const ( + wantEnc = "15161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333478777675747372710e0000000000000025262728292a2b2c2d2e2f3031323334353637380f0000000000000035363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f9091929394" + wantRoot = "593a67daddfee5a7ef1ff405c073f32ff95a6f6397e3f35239100dd0ca9ad6c7" + wantSize = 172 + ) + obj := &cltypes.SignedProposerPreferences{ + Message: &cltypes.ProposerPreferences{ + DependentRoot: patHash(0x15), + ProposalSlot: 0x7172737475767778, + ValidatorIndex: 0x0e, + FeeRecipient: patAddress(0x25), + TargetGasLimit: 0x0f, + }, + Signature: patBytes96(0x35), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + requireSSZRoundTrip(t, &cltypes.SignedProposerPreferences{}, enc, clparams.GloasVersion, wantRoot) + + require.Equal(t, 96, (&cltypes.SignedProposerPreferences{}).EncodingSizeSSZ()) +} + +func TestSignedExecutionPayloadBidSSZGolden(t *testing.T) { + const ( + wantEnc = "64000000c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b888878685848382811000000000000000110000000000000012000000000000001300000000000000e0000000b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384" + wantRoot = "83f2e9dcb83b1c43e13aa7cd46c2251938cd9b2cec71e243ed97d384ef85f3d2" + wantSize = 420 + ) + commitments := solid.NewStaticListSSZ[*cltypes.KZGCommitment](cltypes.MaxBlobsCommittmentsPerBlock, 48) + var c1, c2 cltypes.KZGCommitment + copy(c1[:], patBytes(48, 0x45)) + copy(c2[:], patBytes(48, 0x55)) + commitments.Append(&c1) + commitments.Append(&c2) + obj := &cltypes.SignedExecutionPayloadBid{ + Message: &cltypes.ExecutionPayloadBid{ + ParentBlockHash: patHash(0x65), + ParentBlockRoot: patHash(0x75), + BlockHash: patHash(0x85), + PrevRandao: patHash(0x95), + FeeRecipient: patAddress(0xa5), + GasLimit: 0x8182838485868788, + BuilderIndex: 0x10, + Slot: 0x11, + Value: 0x12, + ExecutionPayment: 0x13, + BlobKzgCommitments: *commitments, + ExecutionRequestsRoot: patHash(0xb5), + }, + Signature: patBytes96(0xc5), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + requireSSZRoundTrip(t, &cltypes.SignedExecutionPayloadBid{}, enc, clparams.GloasVersion, wantRoot) +} + +func TestSignedExecutionPayloadEnvelopeSSZGolden(t *testing.T) { + const ( + wantEnc = "64000000f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545550000000b10200002000000000000000d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f1011121314161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545514000000000000001500000000000000160000000000000017000000000000001c020000565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485210200002c0200001b000000000000001c00000000000000580200001d00000000000000464748494a04000000767778797a7b7c18000000000000001900000000000000868788898a8b8c8d8e8f909192939495969798991a00000000000000969798999a9b9c9d9e0c000000cc000000cc000000a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d51e00000000000000c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324251f00000000000000" + wantRoot = "b600054b8896b2498137587aeac1f0698f5a71d3214e85bedf19ed605a4f89e4" + wantSize = 981 + ) + cfg := &clparams.MainnetBeaconConfig + + payload := cltypes.NewEth1Block(clparams.GloasVersion, cfg) + payload.ParentHash = patHash(0xd5) + payload.FeeRecipient = patAddress(0xe5) + payload.StateRoot = patHash(0xf5) + payload.ReceiptsRoot = patHash(0x16) + copy(payload.LogsBloom[:], patBytes(256, 0x26)) + payload.PrevRandao = patHash(0x36) + payload.BlockNumber = 0x14 + payload.GasLimit = 0x15 + payload.GasUsed = 0x16 + payload.Time = 0x17 + payload.Extra = solid.NewExtraData() + payload.Extra.SetBytes(patBytes(5, 0x46)) + payload.BaseFeePerGas = patHash(0x56) + payload.BlockHash = patHash(0x66) + payload.Transactions = solid.NewTransactionsSSZFromTransactions([][]byte{patBytes(7, 0x76)}) + payload.Withdrawals = solid.NewStaticListSSZ[*cltypes.Withdrawal](int(cfg.MaxWithdrawalsPerPayload), 44) + payload.Withdrawals.Append(&cltypes.Withdrawal{ + Index: 0x18, + Validator: 0x19, + Address: patAddress(0x86), + Amount: 0x1a, + }) + payload.BlobGasUsed = 0x1b + payload.ExcessBlobGas = 0x1c + require.NoError(t, payload.BlockAccessList.SetBytes(patBytes(9, 0x96))) + payload.SlotNumber = 0x1d + + requests := cltypes.NewExecutionRequests(cfg) + requests.Deposits.Append(&solid.DepositRequest{ + PubKey: patBytes48(0xa6), + WithdrawalCredentials: patHash(0xb6), + Amount: 0x1e, + Signature: patBytes96(0xc6), + Index: 0x1f, + }) + + obj := &cltypes.SignedExecutionPayloadEnvelope{ + Message: &cltypes.ExecutionPayloadEnvelope{ + Payload: payload, + ExecutionRequests: requests, + BuilderIndex: 0x20, + BeaconBlockRoot: patHash(0xd6), + ParentBeaconBlockRoot: patHash(0xe6), + }, + Signature: patBytes96(0xf6), + } + enc := requireGoldenSSZ(t, obj, wantEnc, wantRoot, wantSize) + + dec := &cltypes.SignedExecutionPayloadEnvelope{Message: cltypes.NewExecutionPayloadEnvelope(cfg)} + requireSSZRoundTrip(t, dec, enc, clparams.GloasVersion, wantRoot) +} diff --git a/cl/cltypes/validator.go b/cl/cltypes/validator.go index 90e4696a5e9..982eaf65a96 100644 --- a/cl/cltypes/validator.go +++ b/cl/cltypes/validator.go @@ -132,18 +132,18 @@ type SignedVoluntaryExit struct { } func (e *SignedVoluntaryExit) EncodeSSZ(dst []byte) ([]byte, error) { - return ssz2.MarshalSSZ(dst, e.VoluntaryExit, e.Signature[:]) + return encodeSigned(dst, e.VoluntaryExit, e.Signature[:]) } func (e *SignedVoluntaryExit) DecodeSSZ(buf []byte, version int) error { e.VoluntaryExit = new(VoluntaryExit) - return ssz2.UnmarshalSSZ(buf, version, e.VoluntaryExit, e.Signature[:]) + return decodeSigned(buf, version, e.VoluntaryExit, e.Signature[:]) } func (e *SignedVoluntaryExit) HashSSZ() ([32]byte, error) { - return merkle_tree.HashTreeRoot(e.VoluntaryExit, e.Signature[:]) + return hashSigned(e.VoluntaryExit, e.Signature[:]) } func (e *SignedVoluntaryExit) EncodingSizeSSZ() int { - return 96 + e.VoluntaryExit.EncodingSizeSSZ() + return sizeSigned(e.VoluntaryExit) } diff --git a/cl/phase1/execution_client/engine_api_rpc_client.go b/cl/phase1/execution_client/engine_api_rpc_client.go index fb63ae8d8e0..ec1444a2a40 100644 --- a/cl/phase1/execution_client/engine_api_rpc_client.go +++ b/cl/phase1/execution_client/engine_api_rpc_client.go @@ -56,186 +56,111 @@ func NewEngineAPIRPCClient(jwtSecret []byte, addr string, port int) (*EngineAPIR return &EngineAPIRPCClient{client: rpcClient}, rpcClient, nil } -func (c *EngineAPIRPCClient) NewPayloadV1(ctx context.Context, payload *engine_types.ExecutionPayload) (*engine_types.PayloadStatus, error) { - result := &engine_types.PayloadStatus{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineNewPayloadV1, payload); err != nil { +func call[T any](ctx context.Context, client *rpc.Client, method string, args ...any) (*T, error) { + result := new(T) + if err := client.CallContext(ctx, result, method, args...); err != nil { return nil, err } return result, nil } -func (c *EngineAPIRPCClient) NewPayloadV2(ctx context.Context, payload *engine_types.ExecutionPayload) (*engine_types.PayloadStatus, error) { - result := &engine_types.PayloadStatus{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineNewPayloadV2, payload); err != nil { - return nil, err +func callValue[T any](ctx context.Context, client *rpc.Client, method string, args ...any) (T, error) { + result, err := call[T](ctx, client, method, args...) + if err != nil { + var zero T + return zero, err } - return result, nil + return *result, nil +} + +func (c *EngineAPIRPCClient) NewPayloadV1(ctx context.Context, payload *engine_types.ExecutionPayload) (*engine_types.PayloadStatus, error) { + return call[engine_types.PayloadStatus](ctx, c.client, rpc_helper.EngineNewPayloadV1, payload) +} + +func (c *EngineAPIRPCClient) NewPayloadV2(ctx context.Context, payload *engine_types.ExecutionPayload) (*engine_types.PayloadStatus, error) { + return call[engine_types.PayloadStatus](ctx, c.client, rpc_helper.EngineNewPayloadV2, payload) } func (c *EngineAPIRPCClient) NewPayloadV3(ctx context.Context, payload *engine_types.ExecutionPayload, expectedBlobHashes []common.Hash, parentBeaconBlockRoot *common.Hash) (*engine_types.PayloadStatus, error) { - result := &engine_types.PayloadStatus{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineNewPayloadV3, payload, expectedBlobHashes, parentBeaconBlockRoot); err != nil { - return nil, err - } - return result, nil + return call[engine_types.PayloadStatus](ctx, c.client, rpc_helper.EngineNewPayloadV3, payload, expectedBlobHashes, parentBeaconBlockRoot) } func (c *EngineAPIRPCClient) NewPayloadV4(ctx context.Context, payload *engine_types.ExecutionPayload, expectedBlobHashes []common.Hash, parentBeaconBlockRoot *common.Hash, executionRequests []hexutil.Bytes) (*engine_types.PayloadStatus, error) { - result := &engine_types.PayloadStatus{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineNewPayloadV4, payload, expectedBlobHashes, parentBeaconBlockRoot, executionRequests); err != nil { - return nil, err - } - return result, nil + return call[engine_types.PayloadStatus](ctx, c.client, rpc_helper.EngineNewPayloadV4, payload, expectedBlobHashes, parentBeaconBlockRoot, executionRequests) } func (c *EngineAPIRPCClient) NewPayloadV5(ctx context.Context, payload *engine_types.ExecutionPayload, expectedBlobHashes []common.Hash, parentBeaconBlockRoot *common.Hash, executionRequests []hexutil.Bytes) (*engine_types.PayloadStatus, error) { - result := &engine_types.PayloadStatus{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineNewPayloadV5, payload, expectedBlobHashes, parentBeaconBlockRoot, executionRequests); err != nil { - return nil, err - } - return result, nil + return call[engine_types.PayloadStatus](ctx, c.client, rpc_helper.EngineNewPayloadV5, payload, expectedBlobHashes, parentBeaconBlockRoot, executionRequests) } func (c *EngineAPIRPCClient) ForkchoiceUpdatedV1(ctx context.Context, forkChoiceState *engine_types.ForkChoiceState, payloadAttributes *engine_types.PayloadAttributes) (*engine_types.ForkChoiceUpdatedResponse, error) { - result := &engine_types.ForkChoiceUpdatedResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.ForkChoiceUpdatedV1, forkChoiceState, payloadAttributes); err != nil { - return nil, err - } - return result, nil + return call[engine_types.ForkChoiceUpdatedResponse](ctx, c.client, rpc_helper.ForkChoiceUpdatedV1, forkChoiceState, payloadAttributes) } func (c *EngineAPIRPCClient) ForkchoiceUpdatedV2(ctx context.Context, forkChoiceState *engine_types.ForkChoiceState, payloadAttributes *engine_types.PayloadAttributes) (*engine_types.ForkChoiceUpdatedResponse, error) { - result := &engine_types.ForkChoiceUpdatedResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.ForkChoiceUpdatedV2, forkChoiceState, payloadAttributes); err != nil { - return nil, err - } - return result, nil + return call[engine_types.ForkChoiceUpdatedResponse](ctx, c.client, rpc_helper.ForkChoiceUpdatedV2, forkChoiceState, payloadAttributes) } func (c *EngineAPIRPCClient) ForkchoiceUpdatedV3(ctx context.Context, forkChoiceState *engine_types.ForkChoiceState, payloadAttributes *engine_types.PayloadAttributes) (*engine_types.ForkChoiceUpdatedResponse, error) { - result := &engine_types.ForkChoiceUpdatedResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.ForkChoiceUpdatedV3, forkChoiceState, payloadAttributes); err != nil { - return nil, err - } - return result, nil + return call[engine_types.ForkChoiceUpdatedResponse](ctx, c.client, rpc_helper.ForkChoiceUpdatedV3, forkChoiceState, payloadAttributes) } func (c *EngineAPIRPCClient) ForkchoiceUpdatedV4(ctx context.Context, forkChoiceState *engine_types.ForkChoiceState, payloadAttributes *engine_types.PayloadAttributes) (*engine_types.ForkChoiceUpdatedResponse, error) { - result := &engine_types.ForkChoiceUpdatedResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.ForkChoiceUpdatedV4, forkChoiceState, payloadAttributes); err != nil { - return nil, err - } - return result, nil + return call[engine_types.ForkChoiceUpdatedResponse](ctx, c.client, rpc_helper.ForkChoiceUpdatedV4, forkChoiceState, payloadAttributes) } func (c *EngineAPIRPCClient) GetPayloadV1(ctx context.Context, payloadID hexutil.Bytes) (*engine_types.ExecutionPayload, error) { - result := &engine_types.ExecutionPayload{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineGetPayloadV1, payloadID); err != nil { - return nil, err - } - return result, nil + return call[engine_types.ExecutionPayload](ctx, c.client, rpc_helper.EngineGetPayloadV1, payloadID) } func (c *EngineAPIRPCClient) GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*engine_types.GetPayloadResponse, error) { - result := &engine_types.GetPayloadResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineGetPayloadV2, payloadID); err != nil { - return nil, err - } - return result, nil + return call[engine_types.GetPayloadResponse](ctx, c.client, rpc_helper.EngineGetPayloadV2, payloadID) } func (c *EngineAPIRPCClient) GetPayloadV3(ctx context.Context, payloadID hexutil.Bytes) (*engine_types.GetPayloadResponse, error) { - result := &engine_types.GetPayloadResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineGetPayloadV3, payloadID); err != nil { - return nil, err - } - return result, nil + return call[engine_types.GetPayloadResponse](ctx, c.client, rpc_helper.EngineGetPayloadV3, payloadID) } func (c *EngineAPIRPCClient) GetPayloadV4(ctx context.Context, payloadID hexutil.Bytes) (*engine_types.GetPayloadResponse, error) { - result := &engine_types.GetPayloadResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineGetPayloadV4, payloadID); err != nil { - return nil, err - } - return result, nil + return call[engine_types.GetPayloadResponse](ctx, c.client, rpc_helper.EngineGetPayloadV4, payloadID) } func (c *EngineAPIRPCClient) GetPayloadV5(ctx context.Context, payloadID hexutil.Bytes) (*engine_types.GetPayloadResponse, error) { - result := &engine_types.GetPayloadResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineGetPayloadV5, payloadID); err != nil { - return nil, err - } - return result, nil + return call[engine_types.GetPayloadResponse](ctx, c.client, rpc_helper.EngineGetPayloadV5, payloadID) } func (c *EngineAPIRPCClient) GetPayloadV6(ctx context.Context, payloadID hexutil.Bytes) (*engine_types.GetPayloadResponse, error) { - result := &engine_types.GetPayloadResponse{} - if err := c.client.CallContext(ctx, result, rpc_helper.EngineGetPayloadV6, payloadID); err != nil { - return nil, err - } - return result, nil + return call[engine_types.GetPayloadResponse](ctx, c.client, rpc_helper.EngineGetPayloadV6, payloadID) } func (c *EngineAPIRPCClient) GetPayloadBodiesByHashV1(ctx context.Context, hashes []common.Hash) ([]*engine_types.ExecutionPayloadBody, error) { - var result []*engine_types.ExecutionPayloadBody - if err := c.client.CallContext(ctx, &result, rpc_helper.GetPayloadBodiesByHashV1, hashes); err != nil { - return nil, err - } - return result, nil + return callValue[[]*engine_types.ExecutionPayloadBody](ctx, c.client, rpc_helper.GetPayloadBodiesByHashV1, hashes) } func (c *EngineAPIRPCClient) GetPayloadBodiesByHashV2(ctx context.Context, hashes []common.Hash) ([]*engine_types.ExecutionPayloadBodyV2, error) { - var result []*engine_types.ExecutionPayloadBodyV2 - if err := c.client.CallContext(ctx, &result, rpc_helper.GetPayloadBodiesByHashV2, hashes); err != nil { - return nil, err - } - return result, nil + return callValue[[]*engine_types.ExecutionPayloadBodyV2](ctx, c.client, rpc_helper.GetPayloadBodiesByHashV2, hashes) } func (c *EngineAPIRPCClient) GetPayloadBodiesByRangeV1(ctx context.Context, start, count hexutil.Uint64) ([]*engine_types.ExecutionPayloadBody, error) { - var result []*engine_types.ExecutionPayloadBody - if err := c.client.CallContext(ctx, &result, rpc_helper.GetPayloadBodiesByRangeV1, start, count); err != nil { - return nil, err - } - return result, nil + return callValue[[]*engine_types.ExecutionPayloadBody](ctx, c.client, rpc_helper.GetPayloadBodiesByRangeV1, start, count) } func (c *EngineAPIRPCClient) GetPayloadBodiesByRangeV2(ctx context.Context, start, count hexutil.Uint64) ([]*engine_types.ExecutionPayloadBodyV2, error) { - var result []*engine_types.ExecutionPayloadBodyV2 - if err := c.client.CallContext(ctx, &result, rpc_helper.GetPayloadBodiesByRangeV2, start, count); err != nil { - return nil, err - } - return result, nil + return callValue[[]*engine_types.ExecutionPayloadBodyV2](ctx, c.client, rpc_helper.GetPayloadBodiesByRangeV2, start, count) } func (c *EngineAPIRPCClient) GetClientVersionV1(ctx context.Context, callerVersion *engine_types.ClientVersionV1) ([]engine_types.ClientVersionV1, error) { - var result []engine_types.ClientVersionV1 - if err := c.client.CallContext(ctx, &result, rpc_helper.EngineGetClientVersionV1, callerVersion); err != nil { - return nil, err - } - return result, nil + return callValue[[]engine_types.ClientVersionV1](ctx, c.client, rpc_helper.EngineGetClientVersionV1, callerVersion) } func (c *EngineAPIRPCClient) GetBlobsV1(ctx context.Context, blobHashes []common.Hash) (engine_types.BlobsBundleV1, error) { - var result engine_types.BlobsBundleV1 - if err := c.client.CallContext(ctx, &result, rpc_helper.EngineGetBlobsV1, blobHashes); err != nil { - return nil, err - } - return result, nil + return callValue[engine_types.BlobsBundleV1](ctx, c.client, rpc_helper.EngineGetBlobsV1, blobHashes) } func (c *EngineAPIRPCClient) GetBlobsV2(ctx context.Context, blobHashes []common.Hash) (engine_types.BlobsBundleV2, error) { - var result engine_types.BlobsBundleV2 - if err := c.client.CallContext(ctx, &result, rpc_helper.EngineGetBlobsV2, blobHashes); err != nil { - return nil, err - } - return result, nil + return callValue[engine_types.BlobsBundleV2](ctx, c.client, rpc_helper.EngineGetBlobsV2, blobHashes) } func (c *EngineAPIRPCClient) GetBlobsV3(ctx context.Context, blobHashes []common.Hash) (engine_types.BlobsBundleV2, error) { - var result engine_types.BlobsBundleV2 - if err := c.client.CallContext(ctx, &result, rpc_helper.EngineGetBlobsV3, blobHashes); err != nil { - return nil, err - } - return result, nil + return callValue[engine_types.BlobsBundleV2](ctx, c.client, rpc_helper.EngineGetBlobsV3, blobHashes) } diff --git a/cl/phase1/execution_client/execution_client_engine.go b/cl/phase1/execution_client/execution_client_engine.go index a74bade6a73..40f04ec3909 100644 --- a/cl/phase1/execution_client/execution_client_engine.go +++ b/cl/phase1/execution_client/execution_client_engine.go @@ -370,11 +370,11 @@ func (cc *ExecutionClientEngine) GetAssembledBlock(ctx context.Context, id []byt // Select Engine API version based on CL state version. switch { case version >= clparams.GloasVersion: - return cc.getAssembledBlockV6(ctx, id, version) + return cc.getAssembledBlockFromEngine(ctx, id, version, "GetPayloadV6", cc.engine.GetPayloadV6) case version >= clparams.FuluVersion: - return cc.getAssembledBlockV5(ctx, id, version) + return cc.getAssembledBlockFromEngine(ctx, id, version, "GetPayloadV5", cc.engine.GetPayloadV5) case version >= clparams.ElectraVersion: - return cc.getAssembledBlockV4(ctx, id, version) + return cc.getAssembledBlockFromEngine(ctx, id, version, "GetPayloadV4", cc.engine.GetPayloadV4) default: return cc.getAssembledBlockV3(ctx, id, version) } @@ -437,26 +437,10 @@ func (cc *ExecutionClientEngine) getAssembledBlockFromResponse(resp *engine_type return block, resp.BlobsBundle, requestsBundle, blockValue, nil } -func (cc *ExecutionClientEngine) getAssembledBlockV4(ctx context.Context, id []byte, version clparams.StateVersion) (*cltypes.Eth1Block, *engine_types.BlobsBundle, *typesproto.RequestsBundle, *big.Int, error) { - resp, err := cc.engine.GetPayloadV4(ctx, hexutil.Bytes(id)) +func (cc *ExecutionClientEngine) getAssembledBlockFromEngine(ctx context.Context, id []byte, version clparams.StateVersion, methodName string, getPayload func(context.Context, hexutil.Bytes) (*engine_types.GetPayloadResponse, error)) (*cltypes.Eth1Block, *engine_types.BlobsBundle, *typesproto.RequestsBundle, *big.Int, error) { + resp, err := getPayload(ctx, hexutil.Bytes(id)) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("engine GetPayloadV4 failed: %w", err) - } - return cc.getAssembledBlockFromResponse(resp, version) -} - -func (cc *ExecutionClientEngine) getAssembledBlockV5(ctx context.Context, id []byte, version clparams.StateVersion) (*cltypes.Eth1Block, *engine_types.BlobsBundle, *typesproto.RequestsBundle, *big.Int, error) { - resp, err := cc.engine.GetPayloadV5(ctx, hexutil.Bytes(id)) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("engine GetPayloadV5 failed: %w", err) - } - return cc.getAssembledBlockFromResponse(resp, version) -} - -func (cc *ExecutionClientEngine) getAssembledBlockV6(ctx context.Context, id []byte, version clparams.StateVersion) (*cltypes.Eth1Block, *engine_types.BlobsBundle, *typesproto.RequestsBundle, *big.Int, error) { - resp, err := cc.engine.GetPayloadV6(ctx, hexutil.Bytes(id)) - if err != nil { - return nil, nil, nil, nil, fmt.Errorf("engine GetPayloadV6 failed: %w", err) + return nil, nil, nil, nil, fmt.Errorf("engine %s failed: %w", methodName, err) } return cc.getAssembledBlockFromResponse(resp, version) }