Skip to content
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
11d3adc
fix issue
rezzmah May 19, 2025
e141967
add withdrawals_enabled
rezzmah May 19, 2025
c416f12
Added check
rezzmah May 19, 2025
8f81a38
extending withdrawals disabling
rezzmah May 19, 2025
1f9b9c9
Remove electra changes
rezzmah May 19, 2025
eb5df2c
fix
rezzmah May 19, 2025
368fd7e
Update statedb.go
rezzmah May 20, 2025
f8b2016
Update statedb.go
rezzmah May 20, 2025
b84c9ea
Update statedb.go
rezzmah May 20, 2025
8c10052
comments linting
rezzmah May 20, 2025
7f0ae9b
Added test for freezing withdrawals
rezzmah May 20, 2025
cbffee5
Added test
rezzmah May 20, 2025
6f76b58
Add Disable and Enable Fork
rezzmah May 20, 2025
0485ae0
Update defaults.go
rezzmah May 20, 2025
23bd6d5
Update devnet.go
rezzmah May 20, 2025
c018962
Update devnet.go
rezzmah May 20, 2025
31f1bcb
Process Withdrawal Requests even if withdrawals disabled
rezzmah May 21, 2025
b013aea
Merge branch 'main' into prep-for-em-fork
rezzmah May 21, 2025
0cca53e
Fix comment based on updated logic
rezzmah May 21, 2025
f366782
Flip to withdrawals disabled
rezzmah May 21, 2025
dc4ed01
Merge branch 'main' into prep-for-em-fork
rezzmah May 21, 2025
32200e0
merge conflict fix
rezzmah May 21, 2025
8a5b80d
Merge branch 'main' into prep-for-em-fork
rezzmah May 27, 2025
79e3e61
Merge branch 'main' into prep-for-em-fork
rezzmah May 28, 2025
23daa35
Add spec enforcement of ordering
rezzmah May 28, 2025
f0bd3ac
Merge branch 'main' into prep-for-em-fork
calbera May 28, 2025
f5d3115
Merge branch 'main' into prep-for-em-fork
rezzmah Jun 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions chain/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ type SpecData struct {
Deneb1ForkTime uint64 `mapstructure:"deneb-one-fork-time"`
// ElectraForkTime is the time at which the Electra fork is activated.
ElectraForkTime uint64 `mapstructure:"electra-fork-time"`
// ElectraDisableWithdrawalsForkTime is the time at which withdrawals were first disabled (if disabled).
ElectraDisableWithdrawalsForkTime uint64 `mapstructure:"electra-disable-withdrawals-fork-time"`
// ElectraEnableWithdrawalsForkTime is the time at which withdrawals were enabled after disabling
ElectraEnableWithdrawalsForkTime uint64 `mapstructure:"electra-enable-withdrawals-fork-time"`
Comment on lines +98 to +101
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should enforce somewhere that Disable Time <= Enable Time

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also wonder if we should make scaffolding for multiple periods of withdrawal pause?

Copy link
Copy Markdown
Contributor

@abi87 abi87 May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also consider renaming this to DisableWithdrawalsRequestsWindowStart and DisableWithdrawalsRequestsWindowEnd.
I do not believe this is strictly related to Electra.
Also we should stress this is a disabling window

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, in terms of operations we just need to specify the start window at first, right? We can leave the end to farFuture and reset that once the window is closed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should enforce somewhere that Disable Time <= Enable Time

This should be done as a larger ordering enforcement of forks. e.g. geth https://github.com/ethereum/go-ethereum/blob/516451dc3a514c7c122f28864ea76742a027b858/params/config.go#L702

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, in terms of operations we just need to specify the start window at first, right? We can leave the end to farFuture and reset that once the window is closed

correct

Copy link
Copy Markdown
Contributor

@calbera calbera May 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforcement of fork timestamps for now can be done in the (s spec) validate() error function we already have. Good way to make use of that and I would also recommend taking this opportunity to add it in.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// State list lengths
//
Expand Down
13 changes: 13 additions & 0 deletions chain/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ import (
)

// ActiveForkVersionForTimestamp returns the active fork version for a given timestamp.
// Note that ActiveForkVersionForTimestamp will NOT check for
// - ElectraDisableWithdrawalsForkTime
// - ElectraEnableWithdrawalsForkTime
//
// As there is no logic that relies on the above forks that goes through ActiveForkVersionForTimestamp.
// It also gives flexibility for these forks to occur at any point after Electra, e.g. after Electra1.
func (s spec) ActiveForkVersionForTimestamp(timestamp math.U64) common.Version {
time := timestamp.Unwrap()
if time >= s.ElectraForkTime() {
Expand All @@ -38,6 +44,13 @@ func (s spec) ActiveForkVersionForTimestamp(timestamp math.U64) common.Version {
return version.Deneb()
}

// WithdrawalsDisabled is a switch that can be used to freeze withdrawals in an emergency scenario.
// An exception is made for the EVM inflation withdrawal which is always active.
func (s spec) WithdrawalsDisabled(timestamp math.U64) bool {
time := timestamp.Unwrap()
return time >= s.ElectraDisableWithdrawalsForkTime() && time < s.ElectraEnableWithdrawalsForkTime()
}

// GenesisForkVersion returns the fork version at genesis.
func (s spec) GenesisForkVersion() common.Version {
return s.ActiveForkVersionForTimestamp(math.U64(s.GenesisTime()))
Expand Down
18 changes: 16 additions & 2 deletions chain/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ type WithdrawalsSpec interface {
// which is set to MIN_VALIDATOR_WITHDRAWABILITY_DELAY epochs after its exit_epoch.
// This is to allow some extra time for any slashable offences by the validator to be detected and reported.
MinValidatorWithdrawabilityDelay() math.Epoch

// WithdrawalsDisabled is a switch that can be used to freeze withdrawals in an emergency scenario.
// An exception is made for the EVM inflation withdrawal which is always active.
WithdrawalsDisabled(timestamp math.U64) bool
}

// Spec defines an interface for accessing chain-specific parameters.
Expand Down Expand Up @@ -365,16 +369,26 @@ func (s spec) GenesisTime() uint64 {
return s.Data.GenesisTime
}

// Deneb1ForkTime returns the epoch of the Deneb1 fork.
// Deneb1ForkTime returns the timestamp of the Deneb1 fork.
func (s spec) Deneb1ForkTime() uint64 {
return s.Data.Deneb1ForkTime
}

// ElectraForkTime returns the epoch of the Electra fork.
// ElectraForkTime returns the timestamp of the Electra fork.
func (s spec) ElectraForkTime() uint64 {
return s.Data.ElectraForkTime
}

// ElectraDisableWithdrawalsForkTime returns the timestamps of the ElectraDisableWithdrawalsForkTime fork.
func (s spec) ElectraDisableWithdrawalsForkTime() uint64 {
return s.Data.ElectraDisableWithdrawalsForkTime
}

// ElectraEnableWithdrawalsForkTime returns the timestamps of the ElectraEnableWithdrawalsForkTime fork.
func (s spec) ElectraEnableWithdrawalsForkTime() uint64 {
return s.Data.ElectraEnableWithdrawalsForkTime
}

// EpochsPerHistoricalVector returns the number of epochs per historical vector.
func (s spec) EpochsPerHistoricalVector() uint64 {
return s.Data.EpochsPerHistoricalVector
Expand Down
5 changes: 5 additions & 0 deletions config/spec/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ const (
defaultEth1FollowDistance = 1 // Berachain specific.
defaultTargetSecondsPerEth1Block = 2 // Berachain specific.

// Fork-related values.
defaultFarFutureTimestamp = 9999999999999999 // a future timestamp as not yet determined.
defaultElectraDisableWithdrawalsForkTime = defaultFarFutureTimestamp
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To enable and disable on ETH Mainnet, update these values to a relevant timestamp

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultElectraEnableWithdrawalsForkTime = defaultFarFutureTimestamp

// State list length constants.
defaultEpochsPerHistoricalVector = 8
defaultEpochsPerSlashingsVector = 8
Expand Down
7 changes: 7 additions & 0 deletions config/spec/devnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ const (
// devnet is configured to start on electra.
devnetElectraForkTime = 0

// devnetElectraDisableWithdrawalsForkTime is the start time at which withdrawals are disabled
devnetElectraDisableWithdrawalsForkTime = defaultFarFutureTimestamp
// devnetElectraEnableWithdrawalsForkTime is the start time at which withdrawals are re-enabled
devnetElectraEnableWithdrawalsForkTime = defaultFarFutureTimestamp

// devnetEVMInflationAddressDeneb1 is the address of the EVM inflation contract
// after the Deneb1 fork.
devnetEVMInflationAddressDeneb1 = "0x4206942069420694206942069420694206942069"
Expand All @@ -72,6 +77,8 @@ func DevnetChainSpecData() *chain.SpecData {
specData.GenesisTime = devnetGenesisTime
specData.Deneb1ForkTime = devnetDeneb1ForkTime
specData.ElectraForkTime = devnetElectraForkTime
specData.ElectraDisableWithdrawalsForkTime = devnetElectraDisableWithdrawalsForkTime
specData.ElectraEnableWithdrawalsForkTime = devnetElectraEnableWithdrawalsForkTime

// EVM inflation is different from mainnet to test.
specData.EVMInflationAddressGenesis = common.NewExecutionAddressFromHex(devnetEVMInflationAddress)
Expand Down
8 changes: 5 additions & 3 deletions config/spec/mainnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ func MainnetChainSpecData() *chain.SpecData {
TargetSecondsPerEth1Block: defaultTargetSecondsPerEth1Block,

// Fork-related values.
GenesisTime: mainnetGenesisTime,
Deneb1ForkTime: mainnetDeneb1ForkTime,
ElectraForkTime: mainnetElectraForkTime,
GenesisTime: mainnetGenesisTime,
Deneb1ForkTime: mainnetDeneb1ForkTime,
ElectraForkTime: mainnetElectraForkTime,
ElectraDisableWithdrawalsForkTime: defaultElectraDisableWithdrawalsForkTime,
ElectraEnableWithdrawalsForkTime: defaultElectraEnableWithdrawalsForkTime,

// State list length constants.
EpochsPerHistoricalVector: defaultEpochsPerHistoricalVector,
Expand Down
4 changes: 4 additions & 0 deletions config/spec/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func TestnetChainSpecData() *chain.SpecData {
// Timestamp of the Electra fork on Bepolia.
specData.ElectraForkTime = 1746633600

// Override the mainnet configuration for timestamps so it is not accidentally set on testnet a mainnet update.
specData.ElectraDisableWithdrawalsForkTime = defaultFarFutureTimestamp
specData.ElectraEnableWithdrawalsForkTime = defaultFarFutureTimestamp

return specData
}

Expand Down
10 changes: 10 additions & 0 deletions state-transition/core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ func (s *StateDB) ExpectedWithdrawals(timestamp math.U64) (engineprimitives.With
// The first withdrawal is fixed to be the EVM inflation withdrawal.
withdrawals = append(withdrawals, s.EVMInflationWithdrawal(timestamp))

// If withdrawals are not enabled, return only the inflation withdrawal.
// Once withdrawals are re-enabled, all pending withdrawals will be processed.
// 1. Partial Withdrawal Requests will remain untouched and will be handled after re-enabling.
// 2. Validators whose balance is above MAX_EFFECTIVE_BALANCE will not be withdrawn till re-enabled.
// 3. Validators who have initiated a full withdrawal will not be withdrawn till re-enabled.
// 4. Validators who have been kicked out due to validator set cap will not be withdrawn till re-enabled.
if s.cs.WithdrawalsDisabled(timestamp) {
return withdrawals, processedPartialWithdrawals, nil
}

withdrawalIndex, err := s.GetNextWithdrawalIndex()
if err != nil {
return nil, 0, err
Expand Down
2 changes: 1 addition & 1 deletion state-transition/core/state_processor_staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ func (sp *StateProcessor) processOperations(
}
}

// After Electra, validators can request withdrawals through execution requests which must be handled.
if version.EqualsOrIsAfter(blk.GetForkVersion(), version.Electra()) {
// After Electra, validators can request withdrawals through execution requests which must be handled.
requests, err := blk.GetBody().GetExecutionRequests()
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions testing/files/spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ target-seconds-per-eth1-block = 2
genesis-time = 0
deneb-one-fork-time = 0
electra-fork-time = 0
electra-disable-withdrawals-fork-time = 9_999_999_999_999_999
electra-enable-withdrawals-fork-time = 9_999_999_999_999_999

# State list lengths
epochs-per-historical-vector = 8
Expand Down
2 changes: 2 additions & 0 deletions testing/networks/80069/spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ target-seconds-per-eth1-block = 2
genesis-time = 1_739_976_735
deneb-one-fork-time = 1_740_090_694
electra-fork-time = 1_746_633_600
electra-disable-withdrawals-fork-time = 9_999_999_999_999_999
electra-enable-withdrawals-fork-time = 9_999_999_999_999_999

# State list lengths
epochs-per-historical-vector = 8
Expand Down
2 changes: 2 additions & 0 deletions testing/networks/80094/spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ target-seconds-per-eth1-block = 2
genesis-time = 1_737_381_600
deneb-one-fork-time = 1_738_415_507
electra-fork-time = 1_748_451_600
electra-disable-withdrawals-fork-time = 9_999_999_999_999_999
electra-enable-withdrawals-fork-time = 9_999_999_999_999_999
Comment on lines +38 to +39
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also update these these value to configure the fork on mainnet


# State list lengths
epochs-per-historical-vector = 8
Expand Down
27 changes: 27 additions & 0 deletions testing/simulated/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,30 @@ func ProvidePectraWithdrawalTestChainSpec() (chain.Spec, error) {
}
return chainSpec, nil
}

// ProvideFreezeWithdrawalsChainSpec provides a chain spec with pectra as the genesis, but with the
// withdrawals disabled and then re-enabled.
func ProvideFreezeWithdrawalsChainSpec() (chain.Spec, error) {
specData := spec.TestnetChainSpecData()
// Both Deneb1 and Electra happen in genesis.
specData.GenesisTime = 0
specData.Deneb1ForkTime = 0
specData.ElectraForkTime = 0
// We set slots per epoch to 1 for faster observation of withdrawal behaviour
specData.SlotsPerEpoch = 1
// We set this to 4 so tests are faster
specData.MinValidatorWithdrawabilityDelay = 4
// Reduced validator set cap so eviction withdrawals are easier to trigger
specData.ValidatorSetCap = 1

// Disable and Enable withdrawals.
specData.ElectraDisableWithdrawalsForkTime = 10
specData.ElectraEnableWithdrawalsForkTime = 30

chainSpec, err := chain.NewSpec(specData)
if err != nil {
return nil, err
}

return chainSpec, nil
}
Loading
Loading