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)
}