From be3c616d3cf6a12fd84da59a9dc868d44fc178c2 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Thu, 25 Apr 2024 16:09:35 -0700 Subject: [PATCH] Add ePBS to state --- beacon-chain/state/BUILD.bazel | 1 + beacon-chain/state/interfaces.go | 2 + beacon-chain/state/interfaces_epbs.go | 28 ++++ beacon-chain/state/state-native/BUILD.bazel | 8 + .../state-native/beacon_state_mainnet.go | 9 ++ .../state-native/beacon_state_minimal.go | 9 ++ .../state/state-native/getters_epbs.go | 122 ++++++++++++++ .../state-native/getters_payload_header.go | 2 +- .../getters_payload_header_epbs.go | 10 ++ .../state-native/getters_setters_epbs_test.go | 149 ++++++++++++++++++ .../state/state-native/getters_state.go | 79 ++++++++++ beacon-chain/state/state-native/hasher.go | 41 +++++ .../state/state-native/setters_epbs.go | 111 +++++++++++++ .../state-native/setters_payload_header.go | 2 +- .../state/state-native/spec_parameters.go | 4 +- beacon-chain/state/state-native/state_trie.go | 66 +++++++- .../state/state-native/state_trie_epbs.go | 139 ++++++++++++++++ .../state-native/state_trie_epbs_test.go | 86 ++++++++++ .../state/state-native/types/types.go | 41 ++++- beacon-chain/state/stateutil/trie_helpers.go | 4 +- config/params/config.go | 1 + config/params/mainnet_config.go | 1 + proto/prysm/v1alpha1/beacon_state.pb.go | 6 +- proto/prysm/v1alpha1/beacon_state.proto | 2 +- testing/util/BUILD.bazel | 1 - testing/util/payload_attestation.go | 45 ------ testing/util/random/BUILD.bazel | 14 ++ testing/util/random/epbs.go | 134 ++++++++++++++++ validator/client/BUILD.bazel | 1 + validator/client/payload_attestation_test.go | 4 +- 30 files changed, 1058 insertions(+), 64 deletions(-) create mode 100644 beacon-chain/state/interfaces_epbs.go create mode 100644 beacon-chain/state/state-native/getters_epbs.go create mode 100644 beacon-chain/state/state-native/getters_payload_header_epbs.go create mode 100644 beacon-chain/state/state-native/getters_setters_epbs_test.go create mode 100644 beacon-chain/state/state-native/setters_epbs.go create mode 100644 beacon-chain/state/state-native/state_trie_epbs.go create mode 100644 beacon-chain/state/state-native/state_trie_epbs_test.go delete mode 100644 testing/util/payload_attestation.go create mode 100644 testing/util/random/BUILD.bazel create mode 100644 testing/util/random/epbs.go diff --git a/beacon-chain/state/BUILD.bazel b/beacon-chain/state/BUILD.bazel index fa1ee84cff41..415e3ab05689 100644 --- a/beacon-chain/state/BUILD.bazel +++ b/beacon-chain/state/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "error.go", "interfaces.go", + "interfaces_epbs.go", "prometheus.go", ], importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/state", diff --git a/beacon-chain/state/interfaces.go b/beacon-chain/state/interfaces.go index 0a6a92a27772..f2ea16df0ae2 100644 --- a/beacon-chain/state/interfaces.go +++ b/beacon-chain/state/interfaces.go @@ -56,6 +56,7 @@ type ReadOnlyBeaconState interface { ReadOnlyParticipation ReadOnlyInactivity ReadOnlySyncCommittee + ReadOnlyEpbs ToProtoUnsafe() interface{} ToProto() interface{} GenesisTime() uint64 @@ -87,6 +88,7 @@ type WriteOnlyBeaconState interface { WriteOnlyParticipation WriteOnlyInactivity WriteOnlySyncCommittee + WriteOnlyEpbs SetGenesisTime(val uint64) error SetGenesisValidatorsRoot(val []byte) error SetSlot(val primitives.Slot) error diff --git a/beacon-chain/state/interfaces_epbs.go b/beacon-chain/state/interfaces_epbs.go new file mode 100644 index 000000000000..6193a97362ce --- /dev/null +++ b/beacon-chain/state/interfaces_epbs.go @@ -0,0 +1,28 @@ +package state + +import ( + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" +) + +type ReadOnlyEpbs interface { + PreviousInclusionListSlot() (primitives.Slot, error) + PreviousInclusionListProposer() (primitives.ValidatorIndex, error) + LatestInclusionListSlot() (primitives.Slot, error) + LatestInclusionListProposer() (primitives.ValidatorIndex, error) + IsParentBlockFull() (bool, error) + ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeaderEPBS, error) + LatestBlockHash() ([]byte, error) + LatestFullSlot() (primitives.Slot, error) + LastWithdrawalsRoot() ([]byte, error) +} + +type WriteOnlyEpbs interface { + SetExecutionPayloadHeader(val *enginev1.ExecutionPayloadHeaderEPBS) error + UpdatePreviousInclusionListData() error + SetLatestInclusionListSlot(val primitives.Slot) error + SetLatestInclusionListProposer(val primitives.ValidatorIndex) error + SetLatestBlockHash(val []byte) error + SetLatestFullSlot(val primitives.Slot) error + SetLastWithdrawalsRoot(val []byte) error +} diff --git a/beacon-chain/state/state-native/BUILD.bazel b/beacon-chain/state/state-native/BUILD.bazel index 41f9f60c6441..966525fd6268 100644 --- a/beacon-chain/state/state-native/BUILD.bazel +++ b/beacon-chain/state/state-native/BUILD.bazel @@ -8,10 +8,12 @@ go_library( "getters_attestation.go", "getters_block.go", "getters_checkpoint.go", + "getters_epbs.go", "getters_eth1.go", "getters_misc.go", "getters_participation.go", "getters_payload_header.go", + "getters_payload_header_epbs.go", "getters_randao.go", "getters_state.go", "getters_sync_committee.go", @@ -24,6 +26,7 @@ go_library( "setters_attestation.go", "setters_block.go", "setters_checkpoint.go", + "setters_epbs.go", "setters_eth1.go", "setters_misc.go", "setters_participation.go", @@ -36,6 +39,7 @@ go_library( "spec_parameters.go", "ssz.go", "state_trie.go", + "state_trie_epbs.go", "types.go", ] + select({ "//config:mainnet": ["beacon_state_mainnet.go"], @@ -84,6 +88,7 @@ go_test( "getters_block_test.go", "getters_checkpoint_test.go", "getters_participation_test.go", + "getters_setters_epbs_test.go", "getters_test.go", "getters_validator_test.go", "getters_withdrawal_test.go", @@ -100,6 +105,7 @@ go_test( "setters_withdrawal_test.go", "state_fuzz_test.go", "state_test.go", + "state_trie_epbs_test.go", "state_trie_test.go", "types_test.go", ], @@ -114,6 +120,7 @@ go_test( "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", + "//consensus-types:go_default_library", "//consensus-types/blocks:go_default_library", "//consensus-types/primitives:go_default_library", "//container/trie:go_default_library", @@ -126,6 +133,7 @@ go_test( "//testing/assert:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", + "//testing/util/random:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", diff --git a/beacon-chain/state/state-native/beacon_state_mainnet.go b/beacon-chain/state/state-native/beacon_state_mainnet.go index 95eff14bf1fc..dc1422f02a1d 100644 --- a/beacon-chain/state/state-native/beacon_state_mainnet.go +++ b/beacon-chain/state/state-native/beacon_state_mainnet.go @@ -59,6 +59,15 @@ type BeaconState struct { latestExecutionPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb nextWithdrawalIndex uint64 nextWithdrawalValidatorIndex primitives.ValidatorIndex + // ePBS fields + previousInclusionListProposer primitives.ValidatorIndex + previousInclusionListSlot primitives.Slot + latestInclusionListProposer primitives.ValidatorIndex + latestInclusionListSlot primitives.Slot + latestBlockHash [32]byte + latestFullSlot primitives.Slot + executionPayloadHeader *enginev1.ExecutionPayloadHeaderEPBS + lastWithdrawalsRoot [32]byte id uint64 lock sync.RWMutex diff --git a/beacon-chain/state/state-native/beacon_state_minimal.go b/beacon-chain/state/state-native/beacon_state_minimal.go index efddb8d5688e..5b78ffd64dfa 100644 --- a/beacon-chain/state/state-native/beacon_state_minimal.go +++ b/beacon-chain/state/state-native/beacon_state_minimal.go @@ -59,6 +59,15 @@ type BeaconState struct { latestExecutionPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb nextWithdrawalIndex uint64 nextWithdrawalValidatorIndex primitives.ValidatorIndex + // ePBS fields + previousInclusionListProposer primitives.ValidatorIndex + previousInclusionListSlot primitives.Slot + latestInclusionListProposer primitives.ValidatorIndex + latestInclusionListSlot primitives.Slot + latestBlockHash [32]byte + latestFullSlot primitives.Slot + executionPayloadHeader *enginev1.ExecutionPayloadHeaderEPBS + lastWithdrawalsRoot [32]byte id uint64 lock sync.RWMutex diff --git a/beacon-chain/state/state-native/getters_epbs.go b/beacon-chain/state/state-native/getters_epbs.go new file mode 100644 index 000000000000..11fbee3e6481 --- /dev/null +++ b/beacon-chain/state/state-native/getters_epbs.go @@ -0,0 +1,122 @@ +package state_native + +import ( + "github.com/pkg/errors" + consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" +) + +// ExecutionPayloadHeader retrieves a copy of the execution payload header. +// It returns an error if the operation is not supported for the beacon state's version. +func (b *BeaconState) ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeaderEPBS, error) { + if b.version < version.EPBS { + return nil, errors.Wrapf(consensus_types.ErrUnsupportedField, "ExecutionPayloadHeader not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.executionPayloadHeaderVal(), nil +} + +// IsParentBlockFull checks if the last committed payload header was fulfilled. +// Returns true if both the beacon block and payload were present. +// Call this function on a beacon state before processing the execution payload header. +func (b *BeaconState) IsParentBlockFull() (bool, error) { + if b.version < version.EPBS { + return false, errors.Wrapf(consensus_types.ErrUnsupportedField, "IsParentBlockFull not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + headerBlockHash := bytesutil.ToBytes32(b.executionPayloadHeader.BlockHash) + return headerBlockHash == b.latestBlockHash, nil +} + +// LatestInclusionListProposer returns the proposer index from the latest inclusion list. +func (b *BeaconState) LatestInclusionListProposer() (primitives.ValidatorIndex, error) { + if b.version < version.EPBS { + return 0, errors.Wrapf(consensus_types.ErrUnsupportedField, "LatestInclusionListProposer not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.latestInclusionListProposer, nil +} + +// LatestInclusionListSlot returns the slot from the latest inclusion list. +func (b *BeaconState) LatestInclusionListSlot() (primitives.Slot, error) { + if b.version < version.EPBS { + return 0, errors.Wrapf(consensus_types.ErrUnsupportedField, "LatestInclusionListSlot not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.latestInclusionListSlot, nil +} + +// PreviousInclusionListProposer returns the proposer index from the previous inclusion list. +func (b *BeaconState) PreviousInclusionListProposer() (primitives.ValidatorIndex, error) { + if b.version < version.EPBS { + return 0, errors.Wrapf(consensus_types.ErrUnsupportedField, "PreviousInclusionListProposer not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.previousInclusionListProposer, nil +} + +// PreviousInclusionListSlot returns the slot from the previous inclusion list. +func (b *BeaconState) PreviousInclusionListSlot() (primitives.Slot, error) { + if b.version < version.EPBS { + return 0, errors.Wrapf(consensus_types.ErrUnsupportedField, "PreviousInclusionListSlot not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.previousInclusionListSlot, nil +} + +// LatestBlockHash returns the latest block hash. +func (b *BeaconState) LatestBlockHash() ([]byte, error) { + if b.version < version.EPBS { + return nil, errors.Wrapf(consensus_types.ErrUnsupportedField, "LatestBlockHash not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.latestBlockHash[:], nil +} + +// LatestFullSlot returns the slot of the latest full block. +func (b *BeaconState) LatestFullSlot() (primitives.Slot, error) { + if b.version < version.EPBS { + return 0, errors.Wrapf(consensus_types.ErrUnsupportedField, "LatestFullSlot not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.latestFullSlot, nil +} + +// LastWithdrawalsRoot returns the latest withdrawal root. +func (b *BeaconState) LastWithdrawalsRoot() ([]byte, error) { + if b.version < version.EPBS { + return nil, errors.Wrapf(consensus_types.ErrUnsupportedField, "LastWithdrawalsRoot not supported for version: %d", b.version) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.lastWithdrawalsRoot[:], nil +} diff --git a/beacon-chain/state/state-native/getters_payload_header.go b/beacon-chain/state/state-native/getters_payload_header.go index 74feadca17df..24b175f0a4a8 100644 --- a/beacon-chain/state/state-native/getters_payload_header.go +++ b/beacon-chain/state/state-native/getters_payload_header.go @@ -12,7 +12,7 @@ import ( // LatestExecutionPayloadHeader of the beacon state. func (b *BeaconState) LatestExecutionPayloadHeader() (interfaces.ExecutionData, error) { - if b.version < version.Bellatrix { + if b.version < version.Bellatrix || b.version >= version.EPBS { return nil, errNotSupported("LatestExecutionPayloadHeader", b.version) } diff --git a/beacon-chain/state/state-native/getters_payload_header_epbs.go b/beacon-chain/state/state-native/getters_payload_header_epbs.go new file mode 100644 index 000000000000..280336260ec3 --- /dev/null +++ b/beacon-chain/state/state-native/getters_payload_header_epbs.go @@ -0,0 +1,10 @@ +package state_native + +import ( + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" +) + +func (b *BeaconState) executionPayloadHeaderVal() *enginev1.ExecutionPayloadHeaderEPBS { + return eth.CopyExecutionPayloadHeaderEPBS(b.executionPayloadHeader) +} diff --git a/beacon-chain/state/state-native/getters_setters_epbs_test.go b/beacon-chain/state/state-native/getters_setters_epbs_test.go new file mode 100644 index 000000000000..e2655ed1e3e6 --- /dev/null +++ b/beacon-chain/state/state-native/getters_setters_epbs_test.go @@ -0,0 +1,149 @@ +package state_native + +import ( + "crypto/rand" + "testing" + + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" + consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/runtime/version" + "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/util/random" +) + +func Test_LatestExecutionPayloadHeader(t *testing.T) { + s := &BeaconState{version: version.EPBS} + _, err := s.LatestExecutionPayloadHeader() + require.ErrorContains(t, "LatestExecutionPayloadHeader is not supported for epbs", err) +} + +func Test_SetLatestExecutionPayloadHeader(t *testing.T) { + s := &BeaconState{version: version.EPBS} + require.ErrorContains(t, "SetLatestExecutionPayloadHeader is not supported for epbs", s.SetLatestExecutionPayloadHeader(nil)) +} + +func Test_SetExecutionPayloadHeader(t *testing.T) { + s := &BeaconState{version: version.Deneb} + require.ErrorIs(t, s.SetExecutionPayloadHeader(nil), consensus_types.ErrUnsupportedField) + _, err := s.ExecutionPayloadHeader() + require.ErrorIs(t, err, consensus_types.ErrUnsupportedField) + + s = &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)} + header := random.ExecutionPayloadHeader(t) + require.NoError(t, s.SetExecutionPayloadHeader(header)) + require.Equal(t, true, s.dirtyFields[types.ExecutionPayloadHeader]) + + got, err := s.ExecutionPayloadHeader() + require.NoError(t, err) + require.DeepEqual(t, got, header) +} + +func Test_UpdatePreviousInclusionListData(t *testing.T) { + s := &BeaconState{version: version.Deneb} + require.ErrorIs(t, s.UpdatePreviousInclusionListData(), consensus_types.ErrUnsupportedField) + + s = &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)} + + p, err := s.PreviousInclusionListProposer() + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(0), p) + ss, err := s.PreviousInclusionListSlot() + require.NoError(t, err) + require.Equal(t, primitives.Slot(0), ss) + + require.NoError(t, s.SetLatestInclusionListProposer(1)) + require.NoError(t, s.SetLatestInclusionListSlot(2)) + require.NoError(t, s.UpdatePreviousInclusionListData()) + require.Equal(t, true, s.dirtyFields[types.PreviousInclusionListProposer]) + require.Equal(t, true, s.dirtyFields[types.PreviousInclusionListSlot]) + + p, err = s.PreviousInclusionListProposer() + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(1), p) + ss, err = s.PreviousInclusionListSlot() + require.NoError(t, err) + require.Equal(t, primitives.Slot(2), ss) +} + +func Test_SetLatestInclusionListProposer(t *testing.T) { + s := &BeaconState{version: version.Deneb} + require.ErrorIs(t, s.SetLatestInclusionListProposer(0), consensus_types.ErrUnsupportedField) + _, err := s.LatestInclusionListProposer() + require.ErrorIs(t, err, consensus_types.ErrUnsupportedField) + + s = &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)} + require.NoError(t, s.SetLatestInclusionListProposer(1)) + require.Equal(t, true, s.dirtyFields[types.LatestInclusionListProposer]) + + got, err := s.LatestInclusionListProposer() + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(1), got) +} + +func Test_SetLatestInclusionListSlot(t *testing.T) { + s := &BeaconState{version: version.Deneb} + require.ErrorIs(t, s.SetLatestInclusionListSlot(0), consensus_types.ErrUnsupportedField) + _, err := s.LatestInclusionListSlot() + require.ErrorIs(t, err, consensus_types.ErrUnsupportedField) + + s = &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)} + require.NoError(t, s.SetLatestInclusionListSlot(2)) + require.Equal(t, true, s.dirtyFields[types.LatestInclusionListSlot]) + + got, err := s.LatestInclusionListSlot() + require.NoError(t, err) + require.Equal(t, primitives.Slot(2), got) +} + +func Test_SetLatestBlockHash(t *testing.T) { + s := &BeaconState{version: version.Deneb} + require.ErrorIs(t, s.SetLatestBlockHash(nil), consensus_types.ErrUnsupportedField) + _, err := s.LatestBlockHash() + require.ErrorIs(t, err, consensus_types.ErrUnsupportedField) + + s = &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)} + b := make([]byte, fieldparams.RootLength) + _, err = rand.Read(b) + require.NoError(t, err) + require.NoError(t, s.SetLatestBlockHash(b)) + require.Equal(t, true, s.dirtyFields[types.LatestBlockHash]) + + got, err := s.LatestBlockHash() + require.NoError(t, err) + require.DeepEqual(t, got, b) +} + +func Test_SetLatestFullSlot(t *testing.T) { + s := &BeaconState{version: version.Deneb} + require.ErrorIs(t, s.SetLatestFullSlot(0), consensus_types.ErrUnsupportedField) + _, err := s.LatestFullSlot() + require.ErrorIs(t, err, consensus_types.ErrUnsupportedField) + + s = &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)} + require.NoError(t, s.SetLatestFullSlot(3)) + require.Equal(t, true, s.dirtyFields[types.LatestFullSlot]) + + got, err := s.LatestFullSlot() + require.NoError(t, err) + require.Equal(t, primitives.Slot(3), got) +} + +func Test_SetLastWithdrawalsRoot(t *testing.T) { + s := &BeaconState{version: version.Deneb} + require.ErrorIs(t, s.SetLastWithdrawalsRoot(nil), consensus_types.ErrUnsupportedField) + _, err := s.LastWithdrawalsRoot() + require.ErrorIs(t, err, consensus_types.ErrUnsupportedField) + + s = &BeaconState{version: version.EPBS, dirtyFields: make(map[types.FieldIndex]bool)} + b := make([]byte, fieldparams.RootLength) + _, err = rand.Read(b) + require.NoError(t, err) + require.NoError(t, s.SetLastWithdrawalsRoot(b)) + require.Equal(t, true, s.dirtyFields[types.LastWithdrawalsRoot]) + + got, err := s.LastWithdrawalsRoot() + require.NoError(t, err) + require.DeepEqual(t, got, b) +} diff --git a/beacon-chain/state/state-native/getters_state.go b/beacon-chain/state/state-native/getters_state.go index c8f9c4aa7b16..ce141416e6e4 100644 --- a/beacon-chain/state/state-native/getters_state.go +++ b/beacon-chain/state/state-native/getters_state.go @@ -172,6 +172,44 @@ func (b *BeaconState) ToProtoUnsafe() interface{} { NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex, HistoricalSummaries: b.historicalSummaries, } + case version.EPBS: + return ðpb.BeaconStateEPBS{ + GenesisTime: b.genesisTime, + GenesisValidatorsRoot: gvrCopy[:], + Slot: b.slot, + Fork: b.fork, + LatestBlockHeader: b.latestBlockHeader, + BlockRoots: br, + StateRoots: sr, + HistoricalRoots: b.historicalRoots.Slice(), + Eth1Data: b.eth1Data, + Eth1DataVotes: b.eth1DataVotes, + Eth1DepositIndex: b.eth1DepositIndex, + Validators: vals, + Balances: bals, + RandaoMixes: rm, + Slashings: b.slashings, + PreviousEpochParticipation: b.previousEpochParticipation, + CurrentEpochParticipation: b.currentEpochParticipation, + JustificationBits: b.justificationBits, + PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint, + CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint, + FinalizedCheckpoint: b.finalizedCheckpoint, + InactivityScores: b.inactivityScoresVal(), + CurrentSyncCommittee: b.currentSyncCommittee, + NextSyncCommittee: b.nextSyncCommittee, + NextWithdrawalIndex: b.nextWithdrawalIndex, + NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex, + HistoricalSummaries: b.historicalSummaries, + PreviousInclusionListProposer: b.previousInclusionListProposer, + PreviousInclusionListSlot: b.previousInclusionListSlot, + LatestInclusionListProposer: b.latestInclusionListProposer, + LatestInclusionListSlot: b.latestInclusionListSlot, + LatestBlockHash: b.latestBlockHash[:], + LatestFullSlot: b.latestFullSlot, + ExecutionPayloadHeader: b.executionPayloadHeader, + LastWithdrawalsRoot: b.lastWithdrawalsRoot[:], + } default: return nil } @@ -196,6 +234,9 @@ func (b *BeaconState) ToProto() interface{} { inactivityScores = b.inactivityScoresVal() } + LatestBlockHashCopy := b.latestBlockHash + lastWithdrawalsRootCopy := b.lastWithdrawalsRoot + switch b.version { case version.Phase0: return ðpb.BeaconState{ @@ -338,6 +379,44 @@ func (b *BeaconState) ToProto() interface{} { NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex, HistoricalSummaries: b.historicalSummariesVal(), } + case version.EPBS: + return ðpb.BeaconStateEPBS{ + GenesisTime: b.genesisTime, + GenesisValidatorsRoot: gvrCopy[:], + Slot: b.slot, + Fork: b.forkVal(), + LatestBlockHeader: b.latestBlockHeaderVal(), + BlockRoots: br, + StateRoots: sr, + HistoricalRoots: b.historicalRoots.Slice(), + Eth1Data: b.eth1DataVal(), + Eth1DataVotes: b.eth1DataVotesVal(), + Eth1DepositIndex: b.eth1DepositIndex, + Validators: b.validatorsVal(), + Balances: b.balancesVal(), + RandaoMixes: rm, + Slashings: b.slashingsVal(), + PreviousEpochParticipation: b.previousEpochParticipationVal(), + CurrentEpochParticipation: b.currentEpochParticipationVal(), + JustificationBits: b.justificationBitsVal(), + PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(), + CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(), + FinalizedCheckpoint: b.finalizedCheckpointVal(), + InactivityScores: b.inactivityScoresVal(), + CurrentSyncCommittee: b.currentSyncCommitteeVal(), + NextSyncCommittee: b.nextSyncCommitteeVal(), + NextWithdrawalIndex: b.nextWithdrawalIndex, + NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex, + HistoricalSummaries: b.historicalSummariesVal(), + PreviousInclusionListProposer: b.previousInclusionListProposer, + PreviousInclusionListSlot: b.previousInclusionListSlot, + LatestInclusionListProposer: b.latestInclusionListProposer, + LatestInclusionListSlot: b.latestInclusionListSlot, + LatestBlockHash: LatestBlockHashCopy[:], + LatestFullSlot: b.latestFullSlot, + ExecutionPayloadHeader: b.executionPayloadHeaderVal(), + LastWithdrawalsRoot: lastWithdrawalsRootCopy[:], + } default: return nil } diff --git a/beacon-chain/state/state-native/hasher.go b/beacon-chain/state/state-native/hasher.go index eaf3235949f0..489d6aaa3e51 100644 --- a/beacon-chain/state/state-native/hasher.go +++ b/beacon-chain/state/state-native/hasher.go @@ -38,6 +38,8 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateCapellaFieldCount) case version.Deneb: fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateDenebFieldCount) + case version.EPBS: + fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateEpbsFieldCount) } // Genesis time root. @@ -247,6 +249,15 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b fieldRoots[types.LatestExecutionPayloadHeaderDeneb.RealPosition()] = executionPayloadRoot[:] } + if state.version == version.EPBS { + // Execution payload header root. + executionPayloadRoot, err := state.executionPayloadHeader.HashTreeRoot() + if err != nil { + return nil, err + } + fieldRoots[types.ExecutionPayloadHeader.RealPosition()] = executionPayloadRoot[:] + } + if state.version >= version.Capella { // Next withdrawal index root. nextWithdrawalIndexRoot := make([]byte, 32) @@ -266,5 +277,35 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b fieldRoots[types.HistoricalSummaries.RealPosition()] = historicalSummaryRoot[:] } + if state.version >= version.EPBS { + // Previous inclusion list proposer root. + prevInclusionListProposerRoot := ssz.Uint64Root(uint64(state.previousInclusionListProposer)) + fieldRoots[types.PreviousInclusionListProposer.RealPosition()] = prevInclusionListProposerRoot[:] + + // Previous inclusion list slot root. + prevInclusionListSlotRoot := ssz.Uint64Root(uint64(state.previousInclusionListSlot)) + fieldRoots[types.PreviousInclusionListSlot.RealPosition()] = prevInclusionListSlotRoot[:] + + // Latest inclusion list proposer root. + latestInclusionListProposerRoot := ssz.Uint64Root(uint64(state.latestInclusionListProposer)) + fieldRoots[types.LatestInclusionListProposer.RealPosition()] = latestInclusionListProposerRoot[:] + + // Latest inclusion list slot root. + latestInclusionListSlotRoot := ssz.Uint64Root(uint64(state.latestInclusionListSlot)) + fieldRoots[types.LatestInclusionListSlot.RealPosition()] = latestInclusionListSlotRoot[:] + + // Latest block hash root. + latestBlockHashRoot := state.latestBlockHash[:] + fieldRoots[types.LatestBlockHash.RealPosition()] = latestBlockHashRoot + + // Latest full slot root. + latestFullSlotRoot := ssz.Uint64Root(uint64(state.latestFullSlot)) + fieldRoots[types.LatestFullSlot.RealPosition()] = latestFullSlotRoot[:] + + // Last withdrawals root. + lastWithdrawalsRoot := state.lastWithdrawalsRoot[:] + fieldRoots[types.LastWithdrawalsRoot.RealPosition()] = lastWithdrawalsRoot + } + return fieldRoots, nil } diff --git a/beacon-chain/state/state-native/setters_epbs.go b/beacon-chain/state/state-native/setters_epbs.go new file mode 100644 index 000000000000..eb4ca5d73538 --- /dev/null +++ b/beacon-chain/state/state-native/setters_epbs.go @@ -0,0 +1,111 @@ +package state_native + +import ( + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types" + consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" +) + +// SetExecutionPayloadHeader sets the execution payload header for the beacon state. +func (b *BeaconState) SetExecutionPayloadHeader(h *enginev1.ExecutionPayloadHeaderEPBS) error { + if b.version < version.EPBS { + return errors.Wrapf(consensus_types.ErrUnsupportedField, "SetExecutionPayloadHeader not supported for version: %d", b.version) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.executionPayloadHeader = h + b.markFieldAsDirty(types.ExecutionPayloadHeader) + return nil +} + +// UpdatePreviousInclusionListData updates the data of previous inclusion list with latest values. +func (b *BeaconState) UpdatePreviousInclusionListData() error { + if b.version < version.EPBS { + return errors.Wrapf(consensus_types.ErrUnsupportedField, "UpdatePreviousInclusionListData not supported for version: %d", b.version) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.previousInclusionListProposer = b.latestInclusionListProposer + b.previousInclusionListSlot = b.latestInclusionListSlot + b.markFieldAsDirty(types.PreviousInclusionListProposer) + b.markFieldAsDirty(types.PreviousInclusionListSlot) + return nil +} + +// SetLatestInclusionListProposer sets the latest inclusion list proposer for the beacon state. +func (b *BeaconState) SetLatestInclusionListProposer(i primitives.ValidatorIndex) error { + if b.version < version.EPBS { + return errors.Wrapf(consensus_types.ErrUnsupportedField, "SetLatestInclusionListProposer not supported for version: %d", b.version) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.latestInclusionListProposer = i + b.markFieldAsDirty(types.LatestInclusionListProposer) + return nil +} + +// SetLatestInclusionListSlot sets the latest inclusion list slot for the beacon state. +func (b *BeaconState) SetLatestInclusionListSlot(s primitives.Slot) error { + if b.version < version.EPBS { + return errors.Wrapf(consensus_types.ErrUnsupportedField, "SetLatestInclusionListSlot not supported for version: %d", b.version) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.latestInclusionListSlot = s + b.markFieldAsDirty(types.LatestInclusionListSlot) + return nil +} + +// SetLatestBlockHash sets the latest block hash for the beacon state. +func (b *BeaconState) SetLatestBlockHash(h []byte) error { + if b.version < version.EPBS { + return errors.Wrapf(consensus_types.ErrUnsupportedField, "SetLatestBlockHash not supported for version: %d", b.version) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.latestBlockHash = bytesutil.ToBytes32(h) + b.markFieldAsDirty(types.LatestBlockHash) + return nil +} + +// SetLatestFullSlot sets the latest full slot for the beacon state. +func (b *BeaconState) SetLatestFullSlot(s primitives.Slot) error { + if b.version < version.EPBS { + return errors.Wrapf(consensus_types.ErrUnsupportedField, "SetLatestFullSlot not supported for version: %d", b.version) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.latestFullSlot = s + b.markFieldAsDirty(types.LatestFullSlot) + return nil +} + +// SetLastWithdrawalsRoot sets the latest withdrawals root for the beacon state. +func (b *BeaconState) SetLastWithdrawalsRoot(r []byte) error { + if b.version < version.EPBS { + return errors.Wrapf(consensus_types.ErrUnsupportedField, "SetLastWithdrawalsRoot not supported for version: %d", b.version) + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.lastWithdrawalsRoot = bytesutil.ToBytes32(r) + b.markFieldAsDirty(types.LastWithdrawalsRoot) + return nil +} diff --git a/beacon-chain/state/state-native/setters_payload_header.go b/beacon-chain/state/state-native/setters_payload_header.go index 3b36f7f5b658..4231ad8ca53a 100644 --- a/beacon-chain/state/state-native/setters_payload_header.go +++ b/beacon-chain/state/state-native/setters_payload_header.go @@ -15,7 +15,7 @@ func (b *BeaconState) SetLatestExecutionPayloadHeader(val interfaces.ExecutionDa b.lock.Lock() defer b.lock.Unlock() - if b.version < version.Bellatrix { + if b.version < version.Bellatrix || b.version >= version.EPBS { return errNotSupported("SetLatestExecutionPayloadHeader", b.version) } diff --git a/beacon-chain/state/state-native/spec_parameters.go b/beacon-chain/state/state-native/spec_parameters.go index 697afd6e73e2..0d84f1092987 100644 --- a/beacon-chain/state/state-native/spec_parameters.go +++ b/beacon-chain/state/state-native/spec_parameters.go @@ -7,7 +7,7 @@ import ( func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) { switch b.version { - case version.Bellatrix, version.Capella, version.Deneb: + case version.Bellatrix, version.Capella, version.Deneb, version.EPBS: return params.BeaconConfig().ProportionalSlashingMultiplierBellatrix, nil case version.Altair: return params.BeaconConfig().ProportionalSlashingMultiplierAltair, nil @@ -19,7 +19,7 @@ func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) { func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) { switch b.version { - case version.Bellatrix, version.Capella, version.Deneb: + case version.Bellatrix, version.Capella, version.Deneb, version.EPBS: return params.BeaconConfig().InactivityPenaltyQuotientBellatrix, nil case version.Altair: return params.BeaconConfig().InactivityPenaltyQuotientAltair, nil diff --git a/beacon-chain/state/state-native/state_trie.go b/beacon-chain/state/state-native/state_trie.go index 03ec6d77079b..00d6d8cb1bee 100644 --- a/beacon-chain/state/state-native/state_trie.go +++ b/beacon-chain/state/state-native/state_trie.go @@ -93,17 +93,35 @@ var denebFields = append( types.HistoricalSummaries, ) +var epbsFields = append( + altairFields, + types.ExecutionPayloadHeader, // new in ePBS + types.NextWithdrawalIndex, + types.NextWithdrawalValidatorIndex, + types.HistoricalSummaries, + types.PreviousInclusionListProposer, // ePBS fields start here + types.PreviousInclusionListSlot, + types.LatestInclusionListProposer, + types.LatestInclusionListSlot, + types.LatestBlockHash, + types.LatestFullSlot, + types.ExecutionPayloadHeader, + types.LastWithdrawalsRoot, +) + const ( phase0SharedFieldRefCount = 10 altairSharedFieldRefCount = 11 bellatrixSharedFieldRefCount = 12 capellaSharedFieldRefCount = 14 denebSharedFieldRefCount = 14 + epbsSharedFieldRefCount = 14 experimentalStatePhase0SharedFieldRefCount = 5 experimentalStateAltairSharedFieldRefCount = 5 experimentalStateBellatrixSharedFieldRefCount = 6 experimentalStateCapellaSharedFieldRefCount = 8 experimentalStateDenebSharedFieldRefCount = 8 + experimentalStateEpbsSharedFieldRefCount = 8 ) // InitializeFromProtoPhase0 the beacon state from a protobuf representation. @@ -131,6 +149,11 @@ func InitializeFromProtoDeneb(st *ethpb.BeaconStateDeneb) (state.BeaconState, er return InitializeFromProtoUnsafeDeneb(proto.Clone(st).(*ethpb.BeaconStateDeneb)) } +// InitializeFromProtoEpbs initializes the beacon state from its protobuf representation. +func InitializeFromProtoEpbs(st *ethpb.BeaconStateEPBS) (state.BeaconState, error) { + return InitializeFromProtoUnsafeEpbs(proto.Clone(st).(*ethpb.BeaconStateEPBS)) +} + // InitializeFromProtoUnsafePhase0 directly uses the beacon state protobuf fields // and sets them as fields of the BeaconState type. func InitializeFromProtoUnsafePhase0(st *ethpb.BeaconState) (state.BeaconState, error) { @@ -700,17 +723,26 @@ func (b *BeaconState) Copy() state.BeaconState { fieldCount = params.BeaconConfig().BeaconStateCapellaFieldCount case version.Deneb: fieldCount = params.BeaconConfig().BeaconStateDenebFieldCount + case version.EPBS: + fieldCount = params.BeaconConfig().BeaconStateEpbsFieldCount } dst := &BeaconState{ version: b.version, // Primitive types, safe to copy. - genesisTime: b.genesisTime, - slot: b.slot, - eth1DepositIndex: b.eth1DepositIndex, - nextWithdrawalIndex: b.nextWithdrawalIndex, - nextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex, + genesisTime: b.genesisTime, + slot: b.slot, + eth1DepositIndex: b.eth1DepositIndex, + nextWithdrawalIndex: b.nextWithdrawalIndex, + nextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex, + previousInclusionListProposer: b.previousInclusionListProposer, + previousInclusionListSlot: b.previousInclusionListSlot, + latestInclusionListProposer: b.latestInclusionListProposer, + latestInclusionListSlot: b.latestInclusionListSlot, + latestBlockHash: b.latestBlockHash, + latestFullSlot: b.latestFullSlot, + lastWithdrawalsRoot: b.lastWithdrawalsRoot, // Large arrays, infrequently changed, constant size. blockRoots: b.blockRoots, @@ -750,6 +782,7 @@ func (b *BeaconState) Copy() state.BeaconState { latestExecutionPayloadHeader: b.latestExecutionPayloadHeaderVal(), latestExecutionPayloadHeaderCapella: b.latestExecutionPayloadHeaderCapellaVal(), latestExecutionPayloadHeaderDeneb: b.latestExecutionPayloadHeaderDenebVal(), + executionPayloadHeader: b.executionPayloadHeaderVal(), id: types.Enumerator.Inc(), @@ -785,6 +818,8 @@ func (b *BeaconState) Copy() state.BeaconState { dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateCapellaSharedFieldRefCount) case version.Deneb: dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateDenebSharedFieldRefCount) + case version.EPBS: + dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateEpbsSharedFieldRefCount) } } else { switch b.version { @@ -798,6 +833,8 @@ func (b *BeaconState) Copy() state.BeaconState { dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, capellaSharedFieldRefCount) case version.Deneb: dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, denebSharedFieldRefCount) + case version.EPBS: + dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, epbsSharedFieldRefCount) } } @@ -877,6 +914,7 @@ func (b *BeaconState) initializeMerkleLayers(ctx context.Context) error { if err != nil { return err } + layers := stateutil.Merkleize(fieldRoots) b.merkleLayers = layers switch b.version { @@ -890,6 +928,8 @@ func (b *BeaconState) initializeMerkleLayers(ctx context.Context) error { b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateCapellaFieldCount) case version.Deneb: b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateDenebFieldCount) + case version.EPBS: + b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateEpbsFieldCount) } return nil @@ -1114,6 +1154,22 @@ func (b *BeaconState) rootSelector(ctx context.Context, field types.FieldIndex) return ssz.Uint64Root(uint64(b.nextWithdrawalValidatorIndex)), nil case types.HistoricalSummaries: return stateutil.HistoricalSummariesRoot(b.historicalSummaries) + case types.PreviousInclusionListProposer: + return ssz.Uint64Root(uint64(b.previousInclusionListProposer)), nil + case types.PreviousInclusionListSlot: + return ssz.Uint64Root(uint64(b.previousInclusionListSlot)), nil + case types.LatestInclusionListProposer: + return ssz.Uint64Root(uint64(b.latestInclusionListProposer)), nil + case types.LatestInclusionListSlot: + return ssz.Uint64Root(uint64(b.latestInclusionListSlot)), nil + case types.LatestBlockHash: + return b.latestBlockHash, nil + case types.LatestFullSlot: + return ssz.Uint64Root(uint64(b.latestFullSlot)), nil + case types.ExecutionPayloadHeader: + return b.executionPayloadHeader.HashTreeRoot() + case types.LastWithdrawalsRoot: + return b.lastWithdrawalsRoot, nil } return [32]byte{}, errors.New("invalid field index provided") } diff --git a/beacon-chain/state/state-native/state_trie_epbs.go b/beacon-chain/state/state-native/state_trie_epbs.go new file mode 100644 index 000000000000..a417fae25415 --- /dev/null +++ b/beacon-chain/state/state-native/state_trie_epbs.go @@ -0,0 +1,139 @@ +package state_native + +import ( + "runtime" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/fieldtrie" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil" + "github.com/prysmaticlabs/prysm/v5/config/features" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" +) + +// InitializeFromProtoUnsafeEpbs constructs a BeaconState from its protobuf representation. +func InitializeFromProtoUnsafeEpbs(st *ethpb.BeaconStateEPBS) (*BeaconState, error) { + if st == nil { + return nil, errors.New("received nil state") + } + + // Process historical roots. + hRoots := make([][32]byte, len(st.HistoricalRoots)) + for i, root := range st.HistoricalRoots { + hRoots[i] = bytesutil.ToBytes32(root) + } + + // Define the number of fields to track changes. + fieldCount := params.BeaconConfig().BeaconStateEpbsFieldCount + b := &BeaconState{ + version: version.EPBS, + genesisTime: st.GenesisTime, + genesisValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot), + slot: st.Slot, + fork: st.Fork, + latestBlockHeader: st.LatestBlockHeader, + historicalRoots: hRoots, + eth1Data: st.Eth1Data, + eth1DataVotes: st.Eth1DataVotes, + eth1DepositIndex: st.Eth1DepositIndex, + slashings: st.Slashings, + previousEpochParticipation: st.PreviousEpochParticipation, + currentEpochParticipation: st.CurrentEpochParticipation, + justificationBits: st.JustificationBits, + previousJustifiedCheckpoint: st.PreviousJustifiedCheckpoint, + currentJustifiedCheckpoint: st.CurrentJustifiedCheckpoint, + finalizedCheckpoint: st.FinalizedCheckpoint, + currentSyncCommittee: st.CurrentSyncCommittee, + nextSyncCommittee: st.NextSyncCommittee, + nextWithdrawalIndex: st.NextWithdrawalIndex, + nextWithdrawalValidatorIndex: st.NextWithdrawalValidatorIndex, + historicalSummaries: st.HistoricalSummaries, + + // ePBS fields + previousInclusionListProposer: st.PreviousInclusionListProposer, + previousInclusionListSlot: st.PreviousInclusionListSlot, + latestInclusionListProposer: st.LatestInclusionListProposer, + latestInclusionListSlot: st.LatestInclusionListSlot, + latestBlockHash: bytesutil.ToBytes32(st.LatestBlockHash), + latestFullSlot: st.LatestFullSlot, + executionPayloadHeader: st.ExecutionPayloadHeader, + lastWithdrawalsRoot: bytesutil.ToBytes32(st.LastWithdrawalsRoot), + + dirtyFields: make(map[types.FieldIndex]bool, fieldCount), + dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount), + stateFieldLeaves: make(map[types.FieldIndex]*fieldtrie.FieldTrie, fieldCount), + rebuildTrie: make(map[types.FieldIndex]bool, fieldCount), + valMapHandler: stateutil.NewValMapHandler(st.Validators), + } + + if features.Get().EnableExperimentalState { + b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots) + b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots) + b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes) + b.balancesMultiValue = NewMultiValueBalances(st.Balances) + b.validatorsMultiValue = NewMultiValueValidators(st.Validators) + b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores) + b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateEpbsSharedFieldRefCount) + } else { + bRoots := make([][32]byte, fieldparams.BlockRootsLength) + for i, r := range st.BlockRoots { + bRoots[i] = bytesutil.ToBytes32(r) + } + b.blockRoots = bRoots + + sRoots := make([][32]byte, fieldparams.StateRootsLength) + for i, r := range st.StateRoots { + sRoots[i] = bytesutil.ToBytes32(r) + } + b.stateRoots = sRoots + + mixes := make([][32]byte, fieldparams.RandaoMixesLength) + for i, m := range st.RandaoMixes { + mixes[i] = bytesutil.ToBytes32(m) + } + b.randaoMixes = mixes + + b.balances = st.Balances + b.validators = st.Validators + b.inactivityScores = st.InactivityScores + + b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, epbsSharedFieldRefCount) + } + + for _, f := range epbsFields { + b.dirtyFields[f] = true + b.rebuildTrie[f] = true + b.dirtyIndices[f] = []uint64{} + trie, err := fieldtrie.NewFieldTrie(f, types.BasicArray, nil, 0) + if err != nil { + return nil, err + } + b.stateFieldLeaves[f] = trie + } + + // Initialize field reference tracking for shared data. + b.sharedFieldReferences[types.HistoricalRoots] = stateutil.NewRef(1) + b.sharedFieldReferences[types.Eth1DataVotes] = stateutil.NewRef(1) + b.sharedFieldReferences[types.Slashings] = stateutil.NewRef(1) + b.sharedFieldReferences[types.PreviousEpochParticipationBits] = stateutil.NewRef(1) + b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1) + b.sharedFieldReferences[types.HistoricalSummaries] = stateutil.NewRef(1) + if !features.Get().EnableExperimentalState { + b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1) + b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1) + b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1) + b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1) + b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1) + b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1) + } + + state.Count.Inc() + // Finalizer runs when dst is being destroyed in garbage collection. + runtime.SetFinalizer(b, finalizerCleanup) + return b, nil +} diff --git a/beacon-chain/state/state-native/state_trie_epbs_test.go b/beacon-chain/state/state-native/state_trie_epbs_test.go new file mode 100644 index 000000000000..c5387762ebce --- /dev/null +++ b/beacon-chain/state/state-native/state_trie_epbs_test.go @@ -0,0 +1,86 @@ +package state_native + +import ( + "context" + "testing" + + "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/util/random" +) + +func Test_InitializeFromProtoEpbs(t *testing.T) { + st := random.BeaconState(t) + + // Cache initial values to check against after initialization. + prevInclusionListProposer := st.PreviousInclusionListProposer + prevInclusionListSlot := st.PreviousInclusionListSlot + latestInclusionListProposer := st.LatestInclusionListProposer + latestInclusionListSlot := st.LatestInclusionListSlot + latestBlockHash := st.LatestBlockHash + latestFullSlot := st.LatestFullSlot + header := st.ExecutionPayloadHeader + lastWithdrawalsRoot := st.LastWithdrawalsRoot + + s, err := InitializeFromProtoEpbs(st) + require.NoError(t, err) + + // Assert that initial values match those in the new state. + gotPrevInclusionListProposer, err := s.PreviousInclusionListProposer() + require.NoError(t, err) + require.Equal(t, prevInclusionListProposer, gotPrevInclusionListProposer) + gotPrevInclusionListSlot, err := s.PreviousInclusionListSlot() + require.NoError(t, err) + require.Equal(t, prevInclusionListSlot, gotPrevInclusionListSlot) + gotLatestInclusionListProposer, err := s.LatestInclusionListProposer() + require.NoError(t, err) + require.Equal(t, latestInclusionListProposer, gotLatestInclusionListProposer) + gotLatestInclusionListSlot, err := s.LatestInclusionListSlot() + require.NoError(t, err) + require.Equal(t, latestInclusionListSlot, gotLatestInclusionListSlot) + gotLatestBlockHash, err := s.LatestBlockHash() + require.NoError(t, err) + require.DeepEqual(t, latestBlockHash, gotLatestBlockHash) + gotLatestFullSlot, err := s.LatestFullSlot() + require.NoError(t, err) + require.Equal(t, latestFullSlot, gotLatestFullSlot) + gotHeader, err := s.ExecutionPayloadHeader() + require.NoError(t, err) + require.DeepEqual(t, header, gotHeader) + gotLastWithdrawalsRoot, err := s.LastWithdrawalsRoot() + require.NoError(t, err) + require.DeepEqual(t, lastWithdrawalsRoot, gotLastWithdrawalsRoot) +} + +func Test_CopyEpbs(t *testing.T) { + st := random.BeaconState(t) + s, err := InitializeFromProtoUnsafeEpbs(st) + require.NoError(t, err) + + // Test shallow copy. + sNoCopy := s + require.DeepEqual(t, s.executionPayloadHeader, sNoCopy.executionPayloadHeader) + + // Modify a field to check if it reflects in the shallow copy. + s.executionPayloadHeader.Slot = 100 + require.Equal(t, s.executionPayloadHeader, sNoCopy.executionPayloadHeader) + + // Copy the state + sCopy := s.Copy() + require.NoError(t, err) + header, err := sCopy.ExecutionPayloadHeader() + require.NoError(t, err) + require.DeepEqual(t, s.executionPayloadHeader, header) + + // Modify the original to check if the copied state is independent. + s.executionPayloadHeader.Slot = 200 + require.DeepNotEqual(t, s.executionPayloadHeader, header) +} + +func Test_HashTreeRootEpbs(t *testing.T) { + st := random.BeaconState(t) + s, err := InitializeFromProtoUnsafeEpbs(st) + require.NoError(t, err) + + _, err = s.HashTreeRoot(context.Background()) + require.NoError(t, err) +} diff --git a/beacon-chain/state/state-native/types/types.go b/beacon-chain/state/state-native/types/types.go index d2dd9cdbf190..a98a3ec7e3d0 100644 --- a/beacon-chain/state/state-native/types/types.go +++ b/beacon-chain/state/state-native/types/types.go @@ -90,6 +90,22 @@ func (f FieldIndex) String() string { return "NextWithdrawalValidatorIndex" case HistoricalSummaries: return "HistoricalSummaries" + case PreviousInclusionListProposer: // ePBS fields start here + return "PreviousInclusionListProposer" + case PreviousInclusionListSlot: + return "PreviousInclusionListSlot" + case LatestInclusionListProposer: + return "LatestInclusionListProposer" + case LatestInclusionListSlot: + return "LatestInclusionListSlot" + case LatestBlockHash: + return "LatestBlockHash" + case LatestFullSlot: + return "LatestFullSlot" + case ExecutionPayloadHeader: + return "ExecutionPayloadHeader" + case LastWithdrawalsRoot: + return "LastWithdrawalsRoot" default: return "" } @@ -147,7 +163,8 @@ func (f FieldIndex) RealPosition() int { return 22 case NextSyncCommittee: return 23 - case LatestExecutionPayloadHeader, LatestExecutionPayloadHeaderCapella, LatestExecutionPayloadHeaderDeneb: + // ExecutionPayloadHeader is from ePBS. + case LatestExecutionPayloadHeader, LatestExecutionPayloadHeaderCapella, LatestExecutionPayloadHeaderDeneb, ExecutionPayloadHeader: return 24 case NextWithdrawalIndex: return 25 @@ -155,6 +172,20 @@ func (f FieldIndex) RealPosition() int { return 26 case HistoricalSummaries: return 27 + case PreviousInclusionListProposer: // ePBS fields start here + return 28 + case PreviousInclusionListSlot: + return 29 + case LatestInclusionListProposer: + return 30 + case LatestInclusionListSlot: + return 31 + case LatestBlockHash: + return 32 + case LatestFullSlot: + return 33 + case LastWithdrawalsRoot: + return 34 default: return -1 } @@ -210,6 +241,14 @@ const ( NextWithdrawalIndex NextWithdrawalValidatorIndex HistoricalSummaries + PreviousInclusionListProposer // ePBS fields start here + PreviousInclusionListSlot + LatestInclusionListProposer + LatestInclusionListSlot + LatestBlockHash + LatestFullSlot + ExecutionPayloadHeader + LastWithdrawalsRoot ) // Enumerator keeps track of the number of states created since the node's start. diff --git a/beacon-chain/state/stateutil/trie_helpers.go b/beacon-chain/state/stateutil/trie_helpers.go index be4aabd0be2b..a0f630b26a8c 100644 --- a/beacon-chain/state/stateutil/trie_helpers.go +++ b/beacon-chain/state/stateutil/trie_helpers.go @@ -250,11 +250,11 @@ func AddInMixin(root [32]byte, length uint64) ([32]byte, error) { // Merkleize 32-byte leaves into a Merkle trie for its adequate depth, returning // the resulting layers of the trie based on the appropriate depth. This function -// pads the leaves to a length of 32. +// pads the leaves to a length of a multiple of 32. func Merkleize(leaves [][]byte) [][][]byte { hashFunc := hash.CustomSHA256Hasher() layers := make([][][]byte, ssz.Depth(uint64(len(leaves)))+1) - for len(leaves) != 32 { + for len(leaves)%32 != 0 { leaves = append(leaves, make([]byte, 32)) } currentLayer := leaves diff --git a/config/params/config.go b/config/params/config.go index 7f98a5acbc3d..92fd4cdea910 100644 --- a/config/params/config.go +++ b/config/params/config.go @@ -148,6 +148,7 @@ type BeaconChainConfig struct { BeaconStateCapellaFieldCount int // BeaconStateCapellaFieldCount defines how many fields are in beacon state post upgrade to Capella. BeaconStateDenebFieldCount int // BeaconStateDenebFieldCount defines how many fields are in beacon state post upgrade to Deneb. BeaconStateElectraFieldCount int // BeaconStateElectraFieldCount defines how many fields are in beacon state post upgrade to Electra. + BeaconStateEpbsFieldCount int // BeaconStateEpbsFieldCount defines how many fields are in beacon state post upgrade to ePBS. // Slasher constants. WeakSubjectivityPeriod primitives.Epoch // WeakSubjectivityPeriod defines the time period expressed in number of epochs were proof of stake network should validate block headers and attestations for slashable events. diff --git a/config/params/mainnet_config.go b/config/params/mainnet_config.go index c4214433ceb7..dad3e548522d 100644 --- a/config/params/mainnet_config.go +++ b/config/params/mainnet_config.go @@ -196,6 +196,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{ BeaconStateCapellaFieldCount: 28, BeaconStateDenebFieldCount: 28, BeaconStateElectraFieldCount: 37, + BeaconStateEpbsFieldCount: 35, // Slasher related values. WeakSubjectivityPeriod: 54000, diff --git a/proto/prysm/v1alpha1/beacon_state.pb.go b/proto/prysm/v1alpha1/beacon_state.pb.go index bc0eca61138a..f3c110e4ffc2 100755 --- a/proto/prysm/v1alpha1/beacon_state.pb.go +++ b/proto/prysm/v1alpha1/beacon_state.pb.go @@ -2208,7 +2208,7 @@ type BeaconStateEPBS struct { LatestBlockHash []byte `protobuf:"bytes,13005,opt,name=latest_block_hash,json=latestBlockHash,proto3" json:"latest_block_hash,omitempty" ssz-size:"32"` LatestFullSlot github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot `protobuf:"varint,13006,opt,name=latest_full_slot,json=latestFullSlot,proto3" json:"latest_full_slot,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"` ExecutionPayloadHeader *v1.ExecutionPayloadHeaderEPBS `protobuf:"bytes,13007,opt,name=execution_payload_header,json=executionPayloadHeader,proto3" json:"execution_payload_header,omitempty"` - LatestWithdrawalsRoot []byte `protobuf:"bytes,13008,opt,name=latest_withdrawals_root,json=latestWithdrawalsRoot,proto3" json:"latest_withdrawals_root,omitempty" ssz-size:"32"` + LastWithdrawalsRoot []byte `protobuf:"bytes,13008,opt,name=latest_withdrawals_root,json=lastWithdrawalsRoot,proto3" json:"latest_withdrawals_root,omitempty" ssz-size:"32"` } func (x *BeaconStateEPBS) Reset() { @@ -2481,9 +2481,9 @@ func (x *BeaconStateEPBS) GetExecutionPayloadHeader() *v1.ExecutionPayloadHeader return nil } -func (x *BeaconStateEPBS) GetLatestWithdrawalsRoot() []byte { +func (x *BeaconStateEPBS) GetLastWithdrawalsRoot() []byte { if x != nil { - return x.LatestWithdrawalsRoot + return x.LastWithdrawalsRoot } return nil } diff --git a/proto/prysm/v1alpha1/beacon_state.proto b/proto/prysm/v1alpha1/beacon_state.proto index 12dd7773712c..432ec7544bc1 100644 --- a/proto/prysm/v1alpha1/beacon_state.proto +++ b/proto/prysm/v1alpha1/beacon_state.proto @@ -468,7 +468,7 @@ message BeaconStateEPBS { bytes latest_block_hash = 13005 [(ethereum.eth.ext.ssz_size) = "32"]; uint64 latest_full_slot = 13006 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"]; ethereum.engine.v1.ExecutionPayloadHeaderEPBS execution_payload_header = 13007; - bytes latest_withdrawals_root = 13008 [(ethereum.eth.ext.ssz_size) = "32"]; + bytes last_withdrawals_root = 13008 [(ethereum.eth.ext.ssz_size) = "32"]; } diff --git a/testing/util/BUILD.bazel b/testing/util/BUILD.bazel index b51ba73c3bdb..3f6c1e6121be 100644 --- a/testing/util/BUILD.bazel +++ b/testing/util/BUILD.bazel @@ -18,7 +18,6 @@ go_library( "deposits.go", "helpers.go", "merge.go", - "payload_attestation.go", "state.go", "sync_aggregate.go", "sync_committee.go", diff --git a/testing/util/payload_attestation.go b/testing/util/payload_attestation.go deleted file mode 100644 index a66a4d1e5a7b..000000000000 --- a/testing/util/payload_attestation.go +++ /dev/null @@ -1,45 +0,0 @@ -package util - -import ( - "crypto/rand" - "math/big" - "testing" - - fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" - "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" - ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" -) - -// GenerateRandomPayloadAttestationData generates a random PayloadAttestationData for testing purposes. -func GenerateRandomPayloadAttestationData(t *testing.T) *ethpb.PayloadAttestationData { - // Generate a random BeaconBlockRoot - randomBytes := make([]byte, fieldparams.RootLength) - _, err := rand.Read(randomBytes) - if err != nil { - t.Fatalf("Failed to generate random BeaconBlockRoot: %v", err) - } - - // Generate a random Slot value - randomSlot, err := rand.Int(rand.Reader, big.NewInt(10000)) - if err != nil { - t.Fatalf("Failed to generate random Slot: %v", err) - } - - payloadStatuses := []primitives.PTCStatus{ - primitives.PAYLOAD_ABSENT, - primitives.PAYLOAD_PRESENT, - primitives.PAYLOAD_WITHHELD, - } - // Select a random PayloadStatus - index, err := rand.Int(rand.Reader, big.NewInt(int64(len(payloadStatuses)))) - if err != nil { - t.Fatalf("Failed to select random PayloadStatus: %v", err) - } - randomPayloadStatus := payloadStatuses[index.Int64()] - - return ðpb.PayloadAttestationData{ - BeaconBlockRoot: randomBytes, - Slot: primitives.Slot(randomSlot.Uint64()), - PayloadStatus: randomPayloadStatus, - } -} diff --git a/testing/util/random/BUILD.bazel b/testing/util/random/BUILD.bazel new file mode 100644 index 000000000000..5ee7fb77b47f --- /dev/null +++ b/testing/util/random/BUILD.bazel @@ -0,0 +1,14 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["epbs.go"], + importpath = "github.com/prysmaticlabs/prysm/v5/testing/util/random", + visibility = ["//visibility:public"], + deps = [ + "//config/fieldparams:go_default_library", + "//consensus-types/primitives:go_default_library", + "//proto/engine/v1:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + ], +) diff --git a/testing/util/random/epbs.go b/testing/util/random/epbs.go new file mode 100644 index 000000000000..308a39247d0a --- /dev/null +++ b/testing/util/random/epbs.go @@ -0,0 +1,134 @@ +package random + +import ( + "crypto/rand" + "encoding/binary" + "math/big" + "testing" + + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" +) + +func BeaconState(t *testing.T) *ethpb.BeaconStateEPBS { + return ðpb.BeaconStateEPBS{ + GenesisTime: randomUint64(t), + GenesisValidatorsRoot: randomBytes(32, t), + Slot: primitives.Slot(randomUint64(t)), + Fork: nil, + LatestBlockHeader: nil, + BlockRoots: nil, + StateRoots: nil, + HistoricalRoots: nil, + Eth1Data: ðpb.Eth1Data{}, + Eth1DataVotes: []*ethpb.Eth1Data{}, + Eth1DepositIndex: randomUint64(t), + Validators: []*ethpb.Validator{ + { + PublicKey: randomBytes(48, t), + WithdrawalCredentials: randomBytes(32, t), + EffectiveBalance: randomUint64(t), + ActivationEligibilityEpoch: primitives.Epoch(randomUint64(t)), + ActivationEpoch: primitives.Epoch(randomUint64(t)), + ExitEpoch: primitives.Epoch(randomUint64(t)), + WithdrawableEpoch: primitives.Epoch(randomUint64(t)), + }, + }, + Balances: []uint64{randomUint64(t)}, + RandaoMixes: nil, + Slashings: nil, + PreviousEpochParticipation: nil, + CurrentEpochParticipation: nil, + JustificationBits: nil, + PreviousJustifiedCheckpoint: nil, + CurrentJustifiedCheckpoint: nil, + FinalizedCheckpoint: nil, + InactivityScores: nil, + CurrentSyncCommittee: nil, + NextSyncCommittee: nil, + NextWithdrawalIndex: randomUint64(t), + NextWithdrawalValidatorIndex: primitives.ValidatorIndex(randomUint64(t)), + HistoricalSummaries: nil, + PreviousInclusionListProposer: primitives.ValidatorIndex(randomUint64(t)), + PreviousInclusionListSlot: primitives.Slot(randomUint64(t)), + LatestInclusionListProposer: primitives.ValidatorIndex(randomUint64(t)), + LatestInclusionListSlot: primitives.Slot(randomUint64(t)), + LatestBlockHash: randomBytes(32, t), + LatestFullSlot: primitives.Slot(randomUint64(t)), + ExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderEPBS{ + ParentBlockHash: randomBytes(32, t), + ParentBlockRoot: randomBytes(32, t), + BlockHash: randomBytes(32, t), + BuilderIndex: primitives.ValidatorIndex(randomUint64(t)), + Slot: primitives.Slot(randomUint64(t)), + Value: randomUint64(t), + BlobKzgCommitmentsRoot: randomBytes(32, t), + }, + LastWithdrawalsRoot: randomBytes(32, t), + } +} + +// ExecutionPayloadHeader creates a random ExecutionPayloadHeaderEPBS for testing. +func ExecutionPayloadHeader(t *testing.T) *enginev1.ExecutionPayloadHeaderEPBS { + return &enginev1.ExecutionPayloadHeaderEPBS{ + ParentBlockHash: randomBytes(32, t), + ParentBlockRoot: randomBytes(32, t), + BlockHash: randomBytes(32, t), + BuilderIndex: primitives.ValidatorIndex(randomUint64(t)), + Slot: primitives.Slot(randomUint64(t)), + Value: randomUint64(t), + BlobKzgCommitmentsRoot: randomBytes(32, t), + } +} + +// PayloadAttestationData generates a random PayloadAttestationData for testing purposes. +func PayloadAttestationData(t *testing.T) *ethpb.PayloadAttestationData { + // Generate a random BeaconBlockRoot + randomBytes := make([]byte, fieldparams.RootLength) + _, err := rand.Read(randomBytes) + if err != nil { + t.Fatalf("Failed to generate random BeaconBlockRoot: %v", err) + } + + // Generate a random Slot value + randomSlot, err := rand.Int(rand.Reader, big.NewInt(10000)) + if err != nil { + t.Fatalf("Failed to generate random Slot: %v", err) + } + + payloadStatuses := []primitives.PTCStatus{ + primitives.PAYLOAD_ABSENT, + primitives.PAYLOAD_PRESENT, + primitives.PAYLOAD_WITHHELD, + } + // Select a random PayloadStatus + index, err := rand.Int(rand.Reader, big.NewInt(int64(len(payloadStatuses)))) + if err != nil { + t.Fatalf("Failed to select random PayloadStatus: %v", err) + } + randomPayloadStatus := payloadStatuses[index.Int64()] + + return ðpb.PayloadAttestationData{ + BeaconBlockRoot: randomBytes, + Slot: primitives.Slot(randomSlot.Uint64()), + PayloadStatus: randomPayloadStatus, + } +} + +func randomBytes(n int, t *testing.T) []byte { + b := make([]byte, n) + _, err := rand.Read(b) + if err != nil { + t.Fatalf("Failed to generate random bytes: %v", err) + } + return b +} + +func randomUint64(t *testing.T) uint64 { + var num uint64 + b := randomBytes(8, t) + num = binary.BigEndian.Uint64(b) + return num +} diff --git a/validator/client/BUILD.bazel b/validator/client/BUILD.bazel index 5c683dd218e5..6665337bb23e 100644 --- a/validator/client/BUILD.bazel +++ b/validator/client/BUILD.bazel @@ -147,6 +147,7 @@ go_test( "//testing/mock:go_default_library", "//testing/require:go_default_library", "//testing/util:go_default_library", + "//testing/util/random:go_default_library", "//testing/validator-mock:go_default_library", "//time:go_default_library", "//time/slots:go_default_library", diff --git a/validator/client/payload_attestation_test.go b/validator/client/payload_attestation_test.go index 6c2f356404f5..2f7a0dc09f61 100644 --- a/validator/client/payload_attestation_test.go +++ b/validator/client/payload_attestation_test.go @@ -11,7 +11,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v5/testing/require" - "github.com/prysmaticlabs/prysm/v5/testing/util" + "github.com/prysmaticlabs/prysm/v5/testing/util/random" "go.uber.org/mock/gomock" ) @@ -32,7 +32,7 @@ func Test_validator_signPayloadAttestation(t *testing.T) { }, nil) // Generate random payload attestation data - pa := util.GenerateRandomPayloadAttestationData(t) + pa := random.PayloadAttestationData(t) pa.Slot = primitives.Slot(e) * params.BeaconConfig().SlotsPerEpoch // Verify that go mock EXPECT() gets the correct epoch. // Perform the signature operation