From 3b587562726b874dcdff42a7c1c08e5ce60bad59 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 29 Apr 2024 11:12:55 -0500 Subject: [PATCH 01/34] wip fork logic upgrade --- beacon-chain/core/electra/upgrade.go | 141 ++++++++++++++++++ beacon-chain/core/electra/upgrade_test.go | 1 + beacon-chain/core/time/slot_epoch.go | 9 ++ beacon-chain/core/time/slot_epoch_test.go | 35 +++++ beacon-chain/core/transition/transition.go | 8 + beacon-chain/state/state-native/state_trie.go | 125 ++++++++++++++++ .../state/state-native/types/types.go | 46 ++++++ beacon-chain/state/stategen/replay.go | 9 ++ config/params/loader.go | 2 + 9 files changed, 376 insertions(+) create mode 100644 beacon-chain/core/electra/upgrade.go create mode 100644 beacon-chain/core/electra/upgrade_test.go diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go new file mode 100644 index 000000000000..6470b344291e --- /dev/null +++ b/beacon-chain/core/electra/upgrade.go @@ -0,0 +1,141 @@ +package electra + +import ( + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" + state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" +) + +// UpgradeToElectra updates inputs a generic state to return the version Electra state. +func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { + epoch := time.CurrentEpoch(state) + + currentSyncCommittee, err := state.CurrentSyncCommittee() + if err != nil { + return nil, err + } + nextSyncCommittee, err := state.NextSyncCommittee() + if err != nil { + return nil, err + } + prevEpochParticipation, err := state.PreviousEpochParticipation() + if err != nil { + return nil, err + } + currentEpochParticipation, err := state.CurrentEpochParticipation() + if err != nil { + return nil, err + } + inactivityScores, err := state.InactivityScores() + if err != nil { + return nil, err + } + payloadHeader, err := state.LatestExecutionPayloadHeader() + if err != nil { + return nil, err + } + txRoot, err := payloadHeader.TransactionsRoot() + if err != nil { + return nil, err + } + wdRoot, err := payloadHeader.WithdrawalsRoot() + if err != nil { + return nil, err + } + wi, err := state.NextWithdrawalIndex() + if err != nil { + return nil, err + } + vi, err := state.NextWithdrawalValidatorIndex() + if err != nil { + return nil, err + } + summaries, err := state.HistoricalSummaries() + if err != nil { + return nil, err + } + historicalRoots, err := state.HistoricalRoots() + if err != nil { + return nil, err + } + excessBlobGas, err := payloadHeader.ExcessBlobGas() + if err != nil { + return nil, err + } + blobGasUsed, err := payloadHeader.BlobGasUsed() + if err != nil { + return nil, err + } + + s := ðpb.BeaconStateElectra{ + GenesisTime: state.GenesisTime(), + GenesisValidatorsRoot: state.GenesisValidatorsRoot(), + Slot: state.Slot(), + Fork: ðpb.Fork{ + PreviousVersion: state.Fork().CurrentVersion, + CurrentVersion: params.BeaconConfig().ElectraForkVersion, + Epoch: epoch, + }, + LatestBlockHeader: state.LatestBlockHeader(), + BlockRoots: state.BlockRoots(), + StateRoots: state.StateRoots(), + HistoricalRoots: historicalRoots, + Eth1Data: state.Eth1Data(), + Eth1DataVotes: state.Eth1DataVotes(), + Eth1DepositIndex: state.Eth1DepositIndex(), + Validators: state.Validators(), + Balances: state.Balances(), + RandaoMixes: state.RandaoMixes(), + Slashings: state.Slashings(), + PreviousEpochParticipation: prevEpochParticipation, + CurrentEpochParticipation: currentEpochParticipation, + JustificationBits: state.JustificationBits(), + PreviousJustifiedCheckpoint: state.PreviousJustifiedCheckpoint(), + CurrentJustifiedCheckpoint: state.CurrentJustifiedCheckpoint(), + FinalizedCheckpoint: state.FinalizedCheckpoint(), + InactivityScores: inactivityScores, + CurrentSyncCommittee: currentSyncCommittee, + NextSyncCommittee: nextSyncCommittee, + LatestExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderElectra{ + ParentHash: payloadHeader.ParentHash(), + FeeRecipient: payloadHeader.FeeRecipient(), + StateRoot: payloadHeader.StateRoot(), + ReceiptsRoot: payloadHeader.ReceiptsRoot(), + LogsBloom: payloadHeader.LogsBloom(), + PrevRandao: payloadHeader.PrevRandao(), + BlockNumber: payloadHeader.BlockNumber(), + GasLimit: payloadHeader.GasLimit(), + GasUsed: payloadHeader.GasUsed(), + Timestamp: payloadHeader.Timestamp(), + ExtraData: payloadHeader.ExtraData(), + BaseFeePerGas: payloadHeader.BaseFeePerGas(), + BlockHash: payloadHeader.BlockHash(), + TransactionsRoot: txRoot, + WithdrawalsRoot: wdRoot, + ExcessBlobGas: excessBlobGas, + BlobGasUsed: blobGasUsed, + DepositReceiptsRoot: bytesutil.Bytes32(0), + WithdrawalRequestsRoot: bytesutil.Bytes32(0), + }, + NextWithdrawalIndex: wi, + NextWithdrawalValidatorIndex: vi, + HistoricalSummaries: summaries, + + // TODO: Verify these initial electra values are correct + DepositReceiptsStartIndex: 0, + DepositBalanceToConsume: 0, + ExitBalanceToConsume: 0, + EarliestExitEpoch: 0, + ConsolidationBalanceToConsume: 0, + EarliestConsolidationEpoch: 0, + PendingBalanceDeposits: nil, + PendingPartialWithdrawals: nil, + PendingConsolidations: nil, + } + + return state_native.InitializeFromProtoUnsafeElectra(s) +} diff --git a/beacon-chain/core/electra/upgrade_test.go b/beacon-chain/core/electra/upgrade_test.go new file mode 100644 index 000000000000..74252d944008 --- /dev/null +++ b/beacon-chain/core/electra/upgrade_test.go @@ -0,0 +1 @@ +package electra diff --git a/beacon-chain/core/time/slot_epoch.go b/beacon-chain/core/time/slot_epoch.go index e833284fd493..9ffa1561a3bf 100644 --- a/beacon-chain/core/time/slot_epoch.go +++ b/beacon-chain/core/time/slot_epoch.go @@ -90,6 +90,15 @@ func CanUpgradeToDeneb(slot primitives.Slot) bool { return epochStart && DenebEpoch } +// CanUpgradeToElectra returns true if the input `slot` can upgrade to Electra. +// Spec code: +// If state.slot % SLOTS_PER_EPOCH == 0 and compute_epoch_at_slot(state.slot) == ELECTRA_FORK_EPOCH +func CanUpgradeToElectra(slot primitives.Slot) bool { + epochStart := slots.IsEpochStart(slot) + electraEpoch := slots.ToEpoch(slot) == params.BeaconConfig().ElectraForkEpoch + return epochStart && electraEpoch +} + // CanProcessEpoch checks the eligibility to process epoch. // The epoch can be processed at the end of the last slot of every epoch. // diff --git a/beacon-chain/core/time/slot_epoch_test.go b/beacon-chain/core/time/slot_epoch_test.go index 7e6ce9a46248..69fd32603267 100644 --- a/beacon-chain/core/time/slot_epoch_test.go +++ b/beacon-chain/core/time/slot_epoch_test.go @@ -333,3 +333,38 @@ func TestCanUpgradeToDeneb(t *testing.T) { }) } } + +func TestCanUpgradeToElectra(t *testing.T) { + params.SetupTestConfigCleanup(t) + bc := params.BeaconConfig() + bc.ElectraForkEpoch = 5 + params.OverrideBeaconConfig(bc) + tests := []struct { + name string + slot primitives.Slot + want bool + }{ + { + name: "not epoch start", + slot: 1, + want: false, + }, + { + name: "not electra epoch", + slot: params.BeaconConfig().SlotsPerEpoch, + want: false, + }, + { + name: "electra epoch", + slot: primitives.Slot(params.BeaconConfig().ElectraForkEpoch) * params.BeaconConfig().SlotsPerEpoch, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := time.CanUpgradeToElectra(tt.slot); got != tt.want { + t.Errorf("CanUpgradeToElectra() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/beacon-chain/core/transition/transition.go b/beacon-chain/core/transition/transition.go index 963883183749..e752d078bbb6 100644 --- a/beacon-chain/core/transition/transition.go +++ b/beacon-chain/core/transition/transition.go @@ -320,6 +320,14 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta return nil, err } } + + if time.CanUpgradeToElectra(state.Slot()) { + state, err = deneb.UpgradeToElectra(state) + if err != nil { + tracing.AnnotateError(span, err) + return nil, err + } + } return state, nil } diff --git a/beacon-chain/state/state-native/state_trie.go b/beacon-chain/state/state-native/state_trie.go index 03ec6d77079b..70c4bc3587e3 100644 --- a/beacon-chain/state/state-native/state_trie.go +++ b/beacon-chain/state/state-native/state_trie.go @@ -683,6 +683,131 @@ func InitializeFromProtoUnsafeDeneb(st *ethpb.BeaconStateDeneb) (state.BeaconSta return b, nil } +// InitializeFromProtoUnsafeElectra directly uses the beacon state protobuf fields +// and sets them as fields of the BeaconState type. +func InitializeFromProtoUnsafeElectra(st *ethpb.BeaconStateElectra) (state.BeaconState, error) { + if st == nil { + return nil, errors.New("received nil state") + } + + hRoots := customtypes.HistoricalRoots(make([][32]byte, len(st.HistoricalRoots))) + for i, r := range st.HistoricalRoots { + hRoots[i] = bytesutil.ToBytes32(r) + } + + fieldCount := params.BeaconConfig().BeaconStateElectraFieldCount + b := &BeaconState{ + version: version.Electra, + 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, + latestExecutionPayloadHeaderElectra: st.LatestExecutionPayloadHeader, + nextWithdrawalIndex: st.NextWithdrawalIndex, + nextWithdrawalValidatorIndex: st.NextWithdrawalValidatorIndex, + historicalSummaries: st.HistoricalSummaries, + depositReceiptsStartIndex: st.DepositReceiptsStartIndex, + depositBalanceToConsume: st.DepositBalanceToConsume, + exitBalanceToConsume: st.ExitBalanceToConsume, + earliestExitEpoch: st.EarliestExitEpoch, + consolidationBalanceToConsume: st.ConsolidationBalanceToConsume, + earliestConsolidationEpoch: st.EarliestConsolidationEpoch, + pendingBalanceDeposits: st.PendingBalanceDeposits, + pendingPartialWithdrawals: st.PendingPartialWithdrawals, + pendingConsolidations: st.PendingConsolidations, + + 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, experimentalStateElectraSharedFieldRefCount) + } 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, electraSharedFieldRefCount) + } + + for _, f := range electraFields { + 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.LatestExecutionPayloadHeaderElectra] = stateutil.NewRef(1) // New in Electra. + b.sharedFieldReferences[types.HistoricalSummaries] = stateutil.NewRef(1) // New in Capella. + b.sharedFieldReferences[types.PendingBalanceDeposits] = stateutil.NewRef(1) // New in Electra. + b.sharedFieldReferences[types.PendingPartialWithdrawals] = stateutil.NewRef(1) // New in Electra. + b.sharedFieldReferences[types.PendingConsolidations] = stateutil.NewRef(1) // New in Electra. + 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 +} + // Copy returns a deep copy of the beacon state. func (b *BeaconState) Copy() state.BeaconState { b.lock.RLock() diff --git a/beacon-chain/state/state-native/types/types.go b/beacon-chain/state/state-native/types/types.go index d2dd9cdbf190..fe6eafcedb5b 100644 --- a/beacon-chain/state/state-native/types/types.go +++ b/beacon-chain/state/state-native/types/types.go @@ -90,6 +90,24 @@ func (f FieldIndex) String() string { return "NextWithdrawalValidatorIndex" case HistoricalSummaries: return "HistoricalSummaries" + case DepositReceiptsStartIndex: + return "DepositReceiptsStartIndex" + case DepositBalanceToConsume: + return "DepositBalanceToConsume" + case ExitBalanceToConsume: + return "ExitBalanceToConsume" + case EarliestExitEpoch: + return "EarliestExitEpoch" + case ConsolidationBalanceToConsume: + return "ConsolidationBalanceToConsume" + case EarliestConsolidationEpoch: + return "EarliestConsolidationEpoch" + case PendingBalanceDeposits: + return "PendingBalanceDeposits" + case PendingPartialWithdrawals: + return "PendingPartialWithdrawals" + case PendingConsolidations: + return "PendingConsolidations" default: return "" } @@ -155,6 +173,24 @@ func (f FieldIndex) RealPosition() int { return 26 case HistoricalSummaries: return 27 + case DepositReceiptsStartIndex: + return 28 + case DepositBalanceToConsume: + return 29 + case ExitBalanceToConsume: + return 30 + case EarliestExitEpoch: + return 31 + case ConsolidationBalanceToConsume: + return 32 + case EarliestConsolidationEpoch: + return 33 + case PendingBalanceDeposits: + return 34 + case PendingPartialWithdrawals: + return 35 + case PendingConsolidations: + return 36 default: return -1 } @@ -207,9 +243,19 @@ const ( LatestExecutionPayloadHeader LatestExecutionPayloadHeaderCapella LatestExecutionPayloadHeaderDeneb + LatestExecutionPayloadHeaderElectra NextWithdrawalIndex NextWithdrawalValidatorIndex HistoricalSummaries + DepositReceiptsStartIndex // Electra: EIP-6110 + DepositBalanceToConsume // Electra: EIP-7251 + ExitBalanceToConsume // Electra: EIP-7251 + EarliestExitEpoch // Electra: EIP-7251 + ConsolidationBalanceToConsume // Electra: EIP-7251 + EarliestConsolidationEpoch // Electra: EIP-7251 + PendingBalanceDeposits // Electra: EIP-7251 + PendingPartialWithdrawals // Electra: EIP-7251 + PendingConsolidations // Electra: EIP-7251 ) // Enumerator keeps track of the number of states created since the node's start. diff --git a/beacon-chain/state/stategen/replay.go b/beacon-chain/state/stategen/replay.go index 42755a31daad..465bd9c63983 100644 --- a/beacon-chain/state/stategen/replay.go +++ b/beacon-chain/state/stategen/replay.go @@ -9,6 +9,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/capella" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/deneb" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/execution" prysmtime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition" @@ -254,6 +255,14 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primi return nil, err } } + + if prysmtime.CanUpgradeToElectra(state.Slot()) { + state, err = electra.UpgradeToElectra(state) + if err != nil { + tracing.AnnotateError(span, err) + return nil, err + } + } } return state, nil diff --git a/config/params/loader.go b/config/params/loader.go index c9a7a2562e7b..542c8eb8375c 100644 --- a/config/params/loader.go +++ b/config/params/loader.go @@ -230,6 +230,8 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte { fmt.Sprintf("MESSAGE_DOMAIN_INVALID_SNAPPY: %#x", cfg.MessageDomainInvalidSnappy), fmt.Sprintf("MESSAGE_DOMAIN_VALID_SNAPPY: %#x", cfg.MessageDomainValidSnappy), fmt.Sprintf("MIN_EPOCHS_FOR_BLOCK_REQUESTS: %d", int(cfg.MinEpochsForBlockRequests)), + fmt.Sprintf("ELECTRA_FORK_EPOCH: %d", cfg.ElectraForkEpoch), + fmt.Sprintf("ELECTRA_FORK_VERSION: %#x", cfg.ElectraForkVersion), } yamlFile := []byte(strings.Join(lines, "\n")) From e02475aba1d8cbb0944b5d0331dad4c0b4fd96e5 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 29 Apr 2024 11:18:36 -0500 Subject: [PATCH 02/34] fixing replay and fork.go --- beacon-chain/state/stategen/replay.go | 2 +- config/params/loader_test.go | 2 ++ runtime/version/fork.go | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/beacon-chain/state/stategen/replay.go b/beacon-chain/state/stategen/replay.go index 465bd9c63983..a39f3e28de1b 100644 --- a/beacon-chain/state/stategen/replay.go +++ b/beacon-chain/state/stategen/replay.go @@ -209,7 +209,7 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primi tracing.AnnotateError(span, err) return nil, errors.Wrap(err, "could not process epoch with optimizations") } - case version.Altair, version.Bellatrix, version.Capella, version.Deneb: + case version.Altair, version.Bellatrix, version.Capella, version.Deneb, version.Electra: state, err = altair.ProcessEpoch(ctx, state) if err != nil { tracing.AnnotateError(span, err) diff --git a/config/params/loader_test.go b/config/params/loader_test.go index 555682e30ded..ec11d43e80a2 100644 --- a/config/params/loader_test.go +++ b/config/params/loader_test.go @@ -147,12 +147,14 @@ func assertEqualConfigs(t *testing.T, name string, fields []string, expected, ac assert.Equal(t, expected.BellatrixForkEpoch, actual.BellatrixForkEpoch, "%s: BellatrixForkEpoch", name) assert.Equal(t, expected.CapellaForkEpoch, actual.CapellaForkEpoch, "%s: CapellaForkEpoch", name) assert.Equal(t, expected.DenebForkEpoch, actual.DenebForkEpoch, "%s: DenebForkEpoch", name) + assert.Equal(t, expected.ElectraForkEpoch, actual.ElectraForkEpoch, "%s: ElectraForkEpoch", name) assert.Equal(t, expected.SqrRootSlotsPerEpoch, actual.SqrRootSlotsPerEpoch, "%s: SqrRootSlotsPerEpoch", name) assert.DeepEqual(t, expected.GenesisForkVersion, actual.GenesisForkVersion, "%s: GenesisForkVersion", name) assert.DeepEqual(t, expected.AltairForkVersion, actual.AltairForkVersion, "%s: AltairForkVersion", name) assert.DeepEqual(t, expected.BellatrixForkVersion, actual.BellatrixForkVersion, "%s: BellatrixForkVersion", name) assert.DeepEqual(t, expected.CapellaForkVersion, actual.CapellaForkVersion, "%s: CapellaForkVersion", name) assert.DeepEqual(t, expected.DenebForkVersion, actual.DenebForkVersion, "%s: DenebForkVersion", name) + assert.DeepEqual(t, expected.ElectraForkVersion, actual.ElectraForkVersion, "%s: ElectraForkVersion", name) assertYamlFieldsMatch(t, name, fields, expected, actual) } diff --git a/runtime/version/fork.go b/runtime/version/fork.go index d9e9b3811d1d..902393c8bc80 100644 --- a/runtime/version/fork.go +++ b/runtime/version/fork.go @@ -8,6 +8,7 @@ const ( Bellatrix Capella Deneb + Electra ) var versionToString = map[int]string{ @@ -16,6 +17,7 @@ var versionToString = map[int]string{ Bellatrix: "bellatrix", Capella: "capella", Deneb: "deneb", + Electra: "electra", } // stringToVersion and allVersions are populated in init() From 7d0c2bca6c8350a9f3ce0c72f524ffac8a813909 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 29 Apr 2024 11:27:55 -0500 Subject: [PATCH 03/34] improving process function and adding tests for transition --- beacon-chain/core/transition/transition.go | 3 ++- beacon-chain/core/transition/transition_test.go | 14 ++++++++++++++ beacon-chain/state/stategen/replay.go | 7 +++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/beacon-chain/core/transition/transition.go b/beacon-chain/core/transition/transition.go index e752d078bbb6..253cf2ad941d 100644 --- a/beacon-chain/core/transition/transition.go +++ b/beacon-chain/core/transition/transition.go @@ -13,6 +13,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/capella" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/deneb" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra" e "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch/precompute" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/execution" @@ -322,7 +323,7 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta } if time.CanUpgradeToElectra(state.Slot()) { - state, err = deneb.UpgradeToElectra(state) + state, err = electra.UpgradeToElectra(state) if err != nil { tracing.AnnotateError(span, err) return nil, err diff --git a/beacon-chain/core/transition/transition_test.go b/beacon-chain/core/transition/transition_test.go index 1d31c4127d0c..3a62d637781b 100644 --- a/beacon-chain/core/transition/transition_test.go +++ b/beacon-chain/core/transition/transition_test.go @@ -651,6 +651,20 @@ func TestProcessSlots_ThroughDenebEpoch(t *testing.T) { require.Equal(t, params.BeaconConfig().SlotsPerEpoch*10, st.Slot()) } +func TestProcessSlots_ThroughElectraEpoch(t *testing.T) { + transition.SkipSlotCache.Disable() + params.SetupTestConfigCleanup(t) + conf := params.BeaconConfig() + conf.ElectraForkEpoch = 5 + params.OverrideBeaconConfig(conf) + + st, _ := util.DeterministicGenesisStateCapella(t, params.BeaconConfig().MaxValidatorsPerCommittee) + st, err := transition.ProcessSlots(context.Background(), st, params.BeaconConfig().SlotsPerEpoch*10) + require.NoError(t, err) + require.Equal(t, version.Electra, st.Version()) + require.Equal(t, params.BeaconConfig().SlotsPerEpoch*10, st.Slot()) +} + func TestProcessSlotsUsingNextSlotCache(t *testing.T) { s, _ := util.DeterministicGenesisState(t, 1) r := []byte{'a'} diff --git a/beacon-chain/state/stategen/replay.go b/beacon-chain/state/stategen/replay.go index a39f3e28de1b..cd0fa498db89 100644 --- a/beacon-chain/state/stategen/replay.go +++ b/beacon-chain/state/stategen/replay.go @@ -202,20 +202,19 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primi return nil, errors.Wrap(err, "could not process slot") } if prysmtime.CanProcessEpoch(state) { - switch state.Version() { - case version.Phase0: + if state.Version() == version.Phase0 { state, err = transition.ProcessEpochPrecompute(ctx, state) if err != nil { tracing.AnnotateError(span, err) return nil, errors.Wrap(err, "could not process epoch with optimizations") } - case version.Altair, version.Bellatrix, version.Capella, version.Deneb, version.Electra: + } else if state.Version() >= version.Altair { state, err = altair.ProcessEpoch(ctx, state) if err != nil { tracing.AnnotateError(span, err) return nil, errors.Wrap(err, "could not process epoch") } - default: + } else { return nil, fmt.Errorf("unsupported beacon state version: %s", version.String(state.Version())) } } From 2f7f8996e5e9906c2255df9d2631e7f3685301b7 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 29 Apr 2024 12:00:26 -0500 Subject: [PATCH 04/34] updating unit tests and temporarily removing some fields on state_trie.go --- beacon-chain/core/electra/BUILD.bazel | 23 ++++++ beacon-chain/core/transition/BUILD.bazel | 1 + beacon-chain/state/state-native/state_trie.go | 79 +++++++++++-------- beacon-chain/state/stategen/BUILD.bazel | 1 + beacon-chain/state/stategen/replay_test.go | 20 ++++- 5 files changed, 91 insertions(+), 33 deletions(-) create mode 100644 beacon-chain/core/electra/BUILD.bazel diff --git a/beacon-chain/core/electra/BUILD.bazel b/beacon-chain/core/electra/BUILD.bazel new file mode 100644 index 000000000000..14afad0f3fe0 --- /dev/null +++ b/beacon-chain/core/electra/BUILD.bazel @@ -0,0 +1,23 @@ +load("@prysm//tools/go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["upgrade.go"], + importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra", + visibility = ["//visibility:public"], + deps = [ + "//beacon-chain/core/time:go_default_library", + "//beacon-chain/state:go_default_library", + "//beacon-chain/state/state-native:go_default_library", + "//config/params:go_default_library", + "//encoding/bytesutil:go_default_library", + "//proto/engine/v1:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["upgrade_test.go"], + embed = [":go_default_library"], +) diff --git a/beacon-chain/core/transition/BUILD.bazel b/beacon-chain/core/transition/BUILD.bazel index 5aa1cbcc1ef0..9f2ea105cb2e 100644 --- a/beacon-chain/core/transition/BUILD.bazel +++ b/beacon-chain/core/transition/BUILD.bazel @@ -19,6 +19,7 @@ go_library( "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/core/capella:go_default_library", "//beacon-chain/core/deneb:go_default_library", + "//beacon-chain/core/electra:go_default_library", "//beacon-chain/core/epoch:go_default_library", "//beacon-chain/core/epoch/precompute:go_default_library", "//beacon-chain/core/execution:go_default_library", diff --git a/beacon-chain/state/state-native/state_trie.go b/beacon-chain/state/state-native/state_trie.go index 70c4bc3587e3..5de7e8492cff 100644 --- a/beacon-chain/state/state-native/state_trie.go +++ b/beacon-chain/state/state-native/state_trie.go @@ -93,17 +93,32 @@ var denebFields = append( types.HistoricalSummaries, ) +var electraFields = append( + denebFields, + types.DepositReceiptsStartIndex, + types.DepositBalanceToConsume, + types.ExitBalanceToConsume, + types.EarliestExitEpoch, + types.ConsolidationBalanceToConsume, + types.EarliestConsolidationEpoch, + types.PendingBalanceDeposits, + types.PendingPartialWithdrawals, + types.PendingConsolidations, +) + const ( phase0SharedFieldRefCount = 10 altairSharedFieldRefCount = 11 bellatrixSharedFieldRefCount = 12 capellaSharedFieldRefCount = 14 denebSharedFieldRefCount = 14 + electraSharedFieldRefCount = 17 experimentalStatePhase0SharedFieldRefCount = 5 experimentalStateAltairSharedFieldRefCount = 5 experimentalStateBellatrixSharedFieldRefCount = 6 experimentalStateCapellaSharedFieldRefCount = 8 experimentalStateDenebSharedFieldRefCount = 8 + experimentalStateElectraSharedFieldRefCount = 8 // TODO: Is this correct? ) // InitializeFromProtoPhase0 the beacon state from a protobuf representation. @@ -697,38 +712,38 @@ func InitializeFromProtoUnsafeElectra(st *ethpb.BeaconStateElectra) (state.Beaco fieldCount := params.BeaconConfig().BeaconStateElectraFieldCount b := &BeaconState{ - version: version.Electra, - 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, - latestExecutionPayloadHeaderElectra: st.LatestExecutionPayloadHeader, - nextWithdrawalIndex: st.NextWithdrawalIndex, - nextWithdrawalValidatorIndex: st.NextWithdrawalValidatorIndex, - historicalSummaries: st.HistoricalSummaries, - depositReceiptsStartIndex: st.DepositReceiptsStartIndex, - depositBalanceToConsume: st.DepositBalanceToConsume, - exitBalanceToConsume: st.ExitBalanceToConsume, - earliestExitEpoch: st.EarliestExitEpoch, - consolidationBalanceToConsume: st.ConsolidationBalanceToConsume, - earliestConsolidationEpoch: st.EarliestConsolidationEpoch, - pendingBalanceDeposits: st.PendingBalanceDeposits, - pendingPartialWithdrawals: st.PendingPartialWithdrawals, - pendingConsolidations: st.PendingConsolidations, + version: version.Electra, + 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, + //latestExecutionPayloadHeaderElectra: st.LatestExecutionPayloadHeader, + nextWithdrawalIndex: st.NextWithdrawalIndex, + nextWithdrawalValidatorIndex: st.NextWithdrawalValidatorIndex, + historicalSummaries: st.HistoricalSummaries, + //depositReceiptsStartIndex: st.DepositReceiptsStartIndex, + //depositBalanceToConsume: st.DepositBalanceToConsume, + //exitBalanceToConsume: st.ExitBalanceToConsume, + //earliestExitEpoch: st.EarliestExitEpoch, + //consolidationBalanceToConsume: st.ConsolidationBalanceToConsume, + //earliestConsolidationEpoch: st.EarliestConsolidationEpoch, + //pendingBalanceDeposits: st.PendingBalanceDeposits, + //pendingPartialWithdrawals: st.PendingPartialWithdrawals, + //pendingConsolidations: st.PendingConsolidations, dirtyFields: make(map[types.FieldIndex]bool, fieldCount), dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount), diff --git a/beacon-chain/state/stategen/BUILD.bazel b/beacon-chain/state/stategen/BUILD.bazel index 1260c4236a9c..8f0b0b3ed514 100644 --- a/beacon-chain/state/stategen/BUILD.bazel +++ b/beacon-chain/state/stategen/BUILD.bazel @@ -23,6 +23,7 @@ go_library( "//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/capella:go_default_library", "//beacon-chain/core/deneb:go_default_library", + "//beacon-chain/core/electra:go_default_library", "//beacon-chain/core/execution:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/time:go_default_library", diff --git a/beacon-chain/state/stategen/replay_test.go b/beacon-chain/state/stategen/replay_test.go index 9d8f3c489647..4cbc53012330 100644 --- a/beacon-chain/state/stategen/replay_test.go +++ b/beacon-chain/state/stategen/replay_test.go @@ -140,7 +140,7 @@ func TestReplayBlocks_ThroughForkBoundary(t *testing.T) { assert.Equal(t, version.Altair, newState.Version()) } -func TestReplayBlocks_ThroughCapellaForkBoundary(t *testing.T) { +func TestReplayBlocks_ThroughFutureForkBoundaries(t *testing.T) { params.SetupTestConfigCleanup(t) bCfg := params.BeaconConfig().Copy() bCfg.AltairForkEpoch = 1 @@ -149,6 +149,10 @@ func TestReplayBlocks_ThroughCapellaForkBoundary(t *testing.T) { bCfg.ForkVersionSchedule[bytesutil.ToBytes4(bCfg.BellatrixForkVersion)] = 2 bCfg.CapellaForkEpoch = 3 bCfg.ForkVersionSchedule[bytesutil.ToBytes4(bCfg.CapellaForkVersion)] = 3 + bCfg.DenebForkEpoch = 4 + bCfg.ForkVersionSchedule[bytesutil.ToBytes4(bCfg.DenebForkVersion)] = 4 + bCfg.ElectraForkEpoch = 5 + bCfg.ForkVersionSchedule[bytesutil.ToBytes4(bCfg.ElectraForkVersion)] = 5 params.OverrideBeaconConfig(bCfg) beaconState, _ := util.DeterministicGenesisState(t, 32) @@ -177,6 +181,20 @@ func TestReplayBlocks_ThroughCapellaForkBoundary(t *testing.T) { // Verify state is version Capella. assert.Equal(t, version.Capella, newState.Version()) + + targetSlot = params.BeaconConfig().SlotsPerEpoch * 4 + newState, err = service.replayBlocks(context.Background(), newState, []interfaces.ReadOnlySignedBeaconBlock{}, targetSlot) + require.NoError(t, err) + + // Verify state is version Deneb. + assert.Equal(t, version.Deneb, newState.Version()) + + targetSlot = params.BeaconConfig().SlotsPerEpoch * 5 + newState, err = service.replayBlocks(context.Background(), newState, []interfaces.ReadOnlySignedBeaconBlock{}, targetSlot) + require.NoError(t, err) + + // Verify state is version Electra. + assert.Equal(t, version.Electra, newState.Version()) } func TestLoadBlocks_FirstBranch(t *testing.T) { From c594df8224491ff26ee50be6e5f3dafd3bbeb3d8 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 29 Apr 2024 16:48:52 -0500 Subject: [PATCH 05/34] updating state --- beacon-chain/core/electra/upgrade.go | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 6470b344291e..4ed6d25b63de 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -5,6 +5,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native" "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" @@ -71,6 +72,25 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { return nil, err } + // RTFM: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/fork.md + // Find the earliest exit epoch + exitEpochs := make([]primitives.Epoch, 0) + for _, v := range state.Validators() { + if v.ExitEpoch != params.BeaconConfig().FarFutureEpoch { + exitEpochs = append(exitEpochs, v.ExitEpoch) + } + } + if len(exitEpochs) == 0 { + exitEpochs = append(exitEpochs, time.CurrentEpoch(state)) + } + var earliestExitEpoch primitives.Epoch + for _, e := range exitEpochs { + if e > earliestExitEpoch { + earliestExitEpoch = e + } + } + earliestExitEpoch++ // Increment to find the earliest possible exit epoch + s := ðpb.BeaconStateElectra{ GenesisTime: state.GenesisTime(), GenesisValidatorsRoot: state.GenesisValidatorsRoot(), @@ -126,6 +146,7 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { HistoricalSummaries: summaries, // TODO: Verify these initial electra values are correct + // They are not zero! DepositReceiptsStartIndex: 0, DepositBalanceToConsume: 0, ExitBalanceToConsume: 0, @@ -136,6 +157,27 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { PendingPartialWithdrawals: nil, PendingConsolidations: nil, } + // TODO: more logic to do + //post.exit_balance_to_consume = get_activation_exit_churn_limit(post) + //post.consolidation_balance_to_consume = get_consolidation_churn_limit(post) + // + //# [New in Electra:EIP7251] + //# add validators that are not yet active to pending balance deposits + //pre_activation = sorted([ + //index for index, validator in enumerate(post.validators) + //if validator.activation_epoch == FAR_FUTURE_EPOCH + //], key=lambda index: ( + //post.validators[index].activation_eligibility_epoch, + //index + //)) + // + //for index in pre_activation: + //queue_entire_balance_and_reset_validator(post, ValidatorIndex(index)) + // + //# Ensure early adopters of compounding credentials go through the activation churn + //for index, validator in enumerate(post.validators): + //if has_compounding_withdrawal_credential(validator): + //queue_excess_active_balance(post, ValidatorIndex(index)) return state_native.InitializeFromProtoUnsafeElectra(s) } From 45ee7125223802f3176922177ae9f1c09cb80060 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 29 Apr 2024 17:31:09 -0500 Subject: [PATCH 06/34] wip adding upgrade to electra code --- beacon-chain/core/electra/upgrade.go | 62 ++++++++++++++++++-------- beacon-chain/core/electra/validator.go | 45 +++++++++++++++++++ 2 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 beacon-chain/core/electra/validator.go diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 4ed6d25b63de..d380cf5d033c 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -1,6 +1,10 @@ package electra import ( + "sort" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native" @@ -157,27 +161,49 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { PendingPartialWithdrawals: nil, PendingConsolidations: nil, } - // TODO: more logic to do - //post.exit_balance_to_consume = get_activation_exit_churn_limit(post) - //post.consolidation_balance_to_consume = get_consolidation_churn_limit(post) - // + + tab, err := helpers.TotalActiveBalance(s) // TODO: need state readonly interface + if err != nil { + return nil, errors.Wrap(err, "failed to get total active balance") + } + + s.ExitBalanceToConsume = helpers.ActivationExitChurnLimit(tab) + s.ConsolidationBalanceToConsume = helpers.ConsolidationChurnLimit(tab) + //# [New in Electra:EIP7251] //# add validators that are not yet active to pending balance deposits - //pre_activation = sorted([ - //index for index, validator in enumerate(post.validators) - //if validator.activation_epoch == FAR_FUTURE_EPOCH - //], key=lambda index: ( - //post.validators[index].activation_eligibility_epoch, - //index - //)) - // - //for index in pre_activation: - //queue_entire_balance_and_reset_validator(post, ValidatorIndex(index)) - // + + // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH + var preActivation []primitives.ValidatorIndex + + for index, validator := range s.Validators { + if validator.ActivationEpoch == params.BeaconConfig().FarFutureEpoch { + preActivation = append(preActivation, primitives.ValidatorIndex(index)) + } + } + + // Sorting preActivation based on a custom criteria + sort.Slice(preActivation, func(i, j int) bool { + // Comparing based on ActivationEligibilityEpoch and then by index if the epochs are the same + if s.Validators[preActivation[i]].ActivationEligibilityEpoch == s.Validators[preActivation[j]].ActivationEligibilityEpoch { + return preActivation[i] < preActivation[j] + } + return s.Validators[preActivation[i]].ActivationEligibilityEpoch < s.Validators[preActivation[j]].ActivationEligibilityEpoch + }) + + for _, index := range preActivation { + if err := QueueEntireBalanceAndResetValidator(s, index); err != nil { + return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") + } + } //# Ensure early adopters of compounding credentials go through the activation churn - //for index, validator in enumerate(post.validators): - //if has_compounding_withdrawal_credential(validator): - //queue_excess_active_balance(post, ValidatorIndex(index)) + for index, validator := range s.Validators { + if helpers.HasCompoundingWithdrawalCredential(validator) { + if err := QueueEntireBalanceAndResetValidator(s, primitives.ValidatorIndex(index)); err != nil { + return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") + } + } + } return state_native.InitializeFromProtoUnsafeElectra(s) } diff --git a/beacon-chain/core/electra/validator.go b/beacon-chain/core/electra/validator.go new file mode 100644 index 000000000000..c26491674391 --- /dev/null +++ b/beacon-chain/core/electra/validator.go @@ -0,0 +1,45 @@ +package electra + +import ( + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" +) + +// TODO: need to be updated from state PR +// QueueEntireBalanceAndResetValidator queues the entire balance and resets the validator. This is used in electra fork logic. +// +// Spec definition: +// +// def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None: +// balance = state.balances[index] +// state.balances[index] = 0 +// validator = state.validators[index] +// validator.effective_balance = 0 +// validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH +// state.pending_balance_deposits.append( +// PendingBalanceDeposit(index=index, amount=balance) +// ) +func QueueEntireBalanceAndResetValidator(s state.BeaconState, idx primitives.ValidatorIndex) error { + bal, err := s.BalanceAtIndex(idx) + if err != nil { + return err + } + + if err := s.UpdateBalancesAtIndex(idx, 0); err != nil { + return err + } + + v, err := s.ValidatorAtIndex(idx) + if err != nil { + return err + } + + v.EffectiveBalance = 0 + v.ActivationEligibilityEpoch = params.BeaconConfig().FarFutureEpoch + if err := s.UpdateValidatorAtIndex(idx, v); err != nil { + return err + } + + return s.AppendPendingBalanceDeposit(idx, bal) +} From 0a2dae07878f27b99f28254a51f17665c4fbf30c Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 30 Apr 2024 11:12:11 -0500 Subject: [PATCH 07/34] adding some comments --- beacon-chain/core/electra/upgrade.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index d380cf5d033c..de6bc26fc2db 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -176,6 +176,7 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH var preActivation []primitives.ValidatorIndex + // TODO: make this loop over validators more efficient for index, validator := range s.Validators { if validator.ActivationEpoch == params.BeaconConfig().FarFutureEpoch { preActivation = append(preActivation, primitives.ValidatorIndex(index)) @@ -196,6 +197,7 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") } } + // TODO: combine below loop with above loop //# Ensure early adopters of compounding credentials go through the activation churn for index, validator := range s.Validators { if helpers.HasCompoundingWithdrawalCredential(validator) { From 1f7bb3680d07b731d686e7ad5b1ed5c010ad755e Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 11:09:23 -0500 Subject: [PATCH 08/34] adding spec tests --- .../state/state-native/getters_state.go | 10 ++++ .../fork_helper/upgrade_to_electra_test.go | 11 ++++ .../electra/fork/upgrade_to_electra_test.go | 11 ++++ .../shared/electra/fork/upgrade_to_electra.go | 60 +++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 testing/spectest/mainnet/electra/fork_helper/upgrade_to_electra_test.go create mode 100644 testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go create mode 100644 testing/spectest/shared/electra/fork/upgrade_to_electra.go diff --git a/beacon-chain/state/state-native/getters_state.go b/beacon-chain/state/state-native/getters_state.go index c8f9c4aa7b16..3d288bcbbf24 100644 --- a/beacon-chain/state/state-native/getters_state.go +++ b/beacon-chain/state/state-native/getters_state.go @@ -453,3 +453,13 @@ func ProtobufBeaconStateDeneb(s interface{}) (*ethpb.BeaconStateDeneb, error) { } return pbState, nil } + +// ProtobufBeaconStateElectra transforms an input into beacon state Electra in the form of protobuf. +// Error is returned if the input is not type protobuf beacon state. +func ProtobufBeaconStateElectra(s interface{}) (*ethpb.BeaconStateElectra, error) { + pbState, ok := s.(*ethpb.BeaconStateElectra) + if !ok { + return nil, errors.New("input is not type pb.ProtobufBeaconStateElectra") + } + return pbState, nil +} diff --git a/testing/spectest/mainnet/electra/fork_helper/upgrade_to_electra_test.go b/testing/spectest/mainnet/electra/fork_helper/upgrade_to_electra_test.go new file mode 100644 index 000000000000..d46ddc3acd8e --- /dev/null +++ b/testing/spectest/mainnet/electra/fork_helper/upgrade_to_electra_test.go @@ -0,0 +1,11 @@ +package fork_helper + +import ( + "testing" + + "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/fork" +) + +func TestMainnet_UpgradeToElectra(t *testing.T) { + fork.RunUpgradeToElectra(t, "mainnet") +} diff --git a/testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go b/testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go new file mode 100644 index 000000000000..716a7616ebf2 --- /dev/null +++ b/testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go @@ -0,0 +1,11 @@ +package fork + +import ( + "testing" + + "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/fork" +) + +func TestMinimal_UpgradeToDeneb(t *testing.T) { + fork.RunUpgradeToElectra(t, "minimal") +} diff --git a/testing/spectest/shared/electra/fork/upgrade_to_electra.go b/testing/spectest/shared/electra/fork/upgrade_to_electra.go new file mode 100644 index 000000000000..456b7325bf4b --- /dev/null +++ b/testing/spectest/shared/electra/fork/upgrade_to_electra.go @@ -0,0 +1,60 @@ +package fork + +import ( + "path" + "testing" + + "github.com/golang/snappy" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" + state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/spectest/utils" + "github.com/prysmaticlabs/prysm/v5/testing/util" + "google.golang.org/protobuf/proto" +) + +// RunUpgradeToElectra is a helper function that runs Electra's fork spec tests. +// It unmarshals a pre- and post-state to check `UpgradeToDeneb` comply with spec implementation. +func RunUpgradeToElectra(t *testing.T, config string) { + require.NoError(t, utils.SetConfig(t, config)) + + testFolders, testsFolderPath := utils.TestFolders(t, config, "electra", "fork/fork/pyspec_tests") + for _, folder := range testFolders { + t.Run(folder.Name(), func(t *testing.T) { + helpers.ClearCache() + folderPath := path.Join(testsFolderPath, folder.Name()) + + preStateFile, err := util.BazelFileBytes(path.Join(folderPath, "pre.ssz_snappy")) + require.NoError(t, err) + preStateSSZ, err := snappy.Decode(nil /* dst */, preStateFile) + require.NoError(t, err, "Failed to decompress") + preStateBase := ðpb.BeaconStateDeneb{} + if err := preStateBase.UnmarshalSSZ(preStateSSZ); err != nil { + t.Fatalf("Failed to unmarshal: %v", err) + } + preState, err := state_native.InitializeFromProtoDeneb(preStateBase) + require.NoError(t, err) + postState, err := electra.UpgradeToElectra(preState) + require.NoError(t, err) + postStateFromFunction, err := state_native.ProtobufBeaconStateElectra(postState.ToProtoUnsafe()) + require.NoError(t, err) + + postStateFile, err := util.BazelFileBytes(path.Join(folderPath, "post.ssz_snappy")) + require.NoError(t, err) + postStateSSZ, err := snappy.Decode(nil /* dst */, postStateFile) + require.NoError(t, err, "Failed to decompress") + postStateFromFile := ðpb.BeaconStateElectra{} + if err := postStateFromFile.UnmarshalSSZ(postStateSSZ); err != nil { + t.Fatalf("Failed to unmarshal: %v", err) + } + + if !proto.Equal(postStateFromFile, postStateFromFunction) { + t.Log(postStateFromFile.LatestExecutionPayloadHeader) + t.Log(postStateFromFunction.LatestExecutionPayloadHeader) + t.Fatal("Post state does not match expected") + } + }) + } +} From 38bca8815bc5056ea88cdcd99e5f0cd0f5d4e4a0 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 15:24:29 -0500 Subject: [PATCH 09/34] fixing values used in state transition logic --- beacon-chain/core/electra/BUILD.bazel | 10 +++- beacon-chain/core/electra/upgrade.go | 50 ++++++++++--------- beacon-chain/core/electra/validator.go | 1 - beacon-chain/rpc/eth/config/handlers_test.go | 3 ++ config/params/config.go | 1 + config/params/mainnet_config.go | 1 + .../mainnet/electra/fork_helper/BUILD.bazel | 7 +++ .../spectest/minimal/electra/fork/BUILD.bazel | 7 +++ .../spectest/shared/electra/fork/BUILD.bazel | 19 +++++++ 9 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 testing/spectest/mainnet/electra/fork_helper/BUILD.bazel create mode 100644 testing/spectest/minimal/electra/fork/BUILD.bazel create mode 100644 testing/spectest/shared/electra/fork/BUILD.bazel diff --git a/beacon-chain/core/electra/BUILD.bazel b/beacon-chain/core/electra/BUILD.bazel index 14afad0f3fe0..06364ced77a3 100644 --- a/beacon-chain/core/electra/BUILD.bazel +++ b/beacon-chain/core/electra/BUILD.bazel @@ -2,17 +2,25 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = ["upgrade.go"], + srcs = [ + "upgrade.go", + "validator.go", + ], importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra", visibility = ["//visibility:public"], deps = [ + "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/time:go_default_library", "//beacon-chain/state:go_default_library", "//beacon-chain/state/state-native:go_default_library", "//config/params:go_default_library", + "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", + "//math:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "//time/slots:go_default_library", + "@com_github_pkg_errors//:go_default_library", ], ) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index de6bc26fc2db..5b795ac4c9c1 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -11,8 +11,10 @@ import ( "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + "github.com/prysmaticlabs/prysm/v5/math" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/time/slots" ) // UpgradeToElectra updates inputs a generic state to return the version Electra state. @@ -95,6 +97,13 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { } earliestExitEpoch++ // Increment to find the earliest possible exit epoch + // note: should be the same in prestate and post state. + // we are deviating from the specs a bit as it calls for using the post state + tab, err := helpers.TotalActiveBalance(state) + if err != nil { + return nil, errors.Wrap(err, "failed to get total active balance") + } + s := ðpb.BeaconStateElectra{ GenesisTime: state.GenesisTime(), GenesisValidatorsRoot: state.GenesisValidatorsRoot(), @@ -149,34 +158,23 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { NextWithdrawalValidatorIndex: vi, HistoricalSummaries: summaries, - // TODO: Verify these initial electra values are correct - // They are not zero! - DepositReceiptsStartIndex: 0, + DepositReceiptsStartIndex: params.BeaconConfig().UnsetDepositReceiptsStartIndex, DepositBalanceToConsume: 0, - ExitBalanceToConsume: 0, - EarliestExitEpoch: 0, - ConsolidationBalanceToConsume: 0, - EarliestConsolidationEpoch: 0, + ExitBalanceToConsume: helpers.ActivationExitChurnLimit(math.Gwei(tab)), + EarliestExitEpoch: earliestExitEpoch, + ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(math.Gwei(tab)), + EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(state.Slot())), PendingBalanceDeposits: nil, PendingPartialWithdrawals: nil, PendingConsolidations: nil, } - tab, err := helpers.TotalActiveBalance(s) // TODO: need state readonly interface - if err != nil { - return nil, errors.Wrap(err, "failed to get total active balance") - } - - s.ExitBalanceToConsume = helpers.ActivationExitChurnLimit(tab) - s.ConsolidationBalanceToConsume = helpers.ConsolidationChurnLimit(tab) - - //# [New in Electra:EIP7251] - //# add validators that are not yet active to pending balance deposits + // [New in Electra:EIP7251] + // add validators that are not yet active to pending balance deposits // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH var preActivation []primitives.ValidatorIndex - // TODO: make this loop over validators more efficient for index, validator := range s.Validators { if validator.ActivationEpoch == params.BeaconConfig().FarFutureEpoch { preActivation = append(preActivation, primitives.ValidatorIndex(index)) @@ -192,20 +190,26 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { return s.Validators[preActivation[i]].ActivationEligibilityEpoch < s.Validators[preActivation[j]].ActivationEligibilityEpoch }) + // need to cast the state to use in helper functions + post, err := state_native.InitializeFromProtoUnsafeElectra(s) + if err != nil { + return nil, errors.Wrap(err, "failed to initialize post electra state") + } + for _, index := range preActivation { - if err := QueueEntireBalanceAndResetValidator(s, index); err != nil { + if err := QueueEntireBalanceAndResetValidator(post, index); err != nil { return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") } } - // TODO: combine below loop with above loop - //# Ensure early adopters of compounding credentials go through the activation churn + + // Ensure early adopters of compounding credentials go through the activation churn for index, validator := range s.Validators { if helpers.HasCompoundingWithdrawalCredential(validator) { - if err := QueueEntireBalanceAndResetValidator(s, primitives.ValidatorIndex(index)); err != nil { + if err := QueueEntireBalanceAndResetValidator(post, primitives.ValidatorIndex(index)); err != nil { return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") } } } - return state_native.InitializeFromProtoUnsafeElectra(s) + return post, nil } diff --git a/beacon-chain/core/electra/validator.go b/beacon-chain/core/electra/validator.go index c26491674391..bf4b1759744d 100644 --- a/beacon-chain/core/electra/validator.go +++ b/beacon-chain/core/electra/validator.go @@ -6,7 +6,6 @@ import ( "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" ) -// TODO: need to be updated from state PR // QueueEntireBalanceAndResetValidator queues the entire balance and resets the validator. This is used in electra fork logic. // // Spec definition: diff --git a/beacon-chain/rpc/eth/config/handlers_test.go b/beacon-chain/rpc/eth/config/handlers_test.go index c2f123d4b9f8..ddb7d441111b 100644 --- a/beacon-chain/rpc/eth/config/handlers_test.go +++ b/beacon-chain/rpc/eth/config/handlers_test.go @@ -149,6 +149,7 @@ func TestGetSpec(t *testing.T) { config.MaxAttestationsElectra = 89 config.MaxWithdrawalRequestsPerPayload = 90 config.MaxCellsInExtendedMatrix = 91 + config.UnsetDepositReceiptsStartIndex = 92 var dbp [4]byte copy(dbp[:], []byte{'0', '0', '0', '1'}) @@ -524,6 +525,8 @@ func TestGetSpec(t *testing.T) { assert.Equal(t, "90", v) case "MAX_CELLS_IN_EXTENDED_MATRIX": assert.Equal(t, "91", v) + case "UNSET_DEPOSIT_RECEIPTS_START_INDEX": + assert.Equal(t, "92", v) default: t.Errorf("Incorrect key: %s", k) } diff --git a/config/params/config.go b/config/params/config.go index f0624519c9f8..6bfcaf784f8a 100644 --- a/config/params/config.go +++ b/config/params/config.go @@ -250,6 +250,7 @@ type BeaconChainConfig struct { MaxPendingPartialsPerWithdrawalsSweep uint64 `yaml:"MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP" spec:"true"` // MaxPendingPartialsPerWithdrawalsSweep is the maximum number of pending partial withdrawals to process per payload. FullExitRequestAmount uint64 `yaml:"FULL_EXIT_REQUEST_AMOUNT" spec:"true"` // FullExitRequestAmount is the amount of Gwei required to request a full exit. MaxWithdrawalRequestsPerPayload uint64 `yaml:"MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD" spec:"true"` // MaxWithdrawalRequestsPerPayload is the maximum number of execution layer withdrawal requests in each payload. + UnsetDepositReceiptsStartIndex uint64 `yaml:"UNSET_DEPOSIT_RECEIPTS_START_INDEX" spec:"true"` // UnsetDepositReceiptsStartIndex is used to check the start index for eip6110 // Networking Specific Parameters GossipMaxSize uint64 `yaml:"GOSSIP_MAX_SIZE" spec:"true"` // GossipMaxSize is the maximum allowed size of uncompressed gossip messages. diff --git a/config/params/mainnet_config.go b/config/params/mainnet_config.go index ab18df129de7..a9b5de56fd69 100644 --- a/config/params/mainnet_config.go +++ b/config/params/mainnet_config.go @@ -290,6 +290,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{ MaxPendingPartialsPerWithdrawalsSweep: 8, FullExitRequestAmount: 0, MaxWithdrawalRequestsPerPayload: 16, + UnsetDepositReceiptsStartIndex: math.MaxUint64, // Values related to networking parameters. GossipMaxSize: 10 * 1 << 20, // 10 MiB diff --git a/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel b/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel new file mode 100644 index 000000000000..d58a1222f86f --- /dev/null +++ b/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel @@ -0,0 +1,7 @@ +load("@prysm//tools/go:def.bzl", "go_test") + +go_test( + name = "go_default_test", + srcs = ["upgrade_to_electra_test.go"], + deps = ["//testing/spectest/shared/electra/fork:go_default_library"], +) diff --git a/testing/spectest/minimal/electra/fork/BUILD.bazel b/testing/spectest/minimal/electra/fork/BUILD.bazel new file mode 100644 index 000000000000..d58a1222f86f --- /dev/null +++ b/testing/spectest/minimal/electra/fork/BUILD.bazel @@ -0,0 +1,7 @@ +load("@prysm//tools/go:def.bzl", "go_test") + +go_test( + name = "go_default_test", + srcs = ["upgrade_to_electra_test.go"], + deps = ["//testing/spectest/shared/electra/fork:go_default_library"], +) diff --git a/testing/spectest/shared/electra/fork/BUILD.bazel b/testing/spectest/shared/electra/fork/BUILD.bazel new file mode 100644 index 000000000000..2009436e149a --- /dev/null +++ b/testing/spectest/shared/electra/fork/BUILD.bazel @@ -0,0 +1,19 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["upgrade_to_electra.go"], + importpath = "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/fork", + visibility = ["//visibility:public"], + deps = [ + "//beacon-chain/core/electra:go_default_library", + "//beacon-chain/core/helpers:go_default_library", + "//beacon-chain/state/state-native:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//testing/require:go_default_library", + "//testing/spectest/utils:go_default_library", + "//testing/util:go_default_library", + "@com_github_golang_snappy//:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", + ], +) From de12137ce54c237287d5c4aeb7ea66743b957cd9 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 16:56:53 -0500 Subject: [PATCH 10/34] updating upgrade test --- beacon-chain/core/electra/BUILD.bazel | 15 +- beacon-chain/core/electra/upgrade.go | 4 +- beacon-chain/core/electra/upgrade_test.go | 179 +++++++++++++++++- .../state/state-native/getters_state.go | 10 - 4 files changed, 194 insertions(+), 14 deletions(-) diff --git a/beacon-chain/core/electra/BUILD.bazel b/beacon-chain/core/electra/BUILD.bazel index 06364ced77a3..1e5b2195f4ba 100644 --- a/beacon-chain/core/electra/BUILD.bazel +++ b/beacon-chain/core/electra/BUILD.bazel @@ -27,5 +27,18 @@ go_library( go_test( name = "go_default_test", srcs = ["upgrade_test.go"], - embed = [":go_default_library"], + deps = [ + ":go_default_library", + "//beacon-chain/core/helpers:go_default_library", + "//beacon-chain/core/time:go_default_library", + "//config/params:go_default_library", + "//consensus-types/primitives:go_default_library", + "//encoding/bytesutil:go_default_library", + "//math:go_default_library", + "//proto/engine/v1:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "//testing/require:go_default_library", + "//testing/util:go_default_library", + "//time/slots:go_default_library", + ], ) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 5b795ac4c9c1..ea1ddcf32ec7 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -151,8 +151,8 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { WithdrawalsRoot: wdRoot, ExcessBlobGas: excessBlobGas, BlobGasUsed: blobGasUsed, - DepositReceiptsRoot: bytesutil.Bytes32(0), - WithdrawalRequestsRoot: bytesutil.Bytes32(0), + DepositReceiptsRoot: bytesutil.Bytes32(0), // [New in Electra:EIP6110] + WithdrawalRequestsRoot: bytesutil.Bytes32(0), // [New in Electra:EIP7002] }, NextWithdrawalIndex: wi, NextWithdrawalValidatorIndex: vi, diff --git a/beacon-chain/core/electra/upgrade_test.go b/beacon-chain/core/electra/upgrade_test.go index 74252d944008..630391987d32 100644 --- a/beacon-chain/core/electra/upgrade_test.go +++ b/beacon-chain/core/electra/upgrade_test.go @@ -1 +1,178 @@ -package electra +package electra_test + +import ( + "testing" + + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + "github.com/prysmaticlabs/prysm/v5/math" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + 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/time/slots" +) + +func TestUpgradeToElectra(t *testing.T) { + st, _ := util.DeterministicGenesisStateDeneb(t, params.BeaconConfig().MaxValidatorsPerCommittee) + require.NoError(t, st.SetHistoricalRoots([][]byte{{1}})) + vals := st.Validators() + vals[0].ActivationEpoch = params.BeaconConfig().FarFutureEpoch + vals[1].WithdrawalCredentials = []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte} + require.NoError(t, st.SetValidators(vals)) + preForkState := st.Copy() + mSt, err := electra.UpgradeToElectra(st) + require.NoError(t, err) + + require.Equal(t, preForkState.GenesisTime(), mSt.GenesisTime()) + require.DeepSSZEqual(t, preForkState.GenesisValidatorsRoot(), mSt.GenesisValidatorsRoot()) + require.Equal(t, preForkState.Slot(), mSt.Slot()) + require.DeepSSZEqual(t, preForkState.LatestBlockHeader(), mSt.LatestBlockHeader()) + require.DeepSSZEqual(t, preForkState.BlockRoots(), mSt.BlockRoots()) + require.DeepSSZEqual(t, preForkState.StateRoots(), mSt.StateRoots()) + require.DeepSSZEqual(t, preForkState.Validators()[2:], mSt.Validators()[2:]) + require.DeepSSZEqual(t, preForkState.Balances()[2:], mSt.Balances()[2:]) + require.DeepSSZEqual(t, preForkState.Eth1Data(), mSt.Eth1Data()) + require.DeepSSZEqual(t, preForkState.Eth1DataVotes(), mSt.Eth1DataVotes()) + require.DeepSSZEqual(t, preForkState.Eth1DepositIndex(), mSt.Eth1DepositIndex()) + require.DeepSSZEqual(t, preForkState.RandaoMixes(), mSt.RandaoMixes()) + require.DeepSSZEqual(t, preForkState.Slashings(), mSt.Slashings()) + require.DeepSSZEqual(t, preForkState.JustificationBits(), mSt.JustificationBits()) + require.DeepSSZEqual(t, preForkState.PreviousJustifiedCheckpoint(), mSt.PreviousJustifiedCheckpoint()) + require.DeepSSZEqual(t, preForkState.CurrentJustifiedCheckpoint(), mSt.CurrentJustifiedCheckpoint()) + require.DeepSSZEqual(t, preForkState.FinalizedCheckpoint(), mSt.FinalizedCheckpoint()) + + require.Equal(t, len(preForkState.Validators()), len(mSt.Validators())) + + preVal, err := preForkState.ValidatorAtIndex(0) + require.NoError(t, err) + require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, preVal.EffectiveBalance) + + preVal2, err := preForkState.ValidatorAtIndex(1) + require.NoError(t, err) + require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, preVal2.EffectiveBalance) + + mVal, err := mSt.ValidatorAtIndex(0) + require.NoError(t, err) + require.Equal(t, uint64(0), mVal.EffectiveBalance) + + mVal2, err := mSt.ValidatorAtIndex(1) + require.NoError(t, err) + require.Equal(t, uint64(0), mVal2.EffectiveBalance) + + numValidators := mSt.NumValidators() + p, err := mSt.PreviousEpochParticipation() + require.NoError(t, err) + require.DeepSSZEqual(t, make([]byte, numValidators), p) + p, err = mSt.CurrentEpochParticipation() + require.NoError(t, err) + require.DeepSSZEqual(t, make([]byte, numValidators), p) + s, err := mSt.InactivityScores() + require.NoError(t, err) + require.DeepSSZEqual(t, make([]uint64, numValidators), s) + + hr1, err := preForkState.HistoricalRoots() + require.NoError(t, err) + hr2, err := mSt.HistoricalRoots() + require.NoError(t, err) + require.DeepEqual(t, hr1, hr2) + + f := mSt.Fork() + require.DeepSSZEqual(t, ðpb.Fork{ + PreviousVersion: st.Fork().CurrentVersion, + CurrentVersion: params.BeaconConfig().ElectraForkVersion, + Epoch: time.CurrentEpoch(st), + }, f) + csc, err := mSt.CurrentSyncCommittee() + require.NoError(t, err) + psc, err := preForkState.CurrentSyncCommittee() + require.NoError(t, err) + require.DeepSSZEqual(t, psc, csc) + nsc, err := mSt.NextSyncCommittee() + require.NoError(t, err) + psc, err = preForkState.NextSyncCommittee() + require.NoError(t, err) + require.DeepSSZEqual(t, psc, nsc) + + header, err := mSt.LatestExecutionPayloadHeader() + require.NoError(t, err) + protoHeader, ok := header.Proto().(*enginev1.ExecutionPayloadHeaderElectra) + require.Equal(t, true, ok) + prevHeader, err := preForkState.LatestExecutionPayloadHeader() + require.NoError(t, err) + txRoot, err := prevHeader.TransactionsRoot() + require.NoError(t, err) + + wdRoot, err := prevHeader.WithdrawalsRoot() + require.NoError(t, err) + wanted := &enginev1.ExecutionPayloadHeaderElectra{ + ParentHash: prevHeader.ParentHash(), + FeeRecipient: prevHeader.FeeRecipient(), + StateRoot: prevHeader.StateRoot(), + ReceiptsRoot: prevHeader.ReceiptsRoot(), + LogsBloom: prevHeader.LogsBloom(), + PrevRandao: prevHeader.PrevRandao(), + BlockNumber: prevHeader.BlockNumber(), + GasLimit: prevHeader.GasLimit(), + GasUsed: prevHeader.GasUsed(), + Timestamp: prevHeader.Timestamp(), + ExtraData: prevHeader.ExtraData(), + BaseFeePerGas: prevHeader.BaseFeePerGas(), + BlockHash: prevHeader.BlockHash(), + TransactionsRoot: txRoot, + WithdrawalsRoot: wdRoot, + DepositReceiptsRoot: bytesutil.Bytes32(0), + WithdrawalRequestsRoot: bytesutil.Bytes32(0), + } + require.DeepEqual(t, wanted, protoHeader) + + nwi, err := mSt.NextWithdrawalIndex() + require.NoError(t, err) + require.Equal(t, uint64(0), nwi) + + lwvi, err := mSt.NextWithdrawalValidatorIndex() + require.NoError(t, err) + require.Equal(t, primitives.ValidatorIndex(0), lwvi) + + summaries, err := mSt.HistoricalSummaries() + require.NoError(t, err) + require.Equal(t, 0, len(summaries)) + + startIndex, err := mSt.DepositReceiptsStartIndex() + require.NoError(t, err) + require.Equal(t, params.BeaconConfig().UnsetDepositReceiptsStartIndex, startIndex) + + balance, err := mSt.DepositBalanceToConsume() + require.NoError(t, err) + require.Equal(t, math.Gwei(0), balance) + + //TODO: need getters for ExitBalanceToConsume and EarliestExitEpoch to test + + tab, err := helpers.TotalActiveBalance(mSt) + require.NoError(t, err) + + cbtc, err := mSt.ConsolidationBalanceToConsume() + require.NoError(t, err) + require.Equal(t, helpers.ConsolidationChurnLimit(math.Gwei(tab)), cbtc) + + earliestConsolidationEpoch, err := mSt.EarliestConsolidationEpoch() + require.NoError(t, err) + require.Equal(t, helpers.ActivationExitEpoch(slots.ToEpoch(preForkState.Slot())), earliestConsolidationEpoch) + + pendingBalanceDeposits, err := mSt.PendingBalanceDeposits() + require.NoError(t, err) + require.Equal(t, 2, len(pendingBalanceDeposits)) + + numPendingPartialWithdrawals, err := mSt.NumPendingPartialWithdrawals() + require.NoError(t, err) + require.Equal(t, uint64(0), numPendingPartialWithdrawals) + + consolidations, err := mSt.PendingConsolidations() + require.NoError(t, err) + require.Equal(t, 0, len(consolidations)) + +} diff --git a/beacon-chain/state/state-native/getters_state.go b/beacon-chain/state/state-native/getters_state.go index 69ad1721f8f3..402586e63360 100644 --- a/beacon-chain/state/state-native/getters_state.go +++ b/beacon-chain/state/state-native/getters_state.go @@ -543,13 +543,3 @@ func ProtobufBeaconStateElectra(s interface{}) (*ethpb.BeaconStateElectra, error } return pbState, nil } - -// ProtobufBeaconStateElectra transforms an input into beacon state Electra in the form of protobuf. -// Error is returned if the input is not type protobuf beacon state. -func ProtobufBeaconStateElectra(s interface{}) (*ethpb.BeaconStateElectra, error) { - pbState, ok := s.(*ethpb.BeaconStateElectra) - if !ok { - return nil, errors.New("input is not type pb.ProtobufBeaconStateElectra") - } - return pbState, nil -} From 4dd8861b4906a230e03babf3bae56f854d265e98 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 17:02:02 -0500 Subject: [PATCH 11/34] gofmt --- beacon-chain/state/state-native/state_trie.go | 1 - 1 file changed, 1 deletion(-) diff --git a/beacon-chain/state/state-native/state_trie.go b/beacon-chain/state/state-native/state_trie.go index ee33e9f824b8..60dc8acd6033 100644 --- a/beacon-chain/state/state-native/state_trie.go +++ b/beacon-chain/state/state-native/state_trie.go @@ -754,7 +754,6 @@ func InitializeFromProtoUnsafeElectra(st *ethpb.BeaconStateElectra) (state.Beaco pendingPartialWithdrawals: st.PendingPartialWithdrawals, pendingConsolidations: st.PendingConsolidations, - dirtyFields: make(map[types.FieldIndex]bool, fieldCount), dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount), stateFieldLeaves: make(map[types.FieldIndex]*fieldtrie.FieldTrie, fieldCount), From eae67f715e4daceef26c961fa14ab96034b619a6 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 17:17:59 -0500 Subject: [PATCH 12/34] avoid dup word linting --- beacon-chain/core/electra/validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon-chain/core/electra/validator.go b/beacon-chain/core/electra/validator.go index bf4b1759744d..48bc8e7e2f22 100644 --- a/beacon-chain/core/electra/validator.go +++ b/beacon-chain/core/electra/validator.go @@ -12,8 +12,8 @@ import ( // // def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None: // balance = state.balances[index] -// state.balances[index] = 0 // validator = state.validators[index] +// state.balances[index] = 0 // validator.effective_balance = 0 // validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH // state.pending_balance_deposits.append( From dd36ec648b8e31364cd0897cdce6a3c3364bf81b Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 17:44:06 -0500 Subject: [PATCH 13/34] fixing spec tests for fork --- testing/spectest/mainnet/electra/fork_helper/BUILD.bazel | 6 ++++++ testing/spectest/shared/electra/fork/BUILD.bazel | 1 + 2 files changed, 7 insertions(+) diff --git a/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel b/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel index d58a1222f86f..cfac58470445 100644 --- a/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel +++ b/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel @@ -2,6 +2,12 @@ load("@prysm//tools/go:def.bzl", "go_test") go_test( name = "go_default_test", + size = "small", srcs = ["upgrade_to_electra_test.go"], + data = glob(["*.yaml"]) + [ + "@consensus_spec_tests_mainnet//:test_data", + ], + shard_count = 4, + tags = ["spectest"], deps = ["//testing/spectest/shared/electra/fork:go_default_library"], ) diff --git a/testing/spectest/shared/electra/fork/BUILD.bazel b/testing/spectest/shared/electra/fork/BUILD.bazel index 2009436e149a..eb717b704ce0 100644 --- a/testing/spectest/shared/electra/fork/BUILD.bazel +++ b/testing/spectest/shared/electra/fork/BUILD.bazel @@ -2,6 +2,7 @@ load("@prysm//tools/go:def.bzl", "go_library") go_library( name = "go_default_library", + testonly = True, srcs = ["upgrade_to_electra.go"], importpath = "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/fork", visibility = ["//visibility:public"], From 6080275d820209bc9ff4458189d79a2627ed49cd Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 20:15:16 -0500 Subject: [PATCH 14/34] gaz --- testing/spectest/mainnet/electra/fork_helper/BUILD.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel b/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel index cfac58470445..087e6d9792a5 100644 --- a/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel +++ b/testing/spectest/mainnet/electra/fork_helper/BUILD.bazel @@ -5,8 +5,8 @@ go_test( size = "small", srcs = ["upgrade_to_electra_test.go"], data = glob(["*.yaml"]) + [ - "@consensus_spec_tests_mainnet//:test_data", - ], + "@consensus_spec_tests_mainnet//:test_data", + ], shard_count = 4, tags = ["spectest"], deps = ["//testing/spectest/shared/electra/fork:go_default_library"], From abbdd1ad9e31046e473bf6ad38da887b66fb7111 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 22:47:32 -0500 Subject: [PATCH 15/34] fixing tests --- beacon-chain/core/transition/transition_test.go | 2 +- beacon-chain/rpc/eth/config/handlers_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon-chain/core/transition/transition_test.go b/beacon-chain/core/transition/transition_test.go index 3a62d637781b..30434b60e8fa 100644 --- a/beacon-chain/core/transition/transition_test.go +++ b/beacon-chain/core/transition/transition_test.go @@ -658,7 +658,7 @@ func TestProcessSlots_ThroughElectraEpoch(t *testing.T) { conf.ElectraForkEpoch = 5 params.OverrideBeaconConfig(conf) - st, _ := util.DeterministicGenesisStateCapella(t, params.BeaconConfig().MaxValidatorsPerCommittee) + st, _ := util.DeterministicGenesisStateDeneb(t, params.BeaconConfig().MaxValidatorsPerCommittee) st, err := transition.ProcessSlots(context.Background(), st, params.BeaconConfig().SlotsPerEpoch*10) require.NoError(t, err) require.Equal(t, version.Electra, st.Version()) diff --git a/beacon-chain/rpc/eth/config/handlers_test.go b/beacon-chain/rpc/eth/config/handlers_test.go index ddb7d441111b..384e1d53c950 100644 --- a/beacon-chain/rpc/eth/config/handlers_test.go +++ b/beacon-chain/rpc/eth/config/handlers_test.go @@ -192,7 +192,7 @@ func TestGetSpec(t *testing.T) { data, ok := resp.Data.(map[string]interface{}) require.Equal(t, true, ok) - assert.Equal(t, 153, len(data)) + assert.Equal(t, 154, len(data)) for k, v := range data { t.Run(k, func(t *testing.T) { switch k { From 0b34cf9b8b2b1b0f4bf53557793adf86a8a886e9 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 23:26:04 -0500 Subject: [PATCH 16/34] improving unit test with new getters --- beacon-chain/core/electra/upgrade_test.go | 10 ++++- beacon-chain/state/interfaces.go | 7 +++ beacon-chain/state/state-native/BUILD.bazel | 2 + .../state/state-native/getters_exit.go | 29 ++++++++++++ .../state/state-native/getters_exit_test.go | 44 +++++++++++++++++++ .../electra/fork/upgrade_to_electra_test.go | 2 +- 6 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 beacon-chain/state/state-native/getters_exit.go create mode 100644 beacon-chain/state/state-native/getters_exit_test.go diff --git a/beacon-chain/core/electra/upgrade_test.go b/beacon-chain/core/electra/upgrade_test.go index 630391987d32..36e9cab4747c 100644 --- a/beacon-chain/core/electra/upgrade_test.go +++ b/beacon-chain/core/electra/upgrade_test.go @@ -150,11 +150,17 @@ func TestUpgradeToElectra(t *testing.T) { require.NoError(t, err) require.Equal(t, math.Gwei(0), balance) - //TODO: need getters for ExitBalanceToConsume and EarliestExitEpoch to test - tab, err := helpers.TotalActiveBalance(mSt) require.NoError(t, err) + ebtc, err := mSt.ExitBalanceToConsume() + require.NoError(t, err) + require.Equal(t, helpers.ActivationExitChurnLimit(math.Gwei(tab)), ebtc) + + eee, err := mSt.EarliestExitEpoch() + require.NoError(t, err) + require.Equal(t, primitives.Epoch(1), eee) + cbtc, err := mSt.ConsolidationBalanceToConsume() require.NoError(t, err) require.Equal(t, helpers.ConsolidationChurnLimit(math.Gwei(tab)), cbtc) diff --git a/beacon-chain/state/interfaces.go b/beacon-chain/state/interfaces.go index 8dc8876f2b96..c255ff9fc762 100644 --- a/beacon-chain/state/interfaces.go +++ b/beacon-chain/state/interfaces.go @@ -49,6 +49,7 @@ type ReadOnlyBeaconState interface { ReadOnlyStateRoots ReadOnlyRandaoMixes ReadOnlyEth1Data + ReadOnlyExits ReadOnlyValidators ReadOnlyBalances ReadOnlyCheckpoint @@ -179,6 +180,12 @@ type ReadOnlyEth1Data interface { Eth1DepositIndex() uint64 } +// ReadOnlyExits defines a struct which only has read access to Exit related methods. +type ReadOnlyExits interface { + ExitBalanceToConsume() (math.Gwei, error) + EarliestExitEpoch() (primitives.Epoch, error) +} + // ReadOnlyAttestations defines a struct which only has read access to attestations methods. type ReadOnlyAttestations interface { PreviousEpochAttestations() ([]*ethpb.PendingAttestation, error) diff --git a/beacon-chain/state/state-native/BUILD.bazel b/beacon-chain/state/state-native/BUILD.bazel index 1d16f099eee1..3f8760c2a411 100644 --- a/beacon-chain/state/state-native/BUILD.bazel +++ b/beacon-chain/state/state-native/BUILD.bazel @@ -14,6 +14,7 @@ go_library( "getters_consolidation.go", "getters_deposit_receipts.go", "getters_eth1.go", + "getters_exit.go", "getters_misc.go", "getters_participation.go", "getters_payload_header.go", @@ -94,6 +95,7 @@ go_test( "getters_checkpoint_test.go", "getters_consolidation_test.go", "getters_deposit_receipts_test.go", + "getters_exit_test.go", "getters_participation_test.go", "getters_test.go", "getters_validator_test.go", diff --git a/beacon-chain/state/state-native/getters_exit.go b/beacon-chain/state/state-native/getters_exit.go new file mode 100644 index 000000000000..12be6844e05c --- /dev/null +++ b/beacon-chain/state/state-native/getters_exit.go @@ -0,0 +1,29 @@ +package state_native + +import ( + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/math" + "github.com/prysmaticlabs/prysm/v5/runtime/version" +) + +// ExitBalanceToConsume is used for returning the ExitBalanceToConsume as part of eip 7251 +func (b *BeaconState) ExitBalanceToConsume() (math.Gwei, error) { + if b.version < version.Electra { + return 0, errNotSupported("ExitBalanceToConsume", b.version) + } + b.lock.RLock() + defer b.lock.RUnlock() + + return b.exitBalanceToConsume, nil +} + +// EarliestExitEpoch is used for returning the EarliestExitEpoch as part of eip 7251 +func (b *BeaconState) EarliestExitEpoch() (primitives.Epoch, error) { + if b.version < version.Electra { + return 0, errNotSupported("EarliestExitEpoch", b.version) + } + b.lock.RLock() + defer b.lock.RUnlock() + + return b.earliestExitEpoch, nil +} diff --git a/beacon-chain/state/state-native/getters_exit_test.go b/beacon-chain/state/state-native/getters_exit_test.go new file mode 100644 index 000000000000..1e3287cd191d --- /dev/null +++ b/beacon-chain/state/state-native/getters_exit_test.go @@ -0,0 +1,44 @@ +package state_native_test + +import ( + "testing" + + state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/math" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/util" +) + +func TestExitBalanceToConsume(t *testing.T) { + t.Run("previous fork returns expected error", func(t *testing.T) { + dState, _ := util.DeterministicGenesisState(t, 1) + _, err := dState.ExitBalanceToConsume() + require.ErrorContains(t, "is not supported", err) + }) + t.Run("electra returns expected value", func(t *testing.T) { + want := math.Gwei(2) + dState, err := state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{ExitBalanceToConsume: want}) + require.NoError(t, err) + got, err := dState.ExitBalanceToConsume() + require.NoError(t, err) + require.Equal(t, want, got) + }) +} + +func TestEarliestExitEpoch(t *testing.T) { + t.Run("previous fork returns expected error", func(t *testing.T) { + dState, _ := util.DeterministicGenesisState(t, 1) + _, err := dState.EarliestExitEpoch() + require.ErrorContains(t, "is not supported", err) + }) + t.Run("electra returns expected value", func(t *testing.T) { + want := primitives.Epoch(2) + dState, err := state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{EarliestExitEpoch: want}) + require.NoError(t, err) + got, err := dState.EarliestExitEpoch() + require.NoError(t, err) + require.Equal(t, want, got) + }) +} diff --git a/testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go b/testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go index 716a7616ebf2..de6570fa2ff5 100644 --- a/testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go +++ b/testing/spectest/minimal/electra/fork/upgrade_to_electra_test.go @@ -6,6 +6,6 @@ import ( "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/fork" ) -func TestMinimal_UpgradeToDeneb(t *testing.T) { +func TestMinimal_UpgradeToElectra(t *testing.T) { fork.RunUpgradeToElectra(t, "minimal") } From 5cfe8d24c95063178c38f998a85fc72597421bb3 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 6 May 2024 23:29:14 -0500 Subject: [PATCH 17/34] fixing bazel for minimal fork test --- testing/spectest/minimal/electra/fork/BUILD.bazel | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/testing/spectest/minimal/electra/fork/BUILD.bazel b/testing/spectest/minimal/electra/fork/BUILD.bazel index d58a1222f86f..5094ddda3586 100644 --- a/testing/spectest/minimal/electra/fork/BUILD.bazel +++ b/testing/spectest/minimal/electra/fork/BUILD.bazel @@ -2,6 +2,16 @@ load("@prysm//tools/go:def.bzl", "go_test") go_test( name = "go_default_test", + size = "small", srcs = ["upgrade_to_electra_test.go"], + data = glob(["*.yaml"]) + [ + "@consensus_spec_tests_minimal//:test_data", + ], + eth_network = "minimal", + shard_count = 4, + tags = [ + "minimal", + "spectest", + ], deps = ["//testing/spectest/shared/electra/fork:go_default_library"], ) From 3cf41ee588f08242ed991766d31af24141a923e5 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 10:06:01 -0500 Subject: [PATCH 18/34] adding bazel file --- testing/spectest/shared/electra/fork/BUILD.bazel | 2 ++ testing/spectest/shared/electra/fork/upgrade_to_electra.go | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/testing/spectest/shared/electra/fork/BUILD.bazel b/testing/spectest/shared/electra/fork/BUILD.bazel index eb717b704ce0..25a3a1959e83 100644 --- a/testing/spectest/shared/electra/fork/BUILD.bazel +++ b/testing/spectest/shared/electra/fork/BUILD.bazel @@ -15,6 +15,8 @@ go_library( "//testing/spectest/utils:go_default_library", "//testing/util:go_default_library", "@com_github_golang_snappy//:go_default_library", + "@com_github_google_go_cmp//cmp:go_default_library", "@org_golang_google_protobuf//proto:go_default_library", + "@org_golang_google_protobuf//testing/protocmp:go_default_library", ], ) diff --git a/testing/spectest/shared/electra/fork/upgrade_to_electra.go b/testing/spectest/shared/electra/fork/upgrade_to_electra.go index 456b7325bf4b..b35e1c59dc90 100644 --- a/testing/spectest/shared/electra/fork/upgrade_to_electra.go +++ b/testing/spectest/shared/electra/fork/upgrade_to_electra.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/golang/snappy" + "github.com/google/go-cmp/cmp" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native" @@ -13,6 +14,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/testing/spectest/utils" "github.com/prysmaticlabs/prysm/v5/testing/util" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" ) // RunUpgradeToElectra is a helper function that runs Electra's fork spec tests. @@ -51,8 +53,7 @@ func RunUpgradeToElectra(t *testing.T, config string) { } if !proto.Equal(postStateFromFile, postStateFromFunction) { - t.Log(postStateFromFile.LatestExecutionPayloadHeader) - t.Log(postStateFromFunction.LatestExecutionPayloadHeader) + t.Log(cmp.Diff(postStateFromFile, postStateFromFunction, protocmp.Transform())) t.Fatal("Post state does not match expected") } }) From 4cee2cb70f8888ff3f50289b5dff7607b818b319 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Tue, 7 May 2024 12:56:35 -0500 Subject: [PATCH 19/34] Update beacon-chain/core/electra/upgrade.go Co-authored-by: Preston Van Loon --- beacon-chain/core/electra/upgrade.go | 1 - 1 file changed, 1 deletion(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index ea1ddcf32ec7..95c8a8a03c1c 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -78,7 +78,6 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { return nil, err } - // RTFM: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/fork.md // Find the earliest exit epoch exitEpochs := make([]primitives.Epoch, 0) for _, v := range state.Validators() { From 78af849eeff0c9d97c095be541a50830aa69f036 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 14:37:25 -0500 Subject: [PATCH 20/34] addressing some comments and adding more tests --- beacon-chain/core/electra/BUILD.bazel | 5 +- beacon-chain/core/electra/upgrade.go | 217 ++++++++++++---- beacon-chain/core/electra/validator_test.go | 30 +++ testing/util/BUILD.bazel | 2 + testing/util/electra_state.go | 270 ++++++++++++++++++++ 5 files changed, 470 insertions(+), 54 deletions(-) create mode 100644 beacon-chain/core/electra/validator_test.go create mode 100644 testing/util/electra_state.go diff --git a/beacon-chain/core/electra/BUILD.bazel b/beacon-chain/core/electra/BUILD.bazel index 1e5b2195f4ba..4918aa37f56f 100644 --- a/beacon-chain/core/electra/BUILD.bazel +++ b/beacon-chain/core/electra/BUILD.bazel @@ -26,7 +26,10 @@ go_library( go_test( name = "go_default_test", - srcs = ["upgrade_test.go"], + srcs = [ + "upgrade_test.go", + "validator_test.go", + ], deps = [ ":go_default_library", "//beacon-chain/core/helpers:go_default_library", diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 95c8a8a03c1c..b10c870675b1 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -18,30 +18,141 @@ import ( ) // UpgradeToElectra updates inputs a generic state to return the version Electra state. -func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { - epoch := time.CurrentEpoch(state) +// def upgrade_to_electra(pre: deneb.BeaconState) -> BeaconState: +// +// epoch = deneb.get_current_epoch(pre) +// latest_execution_payload_header = ExecutionPayloadHeader( +// parent_hash=pre.latest_execution_payload_header.parent_hash, +// fee_recipient=pre.latest_execution_payload_header.fee_recipient, +// state_root=pre.latest_execution_payload_header.state_root, +// receipts_root=pre.latest_execution_payload_header.receipts_root, +// logs_bloom=pre.latest_execution_payload_header.logs_bloom, +// prev_randao=pre.latest_execution_payload_header.prev_randao, +// block_number=pre.latest_execution_payload_header.block_number, +// gas_limit=pre.latest_execution_payload_header.gas_limit, +// gas_used=pre.latest_execution_payload_header.gas_used, +// timestamp=pre.latest_execution_payload_header.timestamp, +// extra_data=pre.latest_execution_payload_header.extra_data, +// base_fee_per_gas=pre.latest_execution_payload_header.base_fee_per_gas, +// block_hash=pre.latest_execution_payload_header.block_hash, +// transactions_root=pre.latest_execution_payload_header.transactions_root, +// withdrawals_root=pre.latest_execution_payload_header.withdrawals_root, +// blob_gas_used=pre.latest_execution_payload_header.blob_gas_used, +// excess_blob_gas=pre.latest_execution_payload_header.excess_blob_gas, +// deposit_receipts_root=Root(), # [New in Electra:EIP6110] +// withdrawal_requests_root=Root(), # [New in Electra:EIP7002], +// ) +// +// exit_epochs = [v.exit_epoch for v in pre.validators if v.exit_epoch != FAR_FUTURE_EPOCH] +// if not exit_epochs: +// exit_epochs = [get_current_epoch(pre)] +// earliest_exit_epoch = max(exit_epochs) + 1 +// +// post = BeaconState( +// # Versioning +// genesis_time=pre.genesis_time, +// genesis_validators_root=pre.genesis_validators_root, +// slot=pre.slot, +// fork=Fork( +// previous_version=pre.fork.current_version, +// current_version=ELECTRA_FORK_VERSION, # [Modified in Electra:EIP6110] +// epoch=epoch, +// ), +// # History +// latest_block_header=pre.latest_block_header, +// block_roots=pre.block_roots, +// state_roots=pre.state_roots, +// historical_roots=pre.historical_roots, +// # Eth1 +// eth1_data=pre.eth1_data, +// eth1_data_votes=pre.eth1_data_votes, +// eth1_deposit_index=pre.eth1_deposit_index, +// # Registry +// validators=pre.validators, +// balances=pre.balances, +// # Randomness +// randao_mixes=pre.randao_mixes, +// # Slashings +// slashings=pre.slashings, +// # Participation +// previous_epoch_participation=pre.previous_epoch_participation, +// current_epoch_participation=pre.current_epoch_participation, +// # Finality +// justification_bits=pre.justification_bits, +// previous_justified_checkpoint=pre.previous_justified_checkpoint, +// current_justified_checkpoint=pre.current_justified_checkpoint, +// finalized_checkpoint=pre.finalized_checkpoint, +// # Inactivity +// inactivity_scores=pre.inactivity_scores, +// # Sync +// current_sync_committee=pre.current_sync_committee, +// next_sync_committee=pre.next_sync_committee, +// # Execution-layer +// latest_execution_payload_header=latest_execution_payload_header, # [Modified in Electra:EIP6110:EIP7002] +// # Withdrawals +// next_withdrawal_index=pre.next_withdrawal_index, +// next_withdrawal_validator_index=pre.next_withdrawal_validator_index, +// # Deep history valid from Capella onwards +// historical_summaries=pre.historical_summaries, +// # [New in Electra:EIP6110] +// deposit_receipts_start_index=UNSET_DEPOSIT_RECEIPTS_START_INDEX, +// # [New in Electra:EIP7251] +// deposit_balance_to_consume=0, +// exit_balance_to_consume=0, +// earliest_exit_epoch=earliest_exit_epoch, +// consolidation_balance_to_consume=0, +// earliest_consolidation_epoch=compute_activation_exit_epoch(get_current_epoch(pre)), +// pending_balance_deposits=[], +// pending_partial_withdrawals=[], +// pending_consolidations=[], +// ) +// +// post.exit_balance_to_consume = get_activation_exit_churn_limit(post) +// post.consolidation_balance_to_consume = get_consolidation_churn_limit(post) +// +// # [New in Electra:EIP7251] +// # add validators that are not yet active to pending balance deposits +// pre_activation = sorted([ +// index for index, validator in enumerate(post.validators) +// if validator.activation_epoch == FAR_FUTURE_EPOCH +// ], key=lambda index: ( +// post.validators[index].activation_eligibility_epoch, +// index +// )) +// +// for index in pre_activation: +// queue_entire_balance_and_reset_validator(post, ValidatorIndex(index)) +// +// # Ensure early adopters of compounding credentials go through the activation churn +// for index, validator in enumerate(post.validators): +// if has_compounding_withdrawal_credential(validator): +// queue_excess_active_balance(post, ValidatorIndex(index)) +// +// return post +func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) { + epoch := time.CurrentEpoch(beaconState) - currentSyncCommittee, err := state.CurrentSyncCommittee() + currentSyncCommittee, err := beaconState.CurrentSyncCommittee() if err != nil { return nil, err } - nextSyncCommittee, err := state.NextSyncCommittee() + nextSyncCommittee, err := beaconState.NextSyncCommittee() if err != nil { return nil, err } - prevEpochParticipation, err := state.PreviousEpochParticipation() + prevEpochParticipation, err := beaconState.PreviousEpochParticipation() if err != nil { return nil, err } - currentEpochParticipation, err := state.CurrentEpochParticipation() + currentEpochParticipation, err := beaconState.CurrentEpochParticipation() if err != nil { return nil, err } - inactivityScores, err := state.InactivityScores() + inactivityScores, err := beaconState.InactivityScores() if err != nil { return nil, err } - payloadHeader, err := state.LatestExecutionPayloadHeader() + payloadHeader, err := beaconState.LatestExecutionPayloadHeader() if err != nil { return nil, err } @@ -53,19 +164,19 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { if err != nil { return nil, err } - wi, err := state.NextWithdrawalIndex() + wi, err := beaconState.NextWithdrawalIndex() if err != nil { return nil, err } - vi, err := state.NextWithdrawalValidatorIndex() + vi, err := beaconState.NextWithdrawalValidatorIndex() if err != nil { return nil, err } - summaries, err := state.HistoricalSummaries() + summaries, err := beaconState.HistoricalSummaries() if err != nil { return nil, err } - historicalRoots, err := state.HistoricalRoots() + historicalRoots, err := beaconState.HistoricalRoots() if err != nil { return nil, err } @@ -80,13 +191,25 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { // Find the earliest exit epoch exitEpochs := make([]primitives.Epoch, 0) - for _, v := range state.Validators() { - if v.ExitEpoch != params.BeaconConfig().FarFutureEpoch { - exitEpochs = append(exitEpochs, v.ExitEpoch) + // [New in Electra:EIP7251] + // add validators that are not yet active to pending balance deposits + + // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH + preActivation := make([]primitives.ValidatorIndex, 0) + + if err = beaconState.ReadFromEveryValidator(func(index int, val state.ReadOnlyValidator) error { + if val.ExitEpoch() != params.BeaconConfig().FarFutureEpoch { + exitEpochs = append(exitEpochs, val.ExitEpoch()) } + if val.ActivationEpoch() == params.BeaconConfig().FarFutureEpoch { + preActivation = append(preActivation, primitives.ValidatorIndex(index)) + } + return nil + }); err != nil { + return nil, err } if len(exitEpochs) == 0 { - exitEpochs = append(exitEpochs, time.CurrentEpoch(state)) + exitEpochs = append(exitEpochs, time.CurrentEpoch(beaconState)) } var earliestExitEpoch primitives.Epoch for _, e := range exitEpochs { @@ -96,39 +219,39 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { } earliestExitEpoch++ // Increment to find the earliest possible exit epoch - // note: should be the same in prestate and post state. - // we are deviating from the specs a bit as it calls for using the post state - tab, err := helpers.TotalActiveBalance(state) + // note: should be the same in prestate and post beaconState. + // we are deviating from the specs a bit as it calls for using the post beaconState + tab, err := helpers.TotalActiveBalance(beaconState) if err != nil { return nil, errors.Wrap(err, "failed to get total active balance") } s := ðpb.BeaconStateElectra{ - GenesisTime: state.GenesisTime(), - GenesisValidatorsRoot: state.GenesisValidatorsRoot(), - Slot: state.Slot(), + GenesisTime: beaconState.GenesisTime(), + GenesisValidatorsRoot: beaconState.GenesisValidatorsRoot(), + Slot: beaconState.Slot(), Fork: ðpb.Fork{ - PreviousVersion: state.Fork().CurrentVersion, + PreviousVersion: beaconState.Fork().CurrentVersion, CurrentVersion: params.BeaconConfig().ElectraForkVersion, Epoch: epoch, }, - LatestBlockHeader: state.LatestBlockHeader(), - BlockRoots: state.BlockRoots(), - StateRoots: state.StateRoots(), + LatestBlockHeader: beaconState.LatestBlockHeader(), + BlockRoots: beaconState.BlockRoots(), + StateRoots: beaconState.StateRoots(), HistoricalRoots: historicalRoots, - Eth1Data: state.Eth1Data(), - Eth1DataVotes: state.Eth1DataVotes(), - Eth1DepositIndex: state.Eth1DepositIndex(), - Validators: state.Validators(), - Balances: state.Balances(), - RandaoMixes: state.RandaoMixes(), - Slashings: state.Slashings(), + Eth1Data: beaconState.Eth1Data(), + Eth1DataVotes: beaconState.Eth1DataVotes(), + Eth1DepositIndex: beaconState.Eth1DepositIndex(), + Validators: beaconState.Validators(), + Balances: beaconState.Balances(), + RandaoMixes: beaconState.RandaoMixes(), + Slashings: beaconState.Slashings(), PreviousEpochParticipation: prevEpochParticipation, CurrentEpochParticipation: currentEpochParticipation, - JustificationBits: state.JustificationBits(), - PreviousJustifiedCheckpoint: state.PreviousJustifiedCheckpoint(), - CurrentJustifiedCheckpoint: state.CurrentJustifiedCheckpoint(), - FinalizedCheckpoint: state.FinalizedCheckpoint(), + JustificationBits: beaconState.JustificationBits(), + PreviousJustifiedCheckpoint: beaconState.PreviousJustifiedCheckpoint(), + CurrentJustifiedCheckpoint: beaconState.CurrentJustifiedCheckpoint(), + FinalizedCheckpoint: beaconState.FinalizedCheckpoint(), InactivityScores: inactivityScores, CurrentSyncCommittee: currentSyncCommittee, NextSyncCommittee: nextSyncCommittee, @@ -162,24 +285,12 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { ExitBalanceToConsume: helpers.ActivationExitChurnLimit(math.Gwei(tab)), EarliestExitEpoch: earliestExitEpoch, ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(math.Gwei(tab)), - EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(state.Slot())), + EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(beaconState.Slot())), PendingBalanceDeposits: nil, PendingPartialWithdrawals: nil, PendingConsolidations: nil, } - // [New in Electra:EIP7251] - // add validators that are not yet active to pending balance deposits - - // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH - var preActivation []primitives.ValidatorIndex - - for index, validator := range s.Validators { - if validator.ActivationEpoch == params.BeaconConfig().FarFutureEpoch { - preActivation = append(preActivation, primitives.ValidatorIndex(index)) - } - } - // Sorting preActivation based on a custom criteria sort.Slice(preActivation, func(i, j int) bool { // Comparing based on ActivationEligibilityEpoch and then by index if the epochs are the same @@ -189,10 +300,10 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { return s.Validators[preActivation[i]].ActivationEligibilityEpoch < s.Validators[preActivation[j]].ActivationEligibilityEpoch }) - // need to cast the state to use in helper functions + // need to cast the beaconState to use in helper functions post, err := state_native.InitializeFromProtoUnsafeElectra(s) if err != nil { - return nil, errors.Wrap(err, "failed to initialize post electra state") + return nil, errors.Wrap(err, "failed to initialize post electra beaconState") } for _, index := range preActivation { @@ -202,7 +313,7 @@ func UpgradeToElectra(state state.BeaconState) (state.BeaconState, error) { } // Ensure early adopters of compounding credentials go through the activation churn - for index, validator := range s.Validators { + for index, validator := range post.Validators() { if helpers.HasCompoundingWithdrawalCredential(validator) { if err := QueueEntireBalanceAndResetValidator(post, primitives.ValidatorIndex(index)); err != nil { return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") diff --git a/beacon-chain/core/electra/validator_test.go b/beacon-chain/core/electra/validator_test.go new file mode 100644 index 000000000000..362bcf806258 --- /dev/null +++ b/beacon-chain/core/electra/validator_test.go @@ -0,0 +1,30 @@ +package electra_test + +import ( + "testing" + + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/util" +) + +func TestQueueEntireBalanceAndResetValidator_Ok(t *testing.T) { + st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee) + val, err := st.ValidatorAtIndex(0) + require.NoError(t, err) + require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, val.EffectiveBalance) + pbd, err := st.PendingBalanceDeposits() + require.NoError(t, err) + require.Equal(t, 0, len(pbd)) + err = electra.QueueEntireBalanceAndResetValidator(st, 0) + require.NoError(t, err) + + pbd, err = st.PendingBalanceDeposits() + require.NoError(t, err) + require.Equal(t, 1, len(pbd)) + + val, err = st.ValidatorAtIndex(0) + require.NoError(t, err) + require.Equal(t, uint64(0), val.EffectiveBalance) +} diff --git a/testing/util/BUILD.bazel b/testing/util/BUILD.bazel index 7871191c5ad3..921d39161c9d 100644 --- a/testing/util/BUILD.bazel +++ b/testing/util/BUILD.bazel @@ -17,6 +17,7 @@ go_library( "deneb_state.go", "deposits.go", "electra.go", + "electra_state.go", "helpers.go", "merge.go", "state.go", @@ -48,6 +49,7 @@ go_library( "//crypto/hash:go_default_library", "//crypto/rand:go_default_library", "//encoding/bytesutil:go_default_library", + "//math:go_default_library", "//network/forks:go_default_library", "//proto/engine/v1:go_default_library", "//proto/eth/v1:go_default_library", diff --git a/testing/util/electra_state.go b/testing/util/electra_state.go new file mode 100644 index 000000000000..922f1d0584a6 --- /dev/null +++ b/testing/util/electra_state.go @@ -0,0 +1,270 @@ +package util + +import ( + "context" + "testing" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" + state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" + "github.com/prysmaticlabs/prysm/v5/math" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/time/slots" +) + +// DeterministicGenesisStateElectra returns a genesis state in Deneb format made using the deterministic deposits. +func DeterministicGenesisStateElectra(t testing.TB, numValidators uint64) (state.BeaconState, []bls.SecretKey) { + deposits, privKeys, err := DeterministicDepositsAndKeys(numValidators) + if err != nil { + t.Fatal(errors.Wrapf(err, "failed to get %d deposits", numValidators)) + } + eth1Data, err := DeterministicEth1Data(len(deposits)) + if err != nil { + t.Fatal(errors.Wrapf(err, "failed to get eth1data for %d deposits", numValidators)) + } + beaconState, err := genesisBeaconStateElectra(context.Background(), deposits, uint64(0), eth1Data) + if err != nil { + t.Fatal(errors.Wrapf(err, "failed to get genesis beacon state of %d validators", numValidators)) + } + resetCache() + return beaconState, privKeys +} + +// genesisBeaconStateElectra returns the genesis beacon state. +func genesisBeaconStateElectra(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data) (state.BeaconState, error) { + st, err := emptyGenesisStateElectra() + if err != nil { + return nil, err + } + + // Process initial deposits. + st, err = helpers.UpdateGenesisEth1Data(st, deposits, eth1Data) + if err != nil { + return nil, err + } + + st, err = processPreGenesisDeposits(ctx, st, deposits) + if err != nil { + return nil, errors.Wrap(err, "could not process validator deposits") + } + + return buildGenesisBeaconStateElectra(genesisTime, st, st.Eth1Data()) +} + +// emptyGenesisStateDeneb returns an empty genesis state in Deneb format. +func emptyGenesisStateElectra() (state.BeaconState, error) { + st := ðpb.BeaconStateElectra{ + // Misc fields. + Slot: 0, + Fork: ðpb.Fork{ + PreviousVersion: params.BeaconConfig().BellatrixForkVersion, + CurrentVersion: params.BeaconConfig().DenebForkVersion, + Epoch: 0, + }, + // Validator registry fields. + Validators: []*ethpb.Validator{}, + Balances: []uint64{}, + InactivityScores: []uint64{}, + + JustificationBits: []byte{0}, + HistoricalRoots: [][]byte{}, + CurrentEpochParticipation: []byte{}, + PreviousEpochParticipation: []byte{}, + + // Eth1 data. + Eth1Data: ðpb.Eth1Data{}, + Eth1DataVotes: []*ethpb.Eth1Data{}, + Eth1DepositIndex: 0, + + LatestExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderElectra{}, + } + return state_native.InitializeFromProtoElectra(st) +} + +func buildGenesisBeaconStateElectra(genesisTime uint64, preState state.BeaconState, eth1Data *ethpb.Eth1Data) (state.BeaconState, error) { + if eth1Data == nil { + return nil, errors.New("no eth1data provided for genesis state") + } + + randaoMixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector) + for i := 0; i < len(randaoMixes); i++ { + h := make([]byte, 32) + copy(h, eth1Data.BlockHash) + randaoMixes[i] = h + } + + zeroHash := params.BeaconConfig().ZeroHash[:] + + activeIndexRoots := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector) + for i := 0; i < len(activeIndexRoots); i++ { + activeIndexRoots[i] = zeroHash + } + + blockRoots := make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot) + for i := 0; i < len(blockRoots); i++ { + blockRoots[i] = zeroHash + } + + stateRoots := make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot) + for i := 0; i < len(stateRoots); i++ { + stateRoots[i] = zeroHash + } + + slashings := make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector) + + genesisValidatorsRoot, err := stateutil.ValidatorRegistryRoot(preState.Validators()) + if err != nil { + return nil, errors.Wrapf(err, "could not hash tree root genesis validators %v", err) + } + + prevEpochParticipation, err := preState.PreviousEpochParticipation() + if err != nil { + return nil, err + } + currEpochParticipation, err := preState.CurrentEpochParticipation() + if err != nil { + return nil, err + } + scores, err := preState.InactivityScores() + if err != nil { + return nil, err + } + tab, err := helpers.TotalActiveBalance(preState) + if err != nil { + return nil, err + } + st := ðpb.BeaconStateElectra{ + // Misc fields. + Slot: 0, + GenesisTime: genesisTime, + GenesisValidatorsRoot: genesisValidatorsRoot[:], + + Fork: ðpb.Fork{ + PreviousVersion: params.BeaconConfig().GenesisForkVersion, + CurrentVersion: params.BeaconConfig().GenesisForkVersion, + Epoch: 0, + }, + + // Validator registry fields. + Validators: preState.Validators(), + Balances: preState.Balances(), + PreviousEpochParticipation: prevEpochParticipation, + CurrentEpochParticipation: currEpochParticipation, + InactivityScores: scores, + + // Randomness and committees. + RandaoMixes: randaoMixes, + + // Finality. + PreviousJustifiedCheckpoint: ðpb.Checkpoint{ + Epoch: 0, + Root: params.BeaconConfig().ZeroHash[:], + }, + CurrentJustifiedCheckpoint: ðpb.Checkpoint{ + Epoch: 0, + Root: params.BeaconConfig().ZeroHash[:], + }, + JustificationBits: []byte{0}, + FinalizedCheckpoint: ðpb.Checkpoint{ + Epoch: 0, + Root: params.BeaconConfig().ZeroHash[:], + }, + + HistoricalRoots: [][]byte{}, + BlockRoots: blockRoots, + StateRoots: stateRoots, + Slashings: slashings, + + // Eth1 data. + Eth1Data: eth1Data, + Eth1DataVotes: []*ethpb.Eth1Data{}, + Eth1DepositIndex: preState.Eth1DepositIndex(), + + //Electra Data + DepositReceiptsStartIndex: params.BeaconConfig().UnsetDepositReceiptsStartIndex, + ExitBalanceToConsume: helpers.ActivationExitChurnLimit(math.Gwei(tab)), + EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(preState.Slot())), + ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(math.Gwei(tab)), + } + + var scBits [fieldparams.SyncAggregateSyncCommitteeBytesLength]byte + bodyRoot, err := (ðpb.BeaconBlockBodyElectra{ + RandaoReveal: make([]byte, 96), + Eth1Data: ðpb.Eth1Data{ + DepositRoot: make([]byte, 32), + BlockHash: make([]byte, 32), + }, + Graffiti: make([]byte, 32), + SyncAggregate: ðpb.SyncAggregate{ + SyncCommitteeBits: scBits[:], + SyncCommitteeSignature: make([]byte, 96), + }, + ExecutionPayload: &enginev1.ExecutionPayloadElectra{ + ParentHash: make([]byte, 32), + FeeRecipient: make([]byte, 20), + StateRoot: make([]byte, 32), + ReceiptsRoot: make([]byte, 32), + LogsBloom: make([]byte, 256), + PrevRandao: make([]byte, 32), + ExtraData: make([]byte, 0), + BaseFeePerGas: make([]byte, 32), + BlockHash: make([]byte, 32), + Transactions: make([][]byte, 0), + Withdrawals: make([]*enginev1.Withdrawal, 0), + DepositReceipts: make([]*enginev1.DepositReceipt, 0), + WithdrawalRequests: make([]*enginev1.ExecutionLayerWithdrawalRequest, 0), + }, + }).HashTreeRoot() + if err != nil { + return nil, errors.Wrap(err, "could not hash tree root empty block body") + } + + st.LatestBlockHeader = ðpb.BeaconBlockHeader{ + ParentRoot: zeroHash, + StateRoot: zeroHash, + BodyRoot: bodyRoot[:], + } + + var pubKeys [][]byte + vals := preState.Validators() + for i := uint64(0); i < params.BeaconConfig().SyncCommitteeSize; i++ { + j := i % uint64(len(vals)) + pubKeys = append(pubKeys, vals[j].PublicKey) + } + aggregated, err := bls.AggregatePublicKeys(pubKeys) + if err != nil { + return nil, err + } + st.CurrentSyncCommittee = ðpb.SyncCommittee{ + Pubkeys: pubKeys, + AggregatePubkey: aggregated.Marshal(), + } + st.NextSyncCommittee = ðpb.SyncCommittee{ + Pubkeys: pubKeys, + AggregatePubkey: aggregated.Marshal(), + } + + st.LatestExecutionPayloadHeader = &enginev1.ExecutionPayloadHeaderElectra{ + ParentHash: make([]byte, 32), + FeeRecipient: make([]byte, 20), + StateRoot: make([]byte, 32), + ReceiptsRoot: make([]byte, 32), + LogsBloom: make([]byte, 256), + PrevRandao: make([]byte, 32), + ExtraData: make([]byte, 0), + BaseFeePerGas: make([]byte, 32), + BlockHash: make([]byte, 32), + TransactionsRoot: make([]byte, 32), + WithdrawalsRoot: make([]byte, 32), + DepositReceiptsRoot: make([]byte, 32), + WithdrawalRequestsRoot: make([]byte, 32), + } + + return state_native.InitializeFromProtoElectra(st) +} From 0897beae3cfff58274798084150afe107a398327 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 15:25:34 -0500 Subject: [PATCH 21/34] addressing more feedback --- beacon-chain/core/electra/upgrade.go | 30 ++++++++++--------- beacon-chain/state/interfaces.go | 1 + .../state/state-native/readonly_validator.go | 4 +++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index b10c870675b1..9fb39b13a73f 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -195,14 +195,18 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) // add validators that are not yet active to pending balance deposits // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH - preActivation := make([]primitives.ValidatorIndex, 0) - + preActivationIndices := make([]primitives.ValidatorIndex, 0) + // get all the validators with compound withdrawal indicies for eip7521 + compoundWithdrawalIndices := make([]primitives.ValidatorIndex, 0) if err = beaconState.ReadFromEveryValidator(func(index int, val state.ReadOnlyValidator) error { if val.ExitEpoch() != params.BeaconConfig().FarFutureEpoch { exitEpochs = append(exitEpochs, val.ExitEpoch()) } if val.ActivationEpoch() == params.BeaconConfig().FarFutureEpoch { - preActivation = append(preActivation, primitives.ValidatorIndex(index)) + preActivationIndices = append(preActivationIndices, primitives.ValidatorIndex(index)) + } + if helpers.HasCompoundingWithdrawalCredential(val.Validator()) { + compoundWithdrawalIndices = append(compoundWithdrawalIndices, primitives.ValidatorIndex(index)) } return nil }); err != nil { @@ -291,13 +295,13 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) PendingConsolidations: nil, } - // Sorting preActivation based on a custom criteria - sort.Slice(preActivation, func(i, j int) bool { + // Sorting preActivationIndices based on a custom criteria + sort.Slice(preActivationIndices, func(i, j int) bool { // Comparing based on ActivationEligibilityEpoch and then by index if the epochs are the same - if s.Validators[preActivation[i]].ActivationEligibilityEpoch == s.Validators[preActivation[j]].ActivationEligibilityEpoch { - return preActivation[i] < preActivation[j] + if s.Validators[preActivationIndices[i]].ActivationEligibilityEpoch == s.Validators[preActivationIndices[j]].ActivationEligibilityEpoch { + return preActivationIndices[i] < preActivationIndices[j] } - return s.Validators[preActivation[i]].ActivationEligibilityEpoch < s.Validators[preActivation[j]].ActivationEligibilityEpoch + return s.Validators[preActivationIndices[i]].ActivationEligibilityEpoch < s.Validators[preActivationIndices[j]].ActivationEligibilityEpoch }) // need to cast the beaconState to use in helper functions @@ -306,18 +310,16 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) return nil, errors.Wrap(err, "failed to initialize post electra beaconState") } - for _, index := range preActivation { + for _, index := range preActivationIndices { if err := QueueEntireBalanceAndResetValidator(post, index); err != nil { return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") } } // Ensure early adopters of compounding credentials go through the activation churn - for index, validator := range post.Validators() { - if helpers.HasCompoundingWithdrawalCredential(validator) { - if err := QueueEntireBalanceAndResetValidator(post, primitives.ValidatorIndex(index)); err != nil { - return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") - } + for _, index := range compoundWithdrawalIndices { + if err := QueueEntireBalanceAndResetValidator(post, primitives.ValidatorIndex(index)); err != nil { + return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") } } diff --git a/beacon-chain/state/interfaces.go b/beacon-chain/state/interfaces.go index c255ff9fc762..d92bcc5be3a8 100644 --- a/beacon-chain/state/interfaces.go +++ b/beacon-chain/state/interfaces.go @@ -119,6 +119,7 @@ type ReadOnlyValidator interface { WithdrawalCredentials() []byte Slashed() bool IsNil() bool + Validator() *ethpb.Validator } // ReadOnlyValidators defines a struct which only has read access to validators methods. diff --git a/beacon-chain/state/state-native/readonly_validator.go b/beacon-chain/state/state-native/readonly_validator.go index 6eb2d923d76a..fe5fdc4994ca 100644 --- a/beacon-chain/state/state-native/readonly_validator.go +++ b/beacon-chain/state/state-native/readonly_validator.go @@ -92,3 +92,7 @@ func (v readOnlyValidator) Slashed() bool { func (v readOnlyValidator) IsNil() bool { return v.validator == nil } + +func (v readOnlyValidator) Validator() *ethpb.Validator { + return v.validator +} From 266c7eca4190bf1904927dc253e7ef3e77c398e9 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 15:27:44 -0500 Subject: [PATCH 22/34] one more feedback --- beacon-chain/core/electra/upgrade.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 9fb39b13a73f..20287e97bf19 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -130,8 +130,6 @@ import ( // // return post func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) { - epoch := time.CurrentEpoch(beaconState) - currentSyncCommittee, err := beaconState.CurrentSyncCommittee() if err != nil { return nil, err @@ -237,7 +235,7 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) Fork: ðpb.Fork{ PreviousVersion: beaconState.Fork().CurrentVersion, CurrentVersion: params.BeaconConfig().ElectraForkVersion, - Epoch: epoch, + Epoch: time.CurrentEpoch(beaconState), }, LatestBlockHeader: beaconState.LatestBlockHeader(), BlockRoots: beaconState.BlockRoots(), From 969ae7344267455a78b8067fde58832bc32f415d Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 15:48:10 -0500 Subject: [PATCH 23/34] changing value to interface after talking to preston --- beacon-chain/core/electra/upgrade.go | 2 +- beacon-chain/core/helpers/validators.go | 5 +++-- beacon-chain/rpc/eth/beacon/handlers_validator.go | 2 +- beacon-chain/state/interfaces.go | 3 +-- beacon-chain/state/state-native/readonly_validator.go | 6 +----- beacon-chain/state/state-native/readonly_validator_test.go | 2 +- consensus-types/interfaces/BUILD.bazel | 1 + consensus-types/interfaces/validator.go | 5 +++++ testing/endtoend/evaluators/operations.go | 2 +- 9 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 consensus-types/interfaces/validator.go diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 20287e97bf19..9ac60cc2e143 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -203,7 +203,7 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) if val.ActivationEpoch() == params.BeaconConfig().FarFutureEpoch { preActivationIndices = append(preActivationIndices, primitives.ValidatorIndex(index)) } - if helpers.HasCompoundingWithdrawalCredential(val.Validator()) { + if helpers.HasCompoundingWithdrawalCredential(val) { compoundWithdrawalIndices = append(compoundWithdrawalIndices, primitives.ValidatorIndex(index)) } return nil diff --git a/beacon-chain/core/helpers/validators.go b/beacon-chain/core/helpers/validators.go index 2614c7d17ac0..4e328295bf53 100644 --- a/beacon-chain/core/helpers/validators.go +++ b/beacon-chain/core/helpers/validators.go @@ -12,6 +12,7 @@ import ( forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types" "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v5/crypto/hash" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" @@ -520,11 +521,11 @@ func isETH1WithdrawalCredential(creds []byte) bool { // Check if ``validator`` has an 0x02 prefixed "compounding" withdrawal credential. // """ // return is_compounding_withdrawal_credential(validator.withdrawal_credentials) -func HasCompoundingWithdrawalCredential(v *ethpb.Validator) bool { +func HasCompoundingWithdrawalCredential(v interfaces.WithWithdrawalCredentials) bool { if v == nil { return false } - return isCompoundingWithdrawalCredential(v.WithdrawalCredentials) + return isCompoundingWithdrawalCredential(v.GetWithdrawalCredentials()) } // isCompoundingWithdrawalCredential checks if the credentials are a compounding withdrawal credential. diff --git a/beacon-chain/rpc/eth/beacon/handlers_validator.go b/beacon-chain/rpc/eth/beacon/handlers_validator.go index bc79f890cc2a..706e55a59b2e 100644 --- a/beacon-chain/rpc/eth/beacon/handlers_validator.go +++ b/beacon-chain/rpc/eth/beacon/handlers_validator.go @@ -404,7 +404,7 @@ func valContainerFromReadOnlyVal( Status: valStatus.String(), Validator: &structs.Validator{ Pubkey: hexutil.Encode(pubkey[:]), - WithdrawalCredentials: hexutil.Encode(val.WithdrawalCredentials()), + WithdrawalCredentials: hexutil.Encode(val.GetWithdrawalCredentials()), EffectiveBalance: strconv.FormatUint(val.EffectiveBalance(), 10), Slashed: val.Slashed(), ActivationEligibilityEpoch: strconv.FormatUint(uint64(val.ActivationEligibilityEpoch()), 10), diff --git a/beacon-chain/state/interfaces.go b/beacon-chain/state/interfaces.go index d92bcc5be3a8..2b32602cad14 100644 --- a/beacon-chain/state/interfaces.go +++ b/beacon-chain/state/interfaces.go @@ -116,10 +116,9 @@ type ReadOnlyValidator interface { WithdrawableEpoch() primitives.Epoch ExitEpoch() primitives.Epoch PublicKey() [fieldparams.BLSPubkeyLength]byte - WithdrawalCredentials() []byte + GetWithdrawalCredentials() []byte Slashed() bool IsNil() bool - Validator() *ethpb.Validator } // ReadOnlyValidators defines a struct which only has read access to validators methods. diff --git a/beacon-chain/state/state-native/readonly_validator.go b/beacon-chain/state/state-native/readonly_validator.go index fe5fdc4994ca..f5029049eda9 100644 --- a/beacon-chain/state/state-native/readonly_validator.go +++ b/beacon-chain/state/state-native/readonly_validator.go @@ -77,7 +77,7 @@ func (v readOnlyValidator) publicKeySlice() []byte { // WithdrawalCredentials returns the withdrawal credentials of the // read only validator. -func (v readOnlyValidator) WithdrawalCredentials() []byte { +func (v readOnlyValidator) GetWithdrawalCredentials() []byte { creds := make([]byte, len(v.validator.WithdrawalCredentials)) copy(creds, v.validator.WithdrawalCredentials) return creds @@ -92,7 +92,3 @@ func (v readOnlyValidator) Slashed() bool { func (v readOnlyValidator) IsNil() bool { return v.validator == nil } - -func (v readOnlyValidator) Validator() *ethpb.Validator { - return v.validator -} diff --git a/beacon-chain/state/state-native/readonly_validator_test.go b/beacon-chain/state/state-native/readonly_validator_test.go index 91f0c284f206..6a5f27bcba84 100644 --- a/beacon-chain/state/state-native/readonly_validator_test.go +++ b/beacon-chain/state/state-native/readonly_validator_test.go @@ -63,7 +63,7 @@ func TestReadOnlyValidator_WithdrawalCredentials(t *testing.T) { creds := []byte{0xFA, 0xCC} v, err := statenative.NewValidator(ðpb.Validator{WithdrawalCredentials: creds}) require.NoError(t, err) - assert.DeepEqual(t, creds, v.WithdrawalCredentials()) + assert.DeepEqual(t, creds, v.GetWithdrawalCredentials()) } func TestReadOnlyValidator_Slashed(t *testing.T) { diff --git a/consensus-types/interfaces/BUILD.bazel b/consensus-types/interfaces/BUILD.bazel index 6dbc9a37a043..84e8be9f0d4b 100644 --- a/consensus-types/interfaces/BUILD.bazel +++ b/consensus-types/interfaces/BUILD.bazel @@ -7,6 +7,7 @@ go_library( "cast.go", "error.go", "utils.go", + "validator.go", ], importpath = "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces", visibility = ["//visibility:public"], diff --git a/consensus-types/interfaces/validator.go b/consensus-types/interfaces/validator.go new file mode 100644 index 000000000000..2d7e1fa99f80 --- /dev/null +++ b/consensus-types/interfaces/validator.go @@ -0,0 +1,5 @@ +package interfaces + +type WithWithdrawalCredentials interface { + GetWithdrawalCredentials() []byte +} diff --git a/testing/endtoend/evaluators/operations.go b/testing/endtoend/evaluators/operations.go index 2dd93a3c285b..b683f8c863b3 100644 --- a/testing/endtoend/evaluators/operations.go +++ b/testing/endtoend/evaluators/operations.go @@ -365,7 +365,7 @@ func proposeVoluntaryExit(ec *e2etypes.EvaluationContext, conns ...*grpc.ClientC } var execIndices []int err = st.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error { - if val.WithdrawalCredentials()[0] == params.BeaconConfig().ETH1AddressWithdrawalPrefixByte { + if val.GetWithdrawalCredentials()[0] == params.BeaconConfig().ETH1AddressWithdrawalPrefixByte { execIndices = append(execIndices, idx) } return nil From 174c6f6334960e9a14e8986e384afc949f23d436 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 15:51:10 -0500 Subject: [PATCH 24/34] adding missed review feedback --- beacon-chain/state/stategen/replay.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/beacon-chain/state/stategen/replay.go b/beacon-chain/state/stategen/replay.go index cd0fa498db89..eacf1661f4ef 100644 --- a/beacon-chain/state/stategen/replay.go +++ b/beacon-chain/state/stategen/replay.go @@ -208,14 +208,12 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primi tracing.AnnotateError(span, err) return nil, errors.Wrap(err, "could not process epoch with optimizations") } - } else if state.Version() >= version.Altair { + } else { state, err = altair.ProcessEpoch(ctx, state) if err != nil { tracing.AnnotateError(span, err) return nil, errors.Wrap(err, "could not process epoch") } - } else { - return nil, fmt.Errorf("unsupported beacon state version: %s", version.String(state.Version())) } } if err := state.SetSlot(state.Slot() + 1); err != nil { From ecc6e6a0da811761cfbfba5c093195198acae522 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 16:07:39 -0500 Subject: [PATCH 25/34] fixing linting --- beacon-chain/core/electra/upgrade.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 9ac60cc2e143..0ebc12ee4a4d 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -316,7 +316,7 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) // Ensure early adopters of compounding credentials go through the activation churn for _, index := range compoundWithdrawalIndices { - if err := QueueEntireBalanceAndResetValidator(post, primitives.ValidatorIndex(index)); err != nil { + if err := QueueEntireBalanceAndResetValidator(post, index); err != nil { return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") } } From 7f69c2d9f09f6a19a45cf7b4159904d2fc16318e Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 16:47:17 -0500 Subject: [PATCH 26/34] noticed I was using the wrong function in the state upgrade --- beacon-chain/core/electra/upgrade.go | 4 +-- beacon-chain/core/electra/upgrade_test.go | 7 +++++- beacon-chain/core/electra/validator.go | 28 +++++++++++++++++++++ beacon-chain/core/electra/validator_test.go | 17 +++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 0ebc12ee4a4d..7b3df2a61b37 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -316,8 +316,8 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) // Ensure early adopters of compounding credentials go through the activation churn for _, index := range compoundWithdrawalIndices { - if err := QueueEntireBalanceAndResetValidator(post, index); err != nil { - return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") + if err := QueueExcessActiveBalance(post, index); err != nil { + return nil, errors.Wrap(err, "failed to queue excess active balance") } } diff --git a/beacon-chain/core/electra/upgrade_test.go b/beacon-chain/core/electra/upgrade_test.go index 36e9cab4747c..ee180189e10a 100644 --- a/beacon-chain/core/electra/upgrade_test.go +++ b/beacon-chain/core/electra/upgrade_test.go @@ -24,6 +24,10 @@ func TestUpgradeToElectra(t *testing.T) { vals[0].ActivationEpoch = params.BeaconConfig().FarFutureEpoch vals[1].WithdrawalCredentials = []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte} require.NoError(t, st.SetValidators(vals)) + bals := st.Balances() + bals[1] = params.BeaconConfig().MinActivationBalance + 1000 + require.NoError(t, st.SetBalances(bals)) + preForkState := st.Copy() mSt, err := electra.UpgradeToElectra(st) require.NoError(t, err) @@ -62,7 +66,7 @@ func TestUpgradeToElectra(t *testing.T) { mVal2, err := mSt.ValidatorAtIndex(1) require.NoError(t, err) - require.Equal(t, uint64(0), mVal2.EffectiveBalance) + require.Equal(t, params.BeaconConfig().MinActivationBalance, mVal2.EffectiveBalance) numValidators := mSt.NumValidators() p, err := mSt.PreviousEpochParticipation() @@ -172,6 +176,7 @@ func TestUpgradeToElectra(t *testing.T) { pendingBalanceDeposits, err := mSt.PendingBalanceDeposits() require.NoError(t, err) require.Equal(t, 2, len(pendingBalanceDeposits)) + require.Equal(t, uint64(1000), pendingBalanceDeposits[1].Amount) numPendingPartialWithdrawals, err := mSt.NumPendingPartialWithdrawals() require.NoError(t, err) diff --git a/beacon-chain/core/electra/validator.go b/beacon-chain/core/electra/validator.go index 48bc8e7e2f22..b783aee64de9 100644 --- a/beacon-chain/core/electra/validator.go +++ b/beacon-chain/core/electra/validator.go @@ -6,6 +6,34 @@ import ( "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" ) +// QueueExcessActiveBalance +// +// Spec definition: +// +// def queue_excess_active_balance(state: BeaconState, index: ValidatorIndex) -> None: +// balance = state.balances[index] +// if balance > MIN_ACTIVATION_BALANCE: +// excess_balance = balance - MIN_ACTIVATION_BALANCE +// state.balances[index] = MIN_ACTIVATION_BALANCE +// state.pending_balance_deposits.append( +// PendingBalanceDeposit(index=index, amount=excess_balance) +// ) +func QueueExcessActiveBalance(s state.BeaconState, idx primitives.ValidatorIndex) error { + bal, err := s.BalanceAtIndex(idx) + if err != nil { + return err + } + + if bal > params.BeaconConfig().MinActivationBalance { + excessBalance := bal - params.BeaconConfig().MinActivationBalance + if err := s.UpdateBalancesAtIndex(idx, params.BeaconConfig().MinActivationBalance); err != nil { + return err + } + return s.AppendPendingBalanceDeposit(idx, excessBalance) + } + return nil +} + // QueueEntireBalanceAndResetValidator queues the entire balance and resets the validator. This is used in electra fork logic. // // Spec definition: diff --git a/beacon-chain/core/electra/validator_test.go b/beacon-chain/core/electra/validator_test.go index 362bcf806258..c985c1cfd915 100644 --- a/beacon-chain/core/electra/validator_test.go +++ b/beacon-chain/core/electra/validator_test.go @@ -9,6 +9,23 @@ import ( "github.com/prysmaticlabs/prysm/v5/testing/util" ) +func TestQueueExcessActiveBalance_Ok(t *testing.T) { + st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee) + bals := st.Balances() + bals[0] = params.BeaconConfig().MinActivationBalance + 1000 + require.NoError(t, st.SetBalances(bals)) + + err := electra.QueueExcessActiveBalance(st, 0) + require.NoError(t, err) + + pbd, err := st.PendingBalanceDeposits() + require.NoError(t, err) + require.Equal(t, uint64(1000), pbd[0].Amount) + + bals = st.Balances() + require.Equal(t, params.BeaconConfig().MinActivationBalance, bals[0]) +} + func TestQueueEntireBalanceAndResetValidator_Ok(t *testing.T) { st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee) val, err := st.ValidatorAtIndex(0) From 2b575579c239492cd27baa449feea56576ee1003 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 18:19:17 -0500 Subject: [PATCH 27/34] fixing and ignoring some deepsource issues --- beacon-chain/core/electra/upgrade.go | 2 ++ beacon-chain/core/electra/validator.go | 2 +- beacon-chain/core/transition/transition.go | 2 ++ beacon-chain/rpc/eth/config/handlers_test.go | 1 + beacon-chain/state/stategen/replay.go | 3 ++- testing/util/electra_state.go | 2 +- 6 files changed, 9 insertions(+), 3 deletions(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 7b3df2a61b37..74f9d13dd068 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -129,6 +129,8 @@ import ( // queue_excess_active_balance(post, ValidatorIndex(index)) // // return post +// +// skipcq: GO-R1005 func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) { currentSyncCommittee, err := beaconState.CurrentSyncCommittee() if err != nil { diff --git a/beacon-chain/core/electra/validator.go b/beacon-chain/core/electra/validator.go index b783aee64de9..226eee78d257 100644 --- a/beacon-chain/core/electra/validator.go +++ b/beacon-chain/core/electra/validator.go @@ -6,7 +6,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" ) -// QueueExcessActiveBalance +// QueueExcessActiveBalance queues validators with balances above the min activation balance and adds to pending balance deposit. // // Spec definition: // diff --git a/beacon-chain/core/transition/transition.go b/beacon-chain/core/transition/transition.go index 253cf2ad941d..c234eed3e869 100644 --- a/beacon-chain/core/transition/transition.go +++ b/beacon-chain/core/transition/transition.go @@ -100,6 +100,8 @@ func ExecuteStateTransition( // # Cache block root // previous_block_root = hash_tree_root(state.latest_block_header) // state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root +// +// skipcq: GO-R1005 func ProcessSlot(ctx context.Context, state state.BeaconState) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlot") defer span.End() diff --git a/beacon-chain/rpc/eth/config/handlers_test.go b/beacon-chain/rpc/eth/config/handlers_test.go index 384e1d53c950..53d240b8bec6 100644 --- a/beacon-chain/rpc/eth/config/handlers_test.go +++ b/beacon-chain/rpc/eth/config/handlers_test.go @@ -40,6 +40,7 @@ func TestGetDepositContract(t *testing.T) { assert.Equal(t, "0x4242424242424242424242424242424242424242", response.Data.Address) } +// skipcq: GO-R1005 func TestGetSpec(t *testing.T) { params.SetupTestConfigCleanup(t) config := params.BeaconConfig().Copy() diff --git a/beacon-chain/state/stategen/replay.go b/beacon-chain/state/stategen/replay.go index eacf1661f4ef..1182a17d5b14 100644 --- a/beacon-chain/state/stategen/replay.go +++ b/beacon-chain/state/stategen/replay.go @@ -27,7 +27,7 @@ import ( // ReplayBlocks replays the input blocks on the input state until the target slot is reached. // // WARNING Blocks passed to the function must be in decreasing slots order. -func (_ *State) replayBlocks( +func (*State) replayBlocks( ctx context.Context, state state.BeaconState, signed []interfaces.ReadOnlySignedBeaconBlock, @@ -179,6 +179,7 @@ func executeStateTransitionStateGen( // There's no skip slot cache involved given state gen only works with already stored block and state in DB. // // WARNING: This method should not be used for future slot. +// skipcq: GO-R1005 func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.Slot) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "stategen.ReplayProcessSlots") defer span.End() diff --git a/testing/util/electra_state.go b/testing/util/electra_state.go index 922f1d0584a6..403b23dbd1ef 100644 --- a/testing/util/electra_state.go +++ b/testing/util/electra_state.go @@ -186,7 +186,7 @@ func buildGenesisBeaconStateElectra(genesisTime uint64, preState state.BeaconSta Eth1DataVotes: []*ethpb.Eth1Data{}, Eth1DepositIndex: preState.Eth1DepositIndex(), - //Electra Data + // Electra Data DepositReceiptsStartIndex: params.BeaconConfig().UnsetDepositReceiptsStartIndex, ExitBalanceToConsume: helpers.ActivationExitChurnLimit(math.Gwei(tab)), EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(preState.Slot())), From 37dbcbd845c16d7cff99f43cd701be2021274f6f Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 18:39:31 -0500 Subject: [PATCH 28/34] moving core electra validator functions to helper to remove circular dependencies in other PRs --- beacon-chain/core/electra/BUILD.bazel | 10 +-- beacon-chain/core/electra/upgrade.go | 4 +- beacon-chain/core/electra/validator.go | 72 -------------------- beacon-chain/core/electra/validator_test.go | 47 ------------- beacon-chain/core/helpers/validators.go | 65 ++++++++++++++++++ beacon-chain/core/helpers/validators_test.go | 38 +++++++++++ 6 files changed, 107 insertions(+), 129 deletions(-) delete mode 100644 beacon-chain/core/electra/validator.go delete mode 100644 beacon-chain/core/electra/validator_test.go diff --git a/beacon-chain/core/electra/BUILD.bazel b/beacon-chain/core/electra/BUILD.bazel index 4918aa37f56f..5c7c3beb484d 100644 --- a/beacon-chain/core/electra/BUILD.bazel +++ b/beacon-chain/core/electra/BUILD.bazel @@ -2,10 +2,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", - srcs = [ - "upgrade.go", - "validator.go", - ], + srcs = ["upgrade.go"], importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra", visibility = ["//visibility:public"], deps = [ @@ -26,10 +23,7 @@ go_library( go_test( name = "go_default_test", - srcs = [ - "upgrade_test.go", - "validator_test.go", - ], + srcs = ["upgrade_test.go"], deps = [ ":go_default_library", "//beacon-chain/core/helpers:go_default_library", diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 74f9d13dd068..78c8626bfa32 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -311,14 +311,14 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) } for _, index := range preActivationIndices { - if err := QueueEntireBalanceAndResetValidator(post, index); err != nil { + if err := helpers.QueueEntireBalanceAndResetValidator(post, index); err != nil { return nil, errors.Wrap(err, "failed to queue entire balance and reset validator") } } // Ensure early adopters of compounding credentials go through the activation churn for _, index := range compoundWithdrawalIndices { - if err := QueueExcessActiveBalance(post, index); err != nil { + if err := helpers.QueueExcessActiveBalance(post, index); err != nil { return nil, errors.Wrap(err, "failed to queue excess active balance") } } diff --git a/beacon-chain/core/electra/validator.go b/beacon-chain/core/electra/validator.go deleted file mode 100644 index 226eee78d257..000000000000 --- a/beacon-chain/core/electra/validator.go +++ /dev/null @@ -1,72 +0,0 @@ -package electra - -import ( - "github.com/prysmaticlabs/prysm/v5/beacon-chain/state" - "github.com/prysmaticlabs/prysm/v5/config/params" - "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" -) - -// QueueExcessActiveBalance queues validators with balances above the min activation balance and adds to pending balance deposit. -// -// Spec definition: -// -// def queue_excess_active_balance(state: BeaconState, index: ValidatorIndex) -> None: -// balance = state.balances[index] -// if balance > MIN_ACTIVATION_BALANCE: -// excess_balance = balance - MIN_ACTIVATION_BALANCE -// state.balances[index] = MIN_ACTIVATION_BALANCE -// state.pending_balance_deposits.append( -// PendingBalanceDeposit(index=index, amount=excess_balance) -// ) -func QueueExcessActiveBalance(s state.BeaconState, idx primitives.ValidatorIndex) error { - bal, err := s.BalanceAtIndex(idx) - if err != nil { - return err - } - - if bal > params.BeaconConfig().MinActivationBalance { - excessBalance := bal - params.BeaconConfig().MinActivationBalance - if err := s.UpdateBalancesAtIndex(idx, params.BeaconConfig().MinActivationBalance); err != nil { - return err - } - return s.AppendPendingBalanceDeposit(idx, excessBalance) - } - return nil -} - -// QueueEntireBalanceAndResetValidator queues the entire balance and resets the validator. This is used in electra fork logic. -// -// Spec definition: -// -// def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None: -// balance = state.balances[index] -// validator = state.validators[index] -// state.balances[index] = 0 -// validator.effective_balance = 0 -// validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH -// state.pending_balance_deposits.append( -// PendingBalanceDeposit(index=index, amount=balance) -// ) -func QueueEntireBalanceAndResetValidator(s state.BeaconState, idx primitives.ValidatorIndex) error { - bal, err := s.BalanceAtIndex(idx) - if err != nil { - return err - } - - if err := s.UpdateBalancesAtIndex(idx, 0); err != nil { - return err - } - - v, err := s.ValidatorAtIndex(idx) - if err != nil { - return err - } - - v.EffectiveBalance = 0 - v.ActivationEligibilityEpoch = params.BeaconConfig().FarFutureEpoch - if err := s.UpdateValidatorAtIndex(idx, v); err != nil { - return err - } - - return s.AppendPendingBalanceDeposit(idx, bal) -} diff --git a/beacon-chain/core/electra/validator_test.go b/beacon-chain/core/electra/validator_test.go deleted file mode 100644 index c985c1cfd915..000000000000 --- a/beacon-chain/core/electra/validator_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package electra_test - -import ( - "testing" - - "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra" - "github.com/prysmaticlabs/prysm/v5/config/params" - "github.com/prysmaticlabs/prysm/v5/testing/require" - "github.com/prysmaticlabs/prysm/v5/testing/util" -) - -func TestQueueExcessActiveBalance_Ok(t *testing.T) { - st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee) - bals := st.Balances() - bals[0] = params.BeaconConfig().MinActivationBalance + 1000 - require.NoError(t, st.SetBalances(bals)) - - err := electra.QueueExcessActiveBalance(st, 0) - require.NoError(t, err) - - pbd, err := st.PendingBalanceDeposits() - require.NoError(t, err) - require.Equal(t, uint64(1000), pbd[0].Amount) - - bals = st.Balances() - require.Equal(t, params.BeaconConfig().MinActivationBalance, bals[0]) -} - -func TestQueueEntireBalanceAndResetValidator_Ok(t *testing.T) { - st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee) - val, err := st.ValidatorAtIndex(0) - require.NoError(t, err) - require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, val.EffectiveBalance) - pbd, err := st.PendingBalanceDeposits() - require.NoError(t, err) - require.Equal(t, 0, len(pbd)) - err = electra.QueueEntireBalanceAndResetValidator(st, 0) - require.NoError(t, err) - - pbd, err = st.PendingBalanceDeposits() - require.NoError(t, err) - require.Equal(t, 1, len(pbd)) - - val, err = st.ValidatorAtIndex(0) - require.NoError(t, err) - require.Equal(t, uint64(0), val.EffectiveBalance) -} diff --git a/beacon-chain/core/helpers/validators.go b/beacon-chain/core/helpers/validators.go index 4e328295bf53..62a21cce642c 100644 --- a/beacon-chain/core/helpers/validators.go +++ b/beacon-chain/core/helpers/validators.go @@ -674,3 +674,68 @@ func ValidatorMaxEffectiveBalance(val *ethpb.Validator) uint64 { } return params.BeaconConfig().MinActivationBalance } + +// QueueExcessActiveBalance queues validators with balances above the min activation balance and adds to pending balance deposit. +// +// Spec definition: +// +// def queue_excess_active_balance(state: BeaconState, index: ValidatorIndex) -> None: +// balance = state.balances[index] +// if balance > MIN_ACTIVATION_BALANCE: +// excess_balance = balance - MIN_ACTIVATION_BALANCE +// state.balances[index] = MIN_ACTIVATION_BALANCE +// state.pending_balance_deposits.append( +// PendingBalanceDeposit(index=index, amount=excess_balance) +// ) +func QueueExcessActiveBalance(s state.BeaconState, idx primitives.ValidatorIndex) error { + bal, err := s.BalanceAtIndex(idx) + if err != nil { + return err + } + + if bal > params.BeaconConfig().MinActivationBalance { + excessBalance := bal - params.BeaconConfig().MinActivationBalance + if err := s.UpdateBalancesAtIndex(idx, params.BeaconConfig().MinActivationBalance); err != nil { + return err + } + return s.AppendPendingBalanceDeposit(idx, excessBalance) + } + return nil +} + +// QueueEntireBalanceAndResetValidator queues the entire balance and resets the validator. This is used in electra fork logic. +// +// Spec definition: +// +// def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None: +// balance = state.balances[index] +// validator = state.validators[index] +// state.balances[index] = 0 +// validator.effective_balance = 0 +// validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH +// state.pending_balance_deposits.append( +// PendingBalanceDeposit(index=index, amount=balance) +// ) +func QueueEntireBalanceAndResetValidator(s state.BeaconState, idx primitives.ValidatorIndex) error { + bal, err := s.BalanceAtIndex(idx) + if err != nil { + return err + } + + if err := s.UpdateBalancesAtIndex(idx, 0); err != nil { + return err + } + + v, err := s.ValidatorAtIndex(idx) + if err != nil { + return err + } + + v.EffectiveBalance = 0 + v.ActivationEligibilityEpoch = params.BeaconConfig().FarFutureEpoch + if err := s.UpdateValidatorAtIndex(idx, v); err != nil { + return err + } + + return s.AppendPendingBalanceDeposit(idx, bal) +} diff --git a/beacon-chain/core/helpers/validators_test.go b/beacon-chain/core/helpers/validators_test.go index efa21c75cb63..43e0416eca58 100644 --- a/beacon-chain/core/helpers/validators_test.go +++ b/beacon-chain/core/helpers/validators_test.go @@ -18,6 +18,7 @@ import ( ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v5/testing/assert" "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/util" ) func TestIsActiveValidator_OK(t *testing.T) { @@ -1119,3 +1120,40 @@ func TestValidatorMaxEffectiveBalance(t *testing.T) { // Sanity check that MinActivationBalance equals (pre-electra) MaxEffectiveBalance assert.Equal(t, params.BeaconConfig().MinActivationBalance, params.BeaconConfig().MaxEffectiveBalance) } + +func TestQueueExcessActiveBalance_Ok(t *testing.T) { + st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee) + bals := st.Balances() + bals[0] = params.BeaconConfig().MinActivationBalance + 1000 + require.NoError(t, st.SetBalances(bals)) + + err := helpers.QueueExcessActiveBalance(st, 0) + require.NoError(t, err) + + pbd, err := st.PendingBalanceDeposits() + require.NoError(t, err) + require.Equal(t, uint64(1000), pbd[0].Amount) + + bals = st.Balances() + require.Equal(t, params.BeaconConfig().MinActivationBalance, bals[0]) +} + +func TestQueueEntireBalanceAndResetValidator_Ok(t *testing.T) { + st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee) + val, err := st.ValidatorAtIndex(0) + require.NoError(t, err) + require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, val.EffectiveBalance) + pbd, err := st.PendingBalanceDeposits() + require.NoError(t, err) + require.Equal(t, 0, len(pbd)) + err = helpers.QueueEntireBalanceAndResetValidator(st, 0) + require.NoError(t, err) + + pbd, err = st.PendingBalanceDeposits() + require.NoError(t, err) + require.Equal(t, 1, len(pbd)) + + val, err = st.ValidatorAtIndex(0) + require.NoError(t, err) + require.Equal(t, uint64(0), val.EffectiveBalance) +} From 7ddae4ad87ee1a6ce80f3b69d436f8c02efa8e48 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Tue, 7 May 2024 18:40:29 -0500 Subject: [PATCH 29/34] missed deepsource complaint --- beacon-chain/core/transition/transition.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/beacon-chain/core/transition/transition.go b/beacon-chain/core/transition/transition.go index c234eed3e869..2cfa3b7dd8d6 100644 --- a/beacon-chain/core/transition/transition.go +++ b/beacon-chain/core/transition/transition.go @@ -188,6 +188,8 @@ func ProcessSlotsIfPossible(ctx context.Context, state state.BeaconState, target // if (state.slot + 1) % SLOTS_PER_EPOCH == 0: // process_epoch(state) // state.slot = Slot(state.slot + 1) +// +// skipcq: GO-R1005 func ProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.Slot) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlots") defer span.End() From 1c9a6aedd44c6ff2d95905efca510e5c2f45fa44 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Tue, 7 May 2024 21:37:37 -0500 Subject: [PATCH 30/34] Update upgrade.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Radosław Kapka --- beacon-chain/core/electra/upgrade.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index 78c8626bfa32..e6e59d77e276 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -196,7 +196,7 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH preActivationIndices := make([]primitives.ValidatorIndex, 0) - // get all the validators with compound withdrawal indicies for eip7521 + // get all the validators with compound withdrawal indices for eip7521 compoundWithdrawalIndices := make([]primitives.ValidatorIndex, 0) if err = beaconState.ReadFromEveryValidator(func(index int, val state.ReadOnlyValidator) error { if val.ExitEpoch() != params.BeaconConfig().FarFutureEpoch { From cf89f83110fd9e1cb876ed8a3c5c2da02404dfa1 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Tue, 7 May 2024 22:10:25 -0500 Subject: [PATCH 31/34] Update testing/util/electra_state.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Radosław Kapka --- testing/util/electra_state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/util/electra_state.go b/testing/util/electra_state.go index 403b23dbd1ef..a81ab47865b8 100644 --- a/testing/util/electra_state.go +++ b/testing/util/electra_state.go @@ -18,7 +18,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/time/slots" ) -// DeterministicGenesisStateElectra returns a genesis state in Deneb format made using the deterministic deposits. +// DeterministicGenesisStateElectra returns a genesis state in Electra format made using the deterministic deposits. func DeterministicGenesisStateElectra(t testing.TB, numValidators uint64) (state.BeaconState, []bls.SecretKey) { deposits, privKeys, err := DeterministicDepositsAndKeys(numValidators) if err != nil { From 44993f62e47ff2f7a982bcebab68fd1b7d4fd738 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Tue, 7 May 2024 22:10:43 -0500 Subject: [PATCH 32/34] Update testing/util/electra_state.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Radosław Kapka --- testing/util/electra_state.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/util/electra_state.go b/testing/util/electra_state.go index a81ab47865b8..ad80b260131d 100644 --- a/testing/util/electra_state.go +++ b/testing/util/electra_state.go @@ -57,7 +57,7 @@ func genesisBeaconStateElectra(ctx context.Context, deposits []*ethpb.Deposit, g return buildGenesisBeaconStateElectra(genesisTime, st, st.Eth1Data()) } -// emptyGenesisStateDeneb returns an empty genesis state in Deneb format. +// emptyGenesisStateDeneb returns an empty genesis state in Electra format. func emptyGenesisStateElectra() (state.BeaconState, error) { st := ðpb.BeaconStateElectra{ // Misc fields. From 429b474510d19f1549af8d0686dee76bd8792cb6 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Wed, 8 May 2024 08:26:16 -0500 Subject: [PATCH 33/34] addressing feedback --- beacon-chain/core/electra/upgrade.go | 27 +++++++-------------------- testing/util/electra_state.go | 3 +++ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index e6e59d77e276..b2962d194247 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -189,18 +189,13 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) return nil, err } - // Find the earliest exit epoch - exitEpochs := make([]primitives.Epoch, 0) // [New in Electra:EIP7251] - // add validators that are not yet active to pending balance deposits - - // Creating a slice to store indices of validators whose activation epoch is set to FAR_FUTURE_EPOCH + earliestExitEpoch := time.CurrentEpoch(beaconState) preActivationIndices := make([]primitives.ValidatorIndex, 0) - // get all the validators with compound withdrawal indices for eip7521 compoundWithdrawalIndices := make([]primitives.ValidatorIndex, 0) if err = beaconState.ReadFromEveryValidator(func(index int, val state.ReadOnlyValidator) error { - if val.ExitEpoch() != params.BeaconConfig().FarFutureEpoch { - exitEpochs = append(exitEpochs, val.ExitEpoch()) + if val.ExitEpoch() != params.BeaconConfig().FarFutureEpoch && val.ExitEpoch() > earliestExitEpoch { + earliestExitEpoch = val.ExitEpoch() } if val.ActivationEpoch() == params.BeaconConfig().FarFutureEpoch { preActivationIndices = append(preActivationIndices, primitives.ValidatorIndex(index)) @@ -212,15 +207,7 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) }); err != nil { return nil, err } - if len(exitEpochs) == 0 { - exitEpochs = append(exitEpochs, time.CurrentEpoch(beaconState)) - } - var earliestExitEpoch primitives.Epoch - for _, e := range exitEpochs { - if e > earliestExitEpoch { - earliestExitEpoch = e - } - } + earliestExitEpoch++ // Increment to find the earliest possible exit epoch // note: should be the same in prestate and post beaconState. @@ -290,9 +277,9 @@ func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) EarliestExitEpoch: earliestExitEpoch, ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(math.Gwei(tab)), EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(beaconState.Slot())), - PendingBalanceDeposits: nil, - PendingPartialWithdrawals: nil, - PendingConsolidations: nil, + PendingBalanceDeposits: make([]*ethpb.PendingBalanceDeposit, 0), + PendingPartialWithdrawals: make([]*ethpb.PendingPartialWithdrawal, 0), + PendingConsolidations: make([]*ethpb.PendingConsolidation, 0), } // Sorting preActivationIndices based on a custom criteria diff --git a/testing/util/electra_state.go b/testing/util/electra_state.go index ad80b260131d..c0b8ed1796fd 100644 --- a/testing/util/electra_state.go +++ b/testing/util/electra_state.go @@ -191,6 +191,9 @@ func buildGenesisBeaconStateElectra(genesisTime uint64, preState state.BeaconSta ExitBalanceToConsume: helpers.ActivationExitChurnLimit(math.Gwei(tab)), EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(preState.Slot())), ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(math.Gwei(tab)), + PendingBalanceDeposits: make([]*ethpb.PendingBalanceDeposit, 0), + PendingPartialWithdrawals: make([]*ethpb.PendingPartialWithdrawal, 0), + PendingConsolidations: make([]*ethpb.PendingConsolidation, 0), } var scBits [fieldparams.SyncAggregateSyncCommitteeBytesLength]byte From a915fbea7fe63ebd5685cd9e405fd55886a6a861 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Wed, 8 May 2024 09:56:02 -0500 Subject: [PATCH 34/34] removing deepsoure ignore comments --- beacon-chain/core/electra/upgrade.go | 2 -- beacon-chain/core/transition/transition.go | 4 ---- beacon-chain/rpc/eth/config/handlers_test.go | 1 - beacon-chain/state/stategen/replay.go | 1 - 4 files changed, 8 deletions(-) diff --git a/beacon-chain/core/electra/upgrade.go b/beacon-chain/core/electra/upgrade.go index b2962d194247..3ef96449c40f 100644 --- a/beacon-chain/core/electra/upgrade.go +++ b/beacon-chain/core/electra/upgrade.go @@ -129,8 +129,6 @@ import ( // queue_excess_active_balance(post, ValidatorIndex(index)) // // return post -// -// skipcq: GO-R1005 func UpgradeToElectra(beaconState state.BeaconState) (state.BeaconState, error) { currentSyncCommittee, err := beaconState.CurrentSyncCommittee() if err != nil { diff --git a/beacon-chain/core/transition/transition.go b/beacon-chain/core/transition/transition.go index 2cfa3b7dd8d6..253cf2ad941d 100644 --- a/beacon-chain/core/transition/transition.go +++ b/beacon-chain/core/transition/transition.go @@ -100,8 +100,6 @@ func ExecuteStateTransition( // # Cache block root // previous_block_root = hash_tree_root(state.latest_block_header) // state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root -// -// skipcq: GO-R1005 func ProcessSlot(ctx context.Context, state state.BeaconState) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlot") defer span.End() @@ -188,8 +186,6 @@ func ProcessSlotsIfPossible(ctx context.Context, state state.BeaconState, target // if (state.slot + 1) % SLOTS_PER_EPOCH == 0: // process_epoch(state) // state.slot = Slot(state.slot + 1) -// -// skipcq: GO-R1005 func ProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.Slot) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlots") defer span.End() diff --git a/beacon-chain/rpc/eth/config/handlers_test.go b/beacon-chain/rpc/eth/config/handlers_test.go index 53d240b8bec6..384e1d53c950 100644 --- a/beacon-chain/rpc/eth/config/handlers_test.go +++ b/beacon-chain/rpc/eth/config/handlers_test.go @@ -40,7 +40,6 @@ func TestGetDepositContract(t *testing.T) { assert.Equal(t, "0x4242424242424242424242424242424242424242", response.Data.Address) } -// skipcq: GO-R1005 func TestGetSpec(t *testing.T) { params.SetupTestConfigCleanup(t) config := params.BeaconConfig().Copy() diff --git a/beacon-chain/state/stategen/replay.go b/beacon-chain/state/stategen/replay.go index 1182a17d5b14..873da6ec4d4b 100644 --- a/beacon-chain/state/stategen/replay.go +++ b/beacon-chain/state/stategen/replay.go @@ -179,7 +179,6 @@ func executeStateTransitionStateGen( // There's no skip slot cache involved given state gen only works with already stored block and state in DB. // // WARNING: This method should not be used for future slot. -// skipcq: GO-R1005 func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.Slot) (state.BeaconState, error) { ctx, span := trace.StartSpan(ctx, "stategen.ReplayProcessSlots") defer span.End()