Skip to content

Commit 3ffef02

Browse files
authored
UpgradeToFulu: Respect the specification. (#14821)
https://github.com/ethereum/consensus-specs/blob/188a2ff8183d19dd79d87308bb42906ab1dd3a31/specs/fulu/fork.md#upgrading-the-state Before this commit, the `UpgradeToFulu` did not really respect the specification. This commit fixes that. How can we be sure now the specification is really respected? As long as the equivalent of https://github.com/ethereum/consensus-spec-tests/tree/master/tests/mainnet/electra/fork/fork/pyspec_tests are not released, we cannot be sure. However, with this commit, Prysm and Lighthouse do agree with the post state after the Fulu fork (which is not the case without this commit). So either both Prysm and Lighthouse are both right, either the are both wrong (but in the exact same way, which has a pretty low likelyhood).
1 parent a1eef44 commit 3ffef02

File tree

4 files changed

+99
-113
lines changed

4 files changed

+99
-113
lines changed

beacon-chain/core/fulu/BUILD.bazel

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@ go_library(
66
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/fulu",
77
visibility = ["//visibility:public"],
88
deps = [
9-
"//beacon-chain/core/helpers:go_default_library",
109
"//beacon-chain/core/time:go_default_library",
1110
"//beacon-chain/state:go_default_library",
1211
"//beacon-chain/state/state-native:go_default_library",
1312
"//config/params:go_default_library",
14-
"//consensus-types/primitives:go_default_library",
1513
"//proto/engine/v1:go_default_library",
1614
"//proto/prysm/v1alpha1:go_default_library",
17-
"//time/slots:go_default_library",
1815
"@com_github_pkg_errors//:go_default_library",
1916
],
2017
)
@@ -24,14 +21,12 @@ go_test(
2421
srcs = ["upgrade_test.go"],
2522
deps = [
2623
":go_default_library",
27-
"//beacon-chain/core/helpers:go_default_library",
2824
"//beacon-chain/core/time:go_default_library",
2925
"//config/params:go_default_library",
3026
"//consensus-types/primitives:go_default_library",
3127
"//proto/engine/v1:go_default_library",
3228
"//proto/prysm/v1alpha1:go_default_library",
3329
"//testing/require:go_default_library",
3430
"//testing/util:go_default_library",
35-
"//time/slots:go_default_library",
3631
],
3732
)

beacon-chain/core/fulu/upgrade.go

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
package fulu
22

33
import (
4-
"sort"
5-
64
"github.com/pkg/errors"
7-
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
85
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
96
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
107
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
118
"github.com/prysmaticlabs/prysm/v5/config/params"
12-
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
139
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
1410
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
15-
"github.com/prysmaticlabs/prysm/v5/time/slots"
1611
)
1712

1813
// UpgradeToFulu updates inputs a generic state to return the version Fulu state.
@@ -74,32 +69,37 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
7469
if err != nil {
7570
return nil, err
7671
}
77-
78-
earliestExitEpoch := helpers.ActivationExitEpoch(time.CurrentEpoch(beaconState))
79-
preActivationIndices := make([]primitives.ValidatorIndex, 0)
80-
compoundWithdrawalIndices := make([]primitives.ValidatorIndex, 0)
81-
if err = beaconState.ReadFromEveryValidator(func(index int, val state.ReadOnlyValidator) error {
82-
if val.ExitEpoch() != params.BeaconConfig().FarFutureEpoch && val.ExitEpoch() > earliestExitEpoch {
83-
earliestExitEpoch = val.ExitEpoch()
84-
}
85-
if val.ActivationEpoch() == params.BeaconConfig().FarFutureEpoch {
86-
preActivationIndices = append(preActivationIndices, primitives.ValidatorIndex(index))
87-
}
88-
if val.HasCompoundingWithdrawalCredentials() {
89-
compoundWithdrawalIndices = append(compoundWithdrawalIndices, primitives.ValidatorIndex(index))
90-
}
91-
return nil
92-
}); err != nil {
72+
depositBalanceToConsume, err := beaconState.DepositBalanceToConsume()
73+
if err != nil {
9374
return nil, err
9475
}
95-
96-
earliestExitEpoch++ // Increment to find the earliest possible exit epoch
97-
98-
// note: should be the same in prestate and post beaconState.
99-
// we are deviating from the specs a bit as it calls for using the post beaconState
100-
tab, err := helpers.TotalActiveBalance(beaconState)
76+
exitBalanceToConsume, err := beaconState.ExitBalanceToConsume()
10177
if err != nil {
102-
return nil, errors.Wrap(err, "failed to get total active balance")
78+
return nil, err
79+
}
80+
earliestExitEpoch, err := beaconState.EarliestExitEpoch()
81+
if err != nil {
82+
return nil, err
83+
}
84+
consolidationBalanceToConsume, err := beaconState.ConsolidationBalanceToConsume()
85+
if err != nil {
86+
return nil, err
87+
}
88+
earliestConsolidationEpoch, err := beaconState.EarliestConsolidationEpoch()
89+
if err != nil {
90+
return nil, err
91+
}
92+
pendingDeposits, err := beaconState.PendingDeposits()
93+
if err != nil {
94+
return nil, err
95+
}
96+
pendingPartialWithdrawals, err := beaconState.PendingPartialWithdrawals()
97+
if err != nil {
98+
return nil, err
99+
}
100+
pendingConsolidations, err := beaconState.PendingConsolidations()
101+
if err != nil {
102+
return nil, err
103103
}
104104

105105
s := &ethpb.BeaconStateFulu{
@@ -155,25 +155,16 @@ func UpgradeToFulu(beaconState state.BeaconState) (state.BeaconState, error) {
155155
HistoricalSummaries: summaries,
156156

157157
DepositRequestsStartIndex: params.BeaconConfig().UnsetDepositRequestsStartIndex,
158-
DepositBalanceToConsume: 0,
159-
ExitBalanceToConsume: helpers.ActivationExitChurnLimit(primitives.Gwei(tab)),
158+
DepositBalanceToConsume: depositBalanceToConsume,
159+
ExitBalanceToConsume: exitBalanceToConsume,
160160
EarliestExitEpoch: earliestExitEpoch,
161-
ConsolidationBalanceToConsume: helpers.ConsolidationChurnLimit(primitives.Gwei(tab)),
162-
EarliestConsolidationEpoch: helpers.ActivationExitEpoch(slots.ToEpoch(beaconState.Slot())),
163-
PendingDeposits: make([]*ethpb.PendingDeposit, 0),
164-
PendingPartialWithdrawals: make([]*ethpb.PendingPartialWithdrawal, 0),
165-
PendingConsolidations: make([]*ethpb.PendingConsolidation, 0),
161+
ConsolidationBalanceToConsume: consolidationBalanceToConsume,
162+
EarliestConsolidationEpoch: earliestConsolidationEpoch,
163+
PendingDeposits: pendingDeposits,
164+
PendingPartialWithdrawals: pendingPartialWithdrawals,
165+
PendingConsolidations: pendingConsolidations,
166166
}
167167

168-
// Sorting preActivationIndices based on a custom criteria
169-
sort.Slice(preActivationIndices, func(i, j int) bool {
170-
// Comparing based on ActivationEligibilityEpoch and then by index if the epochs are the same
171-
if s.Validators[preActivationIndices[i]].ActivationEligibilityEpoch == s.Validators[preActivationIndices[j]].ActivationEligibilityEpoch {
172-
return preActivationIndices[i] < preActivationIndices[j]
173-
}
174-
return s.Validators[preActivationIndices[i]].ActivationEligibilityEpoch < s.Validators[preActivationIndices[j]].ActivationEligibilityEpoch
175-
})
176-
177168
// Need to cast the beaconState to use in helper functions
178169
post, err := state_native.InitializeFromProtoUnsafeFulu(s)
179170
if err != nil {

beacon-chain/core/fulu/upgrade_test.go

Lines changed: 61 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import (
44
"testing"
55

66
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/fulu"
7-
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
87
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
98
"github.com/prysmaticlabs/prysm/v5/config/params"
109
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
1110
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
1211
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
1312
"github.com/prysmaticlabs/prysm/v5/testing/require"
1413
"github.com/prysmaticlabs/prysm/v5/testing/util"
15-
"github.com/prysmaticlabs/prysm/v5/time/slots"
1614
)
1715

1816
func TestUpgradeToFulu(t *testing.T) {
@@ -33,69 +31,57 @@ func TestUpgradeToFulu(t *testing.T) {
3331
require.Equal(t, preForkState.GenesisTime(), mSt.GenesisTime())
3432
require.DeepSSZEqual(t, preForkState.GenesisValidatorsRoot(), mSt.GenesisValidatorsRoot())
3533
require.Equal(t, preForkState.Slot(), mSt.Slot())
34+
35+
f := mSt.Fork()
36+
require.DeepSSZEqual(t, &ethpb.Fork{
37+
PreviousVersion: st.Fork().CurrentVersion,
38+
CurrentVersion: params.BeaconConfig().FuluForkVersion,
39+
Epoch: time.CurrentEpoch(st),
40+
}, f)
41+
3642
require.DeepSSZEqual(t, preForkState.LatestBlockHeader(), mSt.LatestBlockHeader())
3743
require.DeepSSZEqual(t, preForkState.BlockRoots(), mSt.BlockRoots())
3844
require.DeepSSZEqual(t, preForkState.StateRoots(), mSt.StateRoots())
39-
require.DeepSSZEqual(t, preForkState.Validators()[2:], mSt.Validators()[2:])
40-
require.DeepSSZEqual(t, preForkState.Balances()[2:], mSt.Balances()[2:])
45+
46+
hr1, err := preForkState.HistoricalRoots()
47+
require.NoError(t, err)
48+
hr2, err := mSt.HistoricalRoots()
49+
require.NoError(t, err)
50+
require.DeepEqual(t, hr1, hr2)
51+
4152
require.DeepSSZEqual(t, preForkState.Eth1Data(), mSt.Eth1Data())
4253
require.DeepSSZEqual(t, preForkState.Eth1DataVotes(), mSt.Eth1DataVotes())
4354
require.DeepSSZEqual(t, preForkState.Eth1DepositIndex(), mSt.Eth1DepositIndex())
55+
require.DeepSSZEqual(t, preForkState.Validators(), mSt.Validators())
56+
require.DeepSSZEqual(t, preForkState.Balances(), mSt.Balances())
4457
require.DeepSSZEqual(t, preForkState.RandaoMixes(), mSt.RandaoMixes())
4558
require.DeepSSZEqual(t, preForkState.Slashings(), mSt.Slashings())
46-
require.DeepSSZEqual(t, preForkState.JustificationBits(), mSt.JustificationBits())
47-
require.DeepSSZEqual(t, preForkState.PreviousJustifiedCheckpoint(), mSt.PreviousJustifiedCheckpoint())
48-
require.DeepSSZEqual(t, preForkState.CurrentJustifiedCheckpoint(), mSt.CurrentJustifiedCheckpoint())
49-
require.DeepSSZEqual(t, preForkState.FinalizedCheckpoint(), mSt.FinalizedCheckpoint())
50-
51-
require.Equal(t, len(preForkState.Validators()), len(mSt.Validators()))
52-
53-
preVal, err := preForkState.ValidatorAtIndex(0)
54-
require.NoError(t, err)
55-
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, preVal.EffectiveBalance)
56-
57-
preVal2, err := preForkState.ValidatorAtIndex(1)
58-
require.NoError(t, err)
59-
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, preVal2.EffectiveBalance)
60-
61-
// TODO: Fix this test
62-
// mVal, err := mSt.ValidatorAtIndex(0)
63-
_, err = mSt.ValidatorAtIndex(0)
64-
require.NoError(t, err)
65-
// require.Equal(t, uint64(0), mVal.EffectiveBalance)
66-
67-
mVal2, err := mSt.ValidatorAtIndex(1)
68-
require.NoError(t, err)
69-
require.Equal(t, params.BeaconConfig().MinActivationBalance, mVal2.EffectiveBalance)
7059

7160
numValidators := mSt.NumValidators()
61+
7262
p, err := mSt.PreviousEpochParticipation()
7363
require.NoError(t, err)
7464
require.DeepSSZEqual(t, make([]byte, numValidators), p)
65+
7566
p, err = mSt.CurrentEpochParticipation()
7667
require.NoError(t, err)
7768
require.DeepSSZEqual(t, make([]byte, numValidators), p)
69+
70+
require.DeepSSZEqual(t, preForkState.JustificationBits(), mSt.JustificationBits())
71+
require.DeepSSZEqual(t, preForkState.PreviousJustifiedCheckpoint(), mSt.PreviousJustifiedCheckpoint())
72+
require.DeepSSZEqual(t, preForkState.CurrentJustifiedCheckpoint(), mSt.CurrentJustifiedCheckpoint())
73+
require.DeepSSZEqual(t, preForkState.FinalizedCheckpoint(), mSt.FinalizedCheckpoint())
74+
7875
s, err := mSt.InactivityScores()
7976
require.NoError(t, err)
8077
require.DeepSSZEqual(t, make([]uint64, numValidators), s)
8178

82-
hr1, err := preForkState.HistoricalRoots()
83-
require.NoError(t, err)
84-
hr2, err := mSt.HistoricalRoots()
85-
require.NoError(t, err)
86-
require.DeepEqual(t, hr1, hr2)
87-
88-
f := mSt.Fork()
89-
require.DeepSSZEqual(t, &ethpb.Fork{
90-
PreviousVersion: st.Fork().CurrentVersion,
91-
CurrentVersion: params.BeaconConfig().FuluForkVersion,
92-
Epoch: time.CurrentEpoch(st),
93-
}, f)
9479
csc, err := mSt.CurrentSyncCommittee()
9580
require.NoError(t, err)
9681
psc, err := preForkState.CurrentSyncCommittee()
9782
require.NoError(t, err)
9883
require.DeepSSZEqual(t, psc, csc)
84+
9985
nsc, err := mSt.NextSyncCommittee()
10086
require.NoError(t, err)
10187
psc, err = preForkState.NextSyncCommittee()
@@ -110,7 +96,6 @@ func TestUpgradeToFulu(t *testing.T) {
11096
require.NoError(t, err)
11197
txRoot, err := prevHeader.TransactionsRoot()
11298
require.NoError(t, err)
113-
11499
wdRoot, err := prevHeader.WithdrawalsRoot()
115100
require.NoError(t, err)
116101
wanted := &enginev1.ExecutionPayloadHeaderDeneb{
@@ -144,45 +129,57 @@ func TestUpgradeToFulu(t *testing.T) {
144129
require.NoError(t, err)
145130
require.Equal(t, 0, len(summaries))
146131

147-
startIndex, err := mSt.DepositRequestsStartIndex()
132+
preDepositRequestsStartIndex, err := preForkState.DepositRequestsStartIndex()
148133
require.NoError(t, err)
149-
require.Equal(t, params.BeaconConfig().UnsetDepositRequestsStartIndex, startIndex)
150-
151-
balance, err := mSt.DepositBalanceToConsume()
134+
postDepositRequestsStartIndex, err := mSt.DepositRequestsStartIndex()
152135
require.NoError(t, err)
153-
require.Equal(t, primitives.Gwei(0), balance)
136+
require.Equal(t, preDepositRequestsStartIndex, postDepositRequestsStartIndex)
154137

155-
tab, err := helpers.TotalActiveBalance(mSt)
138+
preDepositBalanceToConsume, err := preForkState.DepositBalanceToConsume()
139+
require.NoError(t, err)
140+
postDepositBalanceToConsume, err := mSt.DepositBalanceToConsume()
156141
require.NoError(t, err)
142+
require.Equal(t, preDepositBalanceToConsume, postDepositBalanceToConsume)
157143

158-
ebtc, err := mSt.ExitBalanceToConsume()
144+
preExitBalanceToConsume, err := preForkState.ExitBalanceToConsume()
159145
require.NoError(t, err)
160-
require.Equal(t, helpers.ActivationExitChurnLimit(primitives.Gwei(tab)), ebtc)
146+
postExitBalanceToConsume, err := mSt.ExitBalanceToConsume()
147+
require.NoError(t, err)
148+
require.Equal(t, preExitBalanceToConsume, postExitBalanceToConsume)
161149

162-
eee, err := mSt.EarliestExitEpoch()
150+
preEarliestExitEpoch, err := preForkState.EarliestExitEpoch()
151+
require.NoError(t, err)
152+
postEarliestExitEpoch, err := mSt.EarliestExitEpoch()
163153
require.NoError(t, err)
164-
require.Equal(t, helpers.ActivationExitEpoch(primitives.Epoch(1)), eee)
154+
require.Equal(t, preEarliestExitEpoch, postEarliestExitEpoch)
165155

166-
cbtc, err := mSt.ConsolidationBalanceToConsume()
156+
preConsolidationBalanceToConsume, err := preForkState.ConsolidationBalanceToConsume()
167157
require.NoError(t, err)
168-
require.Equal(t, helpers.ConsolidationChurnLimit(primitives.Gwei(tab)), cbtc)
158+
postConsolidationBalanceToConsume, err := mSt.ConsolidationBalanceToConsume()
159+
require.NoError(t, err)
160+
require.Equal(t, preConsolidationBalanceToConsume, postConsolidationBalanceToConsume)
169161

170-
earliestConsolidationEpoch, err := mSt.EarliestConsolidationEpoch()
162+
preEarliesConsolidationEoch, err := preForkState.EarliestConsolidationEpoch()
163+
require.NoError(t, err)
164+
postEarliestConsolidationEpoch, err := mSt.EarliestConsolidationEpoch()
171165
require.NoError(t, err)
172-
require.Equal(t, helpers.ActivationExitEpoch(slots.ToEpoch(preForkState.Slot())), earliestConsolidationEpoch)
166+
require.Equal(t, preEarliesConsolidationEoch, postEarliestConsolidationEpoch)
173167

174-
// TODO: Fix this test
175-
// pendingDeposits, err := mSt.PendingDeposits()
176-
_, err = mSt.PendingDeposits()
168+
prePendingDeposits, err := preForkState.PendingDeposits()
177169
require.NoError(t, err)
178-
// require.Equal(t, 2, len(pendingDeposits))
179-
// require.Equal(t, uint64(1000), pendingDeposits[1].Amount)
170+
postPendingDeposits, err := mSt.PendingDeposits()
171+
require.NoError(t, err)
172+
require.DeepSSZEqual(t, prePendingDeposits, postPendingDeposits)
180173

181-
numPendingPartialWithdrawals, err := mSt.NumPendingPartialWithdrawals()
174+
prePendingPartialWithdrawals, err := preForkState.PendingPartialWithdrawals()
175+
require.NoError(t, err)
176+
postPendingPartialWithdrawals, err := mSt.PendingPartialWithdrawals()
182177
require.NoError(t, err)
183-
require.Equal(t, uint64(0), numPendingPartialWithdrawals)
178+
require.DeepSSZEqual(t, prePendingPartialWithdrawals, postPendingPartialWithdrawals)
184179

185-
consolidations, err := mSt.PendingConsolidations()
180+
prePendingConsolidations, err := preForkState.PendingConsolidations()
181+
require.NoError(t, err)
182+
postPendingConsolidations, err := mSt.PendingConsolidations()
186183
require.NoError(t, err)
187-
require.Equal(t, 0, len(consolidations))
184+
require.DeepSSZEqual(t, prePendingConsolidations, postPendingConsolidations)
188185
}

changelog/manu_fulu_fork.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Fixed
2+
3+
- `UpgradeToFulu`: Respect the specification.

0 commit comments

Comments
 (0)