Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
11 changes: 8 additions & 3 deletions beacon/blockchain/finalize_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ import (
"github.com/berachain/beacon-kit/consensus/types"
"github.com/berachain/beacon-kit/primitives/math"
"github.com/berachain/beacon-kit/primitives/transition"
"github.com/berachain/beacon-kit/primitives/version"
statedb "github.com/berachain/beacon-kit/state-transition/core/state"
cmtabci "github.com/cometbft/cometbft/abci/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

//nolint:funlen // Okay for now.
func (s *Service) FinalizeBlock(
ctx sdk.Context,
req *cmtabci.FinalizeBlockRequest,
Expand Down Expand Up @@ -109,9 +111,12 @@ func (s *Service) FinalizeBlock(

// STEP 4: Post Finalizations cleanups.

// Fetch and store the deposit for the block.
blockNum := blk.GetBody().GetExecutionPayload().GetNumber()
s.depositFetcher(ctx, blockNum)
// Before Electra1, deposits must be fetched from the EL directly in the CL.
if version.IsBefore(blk.GetForkVersion(), version.Electra1()) {
// Fetch and store the deposit for the block.
blockNum := blk.GetBody().GetExecutionPayload().GetNumber()
s.depositFetcher(ctx, blockNum)
}

// Store the finalized block in the KVStore.
//
Expand Down
55 changes: 29 additions & 26 deletions beacon/validator/block_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,36 +291,39 @@ func (s *Service) buildBlockBody(
// Set the KZG commitments on the block body.
body.SetBlobKzgCommitments(blobsBundle.GetCommitments())

// Dequeue deposits from the state.
depositIndex, err := st.GetEth1DepositIndex()
if err != nil {
return fmt.Errorf("failed loading eth1 deposit index: %w", err)
}
// Before Electra1, deposits are processed from the beacon block body directly.
if version.IsBefore(body.GetForkVersion(), version.Electra1()) {
// Dequeue deposits from the state.
depositIndex, err := st.GetEth1DepositIndex()
if err != nil {
return fmt.Errorf("failed loading eth1 deposit index: %w", err)
}

// Grab all previous deposits from genesis up to the current index + max deposits per block.
deposits, err := s.sb.DepositStore().GetDepositsByIndex(
ctx,
constants.FirstDepositIndex,
depositIndex+s.chainSpec.MaxDepositsPerBlock(),
)
if err != nil {
return err
}
if uint64(len(deposits)) < depositIndex {
return errors.Wrapf(ErrDepositStoreIncomplete,
"all historical deposits not available, expected: %d, got: %d",
depositIndex, len(deposits),
// Grab all previous deposits from genesis up to the current index + max deposits per block.
deposits, err := s.sb.DepositStore().GetDepositsByIndex(
ctx,
constants.FirstDepositIndex,
depositIndex+s.chainSpec.MaxDepositsPerBlock(),
)
}
if err != nil {
return err
}
if uint64(len(deposits)) < depositIndex {
return errors.Wrapf(ErrDepositStoreIncomplete,
"all historical deposits not available, expected: %d, got: %d",
depositIndex, len(deposits),
)
}

eth1Data := ctypes.NewEth1Data(deposits.HashTreeRoot())
body.SetEth1Data(eth1Data)
eth1Data := ctypes.NewEth1Data(deposits.HashTreeRoot())
body.SetEth1Data(eth1Data)

s.logger.Info(
"Building block body with local deposits",
"start_index", depositIndex, "num_deposits", uint64(len(deposits))-depositIndex,
)
body.SetDeposits(deposits[depositIndex:])
s.logger.Info(
"Building block body with local deposits",
"start_index", depositIndex, "num_deposits", uint64(len(deposits))-depositIndex,
)
body.SetDeposits(deposits[depositIndex:])
}

// Set the graffiti on the block body.
sizedGraffiti := bytes.ExtendToSize([]byte(s.cfg.Graffiti), bytes.B32Size)
Expand Down
2 changes: 2 additions & 0 deletions chain/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ 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"`
// Electra1ForkTime is the time at which the Electra1 fork is activated.
Electra1ForkTime uint64 `mapstructure:"electra-one-fork-time"`

// State list lengths
//
Expand Down
9 changes: 9 additions & 0 deletions chain/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ type ForkSpec interface {

// ElectraForkTime returns the time at which the Electra fork takes effect.
ElectraForkTime() uint64

// Electra1ForkTime returns the time at which the Electra1 fork takes effect.
Electra1ForkTime() uint64
}

type BlobSpec interface {
Expand Down Expand Up @@ -252,6 +255,7 @@ func (s spec) validate() error {
s.Data.GenesisTime,
s.Data.Deneb1ForkTime,
s.Data.ElectraForkTime,
s.Data.Electra1ForkTime,
}
for i := 1; i < len(orderedForkTimes); i++ {
prev, cur := orderedForkTimes[i-1], orderedForkTimes[i]
Expand Down Expand Up @@ -393,6 +397,11 @@ func (s spec) ElectraForkTime() uint64 {
return s.Data.ElectraForkTime
}

// Electra1ForkTime returns the epoch of the Electra1 fork.
func (s spec) Electra1ForkTime() uint64 {
return s.Data.Electra1ForkTime
}

// EpochsPerHistoricalVector returns the number of epochs per historical vector.
func (s spec) EpochsPerHistoricalVector() uint64 {
return s.Data.EpochsPerHistoricalVector
Expand Down
1 change: 1 addition & 0 deletions config/spec/mainnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@
TargetSecondsPerEth1Block: defaultTargetSecondsPerEth1Block,

// Fork-related values.
GenesisTime: mainnetGenesisTime,

Check failure on line 133 in config/spec/mainnet.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gci)
Deneb1ForkTime: mainnetDeneb1ForkTime,
ElectraForkTime: mainnetElectraForkTime,
Electra1ForkTime: 9999999999999999999,

Check failure on line 136 in config/spec/mainnet.go

View workflow job for this annotation

GitHub Actions / lint

Magic number: 9999999999999999999, in <assign> detected (mnd)

// State list length constants.
EpochsPerHistoricalVector: defaultEpochsPerHistoricalVector,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"max": 6,
"baseFeeUpdateFraction": 3338477
}
}
},
"depositContractAddress": "0x4242424242424242424242424242424242424242"
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x0",
Expand Down
46 changes: 46 additions & 0 deletions state-transition/core/state_processor_forks.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ func (sp *StateProcessor) ProcessFork(
if logUpgrade {
sp.logElectraFork(stateFork.PreviousVersion, timestamp, slot)
}
case version.Electra1():
if err = sp.upgradeToElectra1(st, stateFork, slot); err != nil {
return err
}

// Log the upgrade to Electra1 if requested.
if logUpgrade {
sp.logElectra1Fork(stateFork.PreviousVersion, timestamp, slot)
}
default:
panic(fmt.Sprintf("unsupported fork version: %s", forkVersion))
}
Expand Down Expand Up @@ -208,3 +217,40 @@ func (sp *StateProcessor) logElectraFork(
sp.cs.SlotToEpoch(slot).Unwrap(),
))
}

// upgradeToElectra1 upgrades the state to the Electra1 fork version. It just sets the Fork struct
// in the BeaconState.
func (sp *StateProcessor) upgradeToElectra1(
st *statedb.StateDB, fork *types.Fork, slot math.Slot,
) error {
// Set the fork on BeaconState.
fork.PreviousVersion = fork.CurrentVersion
fork.CurrentVersion = version.Electra1()
fork.Epoch = sp.cs.SlotToEpoch(slot)
return st.SetFork(fork)
}

// logElectra1Fork logs information about the Electra1 fork.
func (sp *StateProcessor) logElectra1Fork(
previousVersion common.Version, timestamp math.U64, slot math.Slot,
) {
sp.logger.Info(fmt.Sprintf(`


⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️

+ ✅ welcome to the electra1 (0x05010000) fork! 🎉
+ 🚝 previous fork: %s (%s)
+ ⏱️ electra1 fork time: %d
+ 🍴 first slot / timestamp of electra1: %d / %d
+ ⛓️ current beacon epoch: %d

⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️

`,
version.Name(previousVersion), previousVersion.String(),
sp.cs.Electra1ForkTime(),
slot.Unwrap(), timestamp.Unwrap(),
sp.cs.SlotToEpoch(slot).Unwrap(),
))
}
77 changes: 45 additions & 32 deletions state-transition/core/state_processor_staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,50 +37,63 @@ func (sp *StateProcessor) processOperations(
st *state.StateDB,
blk *ctypes.BeaconBlock,
) error {
// Verify that outstanding deposits are processed up to the maximum number of deposits.
//
// Unlike Eth 2.0 specs we don't check that
// `len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)`
deposits := blk.GetBody().GetDeposits()
if uint64(len(deposits)) > sp.cs.MaxDepositsPerBlock() {
return errors.Wrapf(
ErrExceedsBlockDepositLimit, "expected: %d, got: %d",
sp.cs.MaxDepositsPerBlock(), len(deposits),
)
// Before Electra1, deposits are processed from the beacon block body directly.
if version.IsBefore(blk.GetForkVersion(), version.Electra1()) {
// Verify that outstanding deposits are processed up to the maximum number of deposits.
//
// Unlike Ethereum 2.0 specs, we don't check that
// `len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)`.
deposits := blk.GetBody().GetDeposits()
if uint64(len(deposits)) > sp.cs.MaxDepositsPerBlock() {
return errors.Wrapf(
ErrExceedsBlockDepositLimit, "expected: %d, got: %d",
sp.cs.MaxDepositsPerBlock(), len(deposits),
)
}

// Instead, we directly compare block deposits with our local store ones.
if err := ValidateNonGenesisDeposits(
ctx.ConsensusCtx(),
st,
sp.ds,
sp.cs.MaxDepositsPerBlock(),
deposits,
blk.GetBody().GetEth1Data().DepositRoot,
); err != nil {
return err
}

for _, dep := range deposits {
if err := sp.processDeposit(st, dep); err != nil {
return err
}
}

return st.SetEth1Data(blk.GetBody().Eth1Data)
}

// Instead we directly compare block deposits with our local store ones.
if err := ValidateNonGenesisDeposits(
ctx.ConsensusCtx(),
st,
sp.ds,
sp.cs.MaxDepositsPerBlock(),
deposits,
blk.GetBody().GetEth1Data().DepositRoot,
); err != nil {
// After Electra1, validators increase/decrease stake through execution requests which must
// be handled.
requests, err := blk.GetBody().GetExecutionRequests()
if err != nil {
return err
}

for _, dep := range deposits {
if err := sp.processDeposit(st, dep); err != nil {
return err
// EIP-7002 Withdrawals.
for _, withdrawal := range requests.Withdrawals {
if withdrawErr := sp.processWithdrawalRequest(st, withdrawal); withdrawErr != nil {
return withdrawErr
}
}

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 {
// EIP-6110 Deposits.
for _, dep := range requests.Deposits {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the biggest change is here: Post this fork, we will just accept the deposits from here as we have instant finality. No deposits queue or epoch processing is necessary here; real-time instant deposits very easily done

if err = sp.processDeposit(st, dep); err != nil {
return err
}
for _, withdrawal := range requests.Withdrawals {
if withdrawErr := sp.processWithdrawalRequest(st, withdrawal); withdrawErr != nil {
return withdrawErr
}
}
}

return st.SetEth1Data(blk.GetBody().Eth1Data)
return st.SetEth1Data(ctypes.NewEmptyEth1Data())
}

// processDeposit processes the deposit and ensures it matches the local state.
Expand Down
3 changes: 2 additions & 1 deletion testing/files/eth-genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"max": 6,
"baseFeeUpdateFraction": 3338477
}
}
},
"depositContractAddress": "0x4242424242424242424242424242424242424242"
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x0",
Expand Down
1 change: 1 addition & 0 deletions testing/files/spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ target-seconds-per-eth1-block = 2
genesis-time = 0
deneb-one-fork-time = 0
electra-fork-time = 0
electra-one-fork-time = 9_999_999_999_999_999_999

# State list lengths
epochs-per-historical-vector = 8
Expand Down
3 changes: 2 additions & 1 deletion testing/networks/80069/eth-genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@
"max": 6,
"baseFeeUpdateFraction": 3338477
}
}
},
"depositContractAddress": "0x4242424242424242424242424242424242424242"
},
"difficulty": "0x01",
"extraData": "",
Expand Down
1 change: 1 addition & 0 deletions testing/networks/80069/spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ 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-one-fork-time = 9_999_999_999_999_999_999

# State list lengths
epochs-per-historical-vector = 8
Expand Down
3 changes: 2 additions & 1 deletion testing/networks/80094/eth-genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"baseFeeUpdateFraction": 3338477
}
},
"ethash": {}
"ethash": {},
"depositContractAddress": "0x4242424242424242424242424242424242424242"
},
"coinbase": "0x0000000000000000000000000000000000000000",
"difficulty": "0x01",
Expand Down
1 change: 1 addition & 0 deletions testing/networks/80094/spec.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ target-seconds-per-eth1-block = 2
genesis-time = 1_737_381_600
deneb-one-fork-time = 1_738_415_507
electra-fork-time = 1_749_056_400
electra-one-fork-time = 9_999_999_999_999_999_999

# State list lengths
epochs-per-historical-vector = 8
Expand Down
Loading