Add Gloas beacon state package (#15611)

* Add Gloas protobuf definitions with spec tests

Add Gloas state fields to beacon state implementation

* Remove shared field for pending payment

* Radek's feedback

* Potuz feedback

* use slice concat

* Fix comment

* Fix concat

* Fix comment

* Fix correct index
This commit is contained in:
terence
2025-11-18 10:08:31 -05:00
committed by GitHub
parent 35c1ab5e88
commit bc0868e232
24 changed files with 1041 additions and 15 deletions

View File

@@ -23,6 +23,7 @@ go_library(
"getters_sync_committee.go",
"getters_validator.go",
"getters_withdrawal.go",
"gloas.go",
"hasher.go",
"multi_value_slices.go",
"proofs.go",

View File

@@ -70,6 +70,14 @@ type BeaconState struct {
pendingConsolidations []*ethpb.PendingConsolidation // pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT]
proposerLookahead []primitives.ValidatorIndex // proposer_look_ahead: List[uint64, (MIN_LOOKAHEAD + 1)*SLOTS_PER_EPOCH]
// Gloas fields
latestExecutionPayloadBid *ethpb.ExecutionPayloadBid
executionPayloadAvailability []byte
builderPendingPayments []*ethpb.BuilderPendingPayment
builderPendingWithdrawals []*ethpb.BuilderPendingWithdrawal
latestBlockHash []byte
latestWithdrawalsRoot []byte
id uint64
lock sync.RWMutex
dirtyFields map[types.FieldIndex]bool
@@ -125,6 +133,12 @@ type beaconStateMarshalable struct {
PendingPartialWithdrawals []*ethpb.PendingPartialWithdrawal `json:"pending_partial_withdrawals" yaml:"pending_partial_withdrawals"`
PendingConsolidations []*ethpb.PendingConsolidation `json:"pending_consolidations" yaml:"pending_consolidations"`
ProposerLookahead []primitives.ValidatorIndex `json:"proposer_look_ahead" yaml:"proposer_look_ahead"`
LatestExecutionPayloadBid *ethpb.ExecutionPayloadBid `json:"latest_execution_payload_bid" yaml:"latest_execution_payload_bid"`
ExecutionPayloadAvailability []byte `json:"execution_payload_availability" yaml:"execution_payload_availability"`
BuilderPendingPayments []*ethpb.BuilderPendingPayment `json:"builder_pending_payments" yaml:"builder_pending_payments"`
BuilderPendingWithdrawals []*ethpb.BuilderPendingWithdrawal `json:"builder_pending_withdrawals" yaml:"builder_pending_withdrawals"`
LatestBlockHash []byte `json:"latest_block_hash" yaml:"latest_block_hash"`
LatestWithdrawalsRoot []byte `json:"latest_withdrawals_root" yaml:"latest_withdrawals_root"`
}
func (b *BeaconState) MarshalJSON() ([]byte, error) {
@@ -179,6 +193,12 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
PendingPartialWithdrawals: b.pendingPartialWithdrawals,
PendingConsolidations: b.pendingConsolidations,
ProposerLookahead: b.proposerLookahead,
LatestExecutionPayloadBid: b.latestExecutionPayloadBid,
ExecutionPayloadAvailability: b.executionPayloadAvailability,
BuilderPendingPayments: b.builderPendingPayments,
BuilderPendingWithdrawals: b.builderPendingWithdrawals,
LatestBlockHash: b.latestBlockHash,
LatestWithdrawalsRoot: b.latestWithdrawalsRoot,
}
return json.Marshal(marshalable)
}

View File

@@ -259,6 +259,57 @@ func (b *BeaconState) ToProtoUnsafe() any {
PendingConsolidations: b.pendingConsolidations,
ProposerLookahead: lookahead,
}
case version.Gloas:
lookahead := make([]uint64, len(b.proposerLookahead))
for i, v := range b.proposerLookahead {
lookahead[i] = uint64(v)
}
return &ethpb.BeaconStateGloas{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.fork,
LatestBlockHeader: b.latestBlockHeader,
BlockRoots: br,
StateRoots: sr,
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
Validators: vals,
Balances: bals,
RandaoMixes: rm,
Slashings: b.slashings,
PreviousEpochParticipation: b.previousEpochParticipation,
CurrentEpochParticipation: b.currentEpochParticipation,
JustificationBits: b.justificationBits,
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: inactivityScores,
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadBid: b.latestExecutionPayloadBid,
NextWithdrawalIndex: b.nextWithdrawalIndex,
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
HistoricalSummaries: b.historicalSummaries,
DepositRequestsStartIndex: b.depositRequestsStartIndex,
DepositBalanceToConsume: b.depositBalanceToConsume,
ExitBalanceToConsume: b.exitBalanceToConsume,
EarliestExitEpoch: b.earliestExitEpoch,
ConsolidationBalanceToConsume: b.consolidationBalanceToConsume,
EarliestConsolidationEpoch: b.earliestConsolidationEpoch,
PendingDeposits: b.pendingDeposits,
PendingPartialWithdrawals: b.pendingPartialWithdrawals,
PendingConsolidations: b.pendingConsolidations,
ProposerLookahead: lookahead,
ExecutionPayloadAvailability: b.executionPayloadAvailability,
BuilderPendingPayments: b.builderPendingPayments,
BuilderPendingWithdrawals: b.builderPendingWithdrawals,
LatestBlockHash: b.latestBlockHash,
LatestWithdrawalsRoot: b.latestWithdrawalsRoot,
}
default:
return nil
}
@@ -510,6 +561,57 @@ func (b *BeaconState) ToProto() any {
PendingConsolidations: b.pendingConsolidationsVal(),
ProposerLookahead: lookahead,
}
case version.Gloas:
lookahead := make([]uint64, len(b.proposerLookahead))
for i, v := range b.proposerLookahead {
lookahead[i] = uint64(v)
}
return &ethpb.BeaconStateGloas{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.forkVal(),
LatestBlockHeader: b.latestBlockHeaderVal(),
BlockRoots: br,
StateRoots: sr,
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1DataVal(),
Eth1DataVotes: b.eth1DataVotesVal(),
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validatorsVal(),
Balances: b.balancesVal(),
RandaoMixes: rm,
Slashings: b.slashingsVal(),
PreviousEpochParticipation: b.previousEpochParticipationVal(),
CurrentEpochParticipation: b.currentEpochParticipationVal(),
JustificationBits: b.justificationBitsVal(),
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
FinalizedCheckpoint: b.finalizedCheckpointVal(),
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
NextSyncCommittee: b.nextSyncCommitteeVal(),
LatestExecutionPayloadBid: b.latestExecutionPayloadBid.Copy(),
NextWithdrawalIndex: b.nextWithdrawalIndex,
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
HistoricalSummaries: b.historicalSummariesVal(),
DepositRequestsStartIndex: b.depositRequestsStartIndex,
DepositBalanceToConsume: b.depositBalanceToConsume,
ExitBalanceToConsume: b.exitBalanceToConsume,
EarliestExitEpoch: b.earliestExitEpoch,
ConsolidationBalanceToConsume: b.consolidationBalanceToConsume,
EarliestConsolidationEpoch: b.earliestConsolidationEpoch,
PendingDeposits: b.pendingDepositsVal(),
PendingPartialWithdrawals: b.pendingPartialWithdrawalsVal(),
PendingConsolidations: b.pendingConsolidationsVal(),
ProposerLookahead: lookahead,
ExecutionPayloadAvailability: b.executionPayloadAvailabilityVal(),
BuilderPendingPayments: b.builderPendingPaymentsVal(),
BuilderPendingWithdrawals: b.builderPendingWithdrawalsVal(),
LatestBlockHash: b.latestBlockHashVal(),
LatestWithdrawalsRoot: b.latestWithdrawalsRootVal(),
}
default:
return nil
}

View File

@@ -0,0 +1,74 @@
package state_native
import (
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
)
// executionPayloadAvailabilityVal returns a copy of the execution payload availability.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) executionPayloadAvailabilityVal() []byte {
if b.executionPayloadAvailability == nil {
return nil
}
availability := make([]byte, len(b.executionPayloadAvailability))
copy(availability, b.executionPayloadAvailability)
return availability
}
// builderPendingPaymentsVal returns a copy of the builder pending payments.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) builderPendingPaymentsVal() []*ethpb.BuilderPendingPayment {
if b.builderPendingPayments == nil {
return nil
}
payments := make([]*ethpb.BuilderPendingPayment, len(b.builderPendingPayments))
for i, payment := range b.builderPendingPayments {
payments[i] = payment.Copy()
}
return payments
}
// builderPendingWithdrawalsVal returns a copy of the builder pending withdrawals.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) builderPendingWithdrawalsVal() []*ethpb.BuilderPendingWithdrawal {
if b.builderPendingWithdrawals == nil {
return nil
}
withdrawals := make([]*ethpb.BuilderPendingWithdrawal, len(b.builderPendingWithdrawals))
for i, withdrawal := range b.builderPendingWithdrawals {
withdrawals[i] = withdrawal.Copy()
}
return withdrawals
}
// latestBlockHashVal returns a copy of the latest block hash.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) latestBlockHashVal() []byte {
if b.latestBlockHash == nil {
return nil
}
hash := make([]byte, len(b.latestBlockHash))
copy(hash, b.latestBlockHash)
return hash
}
// latestWithdrawalsRootVal returns a copy of the latest withdrawals root.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) latestWithdrawalsRootVal() []byte {
if b.latestWithdrawalsRoot == nil {
return nil
}
root := make([]byte, len(b.latestWithdrawalsRoot))
copy(root, b.latestWithdrawalsRoot)
return root
}

View File

@@ -43,6 +43,8 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateElectraFieldCount)
case version.Fulu:
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateFuluFieldCount)
case version.Gloas:
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateGloasFieldCount)
default:
return nil, fmt.Errorf("unknown state version %s", version.String(state.version))
}
@@ -245,7 +247,7 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
fieldRoots[types.LatestExecutionPayloadHeaderCapella.RealPosition()] = executionPayloadRoot[:]
}
if state.version >= version.Deneb {
if state.version >= version.Deneb && state.version < version.Gloas {
// Execution payload root.
executionPayloadRoot, err := state.latestExecutionPayloadHeaderDeneb.HashTreeRoot()
if err != nil {
@@ -254,6 +256,16 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
fieldRoots[types.LatestExecutionPayloadHeaderDeneb.RealPosition()] = executionPayloadRoot[:]
}
if state.version >= version.Gloas {
// Execution payload bid root for Gloas.
bidRoot, err := state.latestExecutionPayloadBid.HashTreeRoot()
if err != nil {
return nil, err
}
fieldRoots[types.LatestExecutionPayloadBid.RealPosition()] = bidRoot[:]
}
if state.version >= version.Capella {
// Next withdrawal index root.
nextWithdrawalIndexRoot := make([]byte, 32)
@@ -328,5 +340,34 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
}
fieldRoots[types.ProposerLookahead.RealPosition()] = proposerLookaheadRoot[:]
}
if state.version >= version.Gloas {
epaRoot, err := stateutil.ExecutionPayloadAvailabilityRoot(state.executionPayloadAvailability)
if err != nil {
return nil, errors.Wrap(err, "could not compute execution payload availability merkleization")
}
fieldRoots[types.ExecutionPayloadAvailability.RealPosition()] = epaRoot[:]
bppRoot, err := stateutil.BuilderPendingPaymentsRoot(state.builderPendingPayments)
if err != nil {
return nil, errors.Wrap(err, "could not compute builder pending payments merkleization")
}
fieldRoots[types.BuilderPendingPayments.RealPosition()] = bppRoot[:]
bpwRoot, err := stateutil.BuilderPendingWithdrawalsRoot(state.builderPendingWithdrawals)
if err != nil {
return nil, errors.Wrap(err, "could not compute builder pending withdrawals merkleization")
}
fieldRoots[types.BuilderPendingWithdrawals.RealPosition()] = bpwRoot[:]
lbhRoot := bytesutil.ToBytes32(state.latestBlockHash)
fieldRoots[types.LatestBlockHash.RealPosition()] = lbhRoot[:]
lwrRoot := bytesutil.ToBytes32(state.latestWithdrawalsRoot)
fieldRoots[types.LatestWithdrawalsRoot.RealPosition()] = lwrRoot[:]
}
return fieldRoots, nil
}

View File

@@ -79,24 +79,25 @@ var (
bellatrixFields = append(altairFields, types.LatestExecutionPayloadHeader)
capellaFields = append(
altairFields,
types.LatestExecutionPayloadHeaderCapella,
withdrawalAndHistoricalSummaryFields = []types.FieldIndex{
types.NextWithdrawalIndex,
types.NextWithdrawalValidatorIndex,
types.HistoricalSummaries,
)
}
denebFields = append(
capellaFields = slices.Concat(
altairFields,
types.LatestExecutionPayloadHeaderDeneb,
types.NextWithdrawalIndex,
types.NextWithdrawalValidatorIndex,
types.HistoricalSummaries,
[]types.FieldIndex{types.LatestExecutionPayloadHeaderCapella},
withdrawalAndHistoricalSummaryFields,
)
electraFields = append(
denebFields,
denebFields = slices.Concat(
altairFields,
[]types.FieldIndex{types.LatestExecutionPayloadHeaderDeneb},
withdrawalAndHistoricalSummaryFields,
)
electraAdditionalFields = []types.FieldIndex{
types.DepositRequestsStartIndex,
types.DepositBalanceToConsume,
types.ExitBalanceToConsume,
@@ -106,12 +107,34 @@ var (
types.PendingDeposits,
types.PendingPartialWithdrawals,
types.PendingConsolidations,
}
electraFields = slices.Concat(
denebFields,
electraAdditionalFields,
)
fuluFields = append(
electraFields,
types.ProposerLookahead,
)
gloasAdditionalFields = []types.FieldIndex{
types.ExecutionPayloadAvailability,
types.BuilderPendingPayments,
types.BuilderPendingWithdrawals,
types.LatestBlockHash,
types.LatestWithdrawalsRoot,
}
gloasFields = slices.Concat(
altairFields,
[]types.FieldIndex{types.LatestExecutionPayloadBid},
withdrawalAndHistoricalSummaryFields,
electraAdditionalFields,
[]types.FieldIndex{types.ProposerLookahead},
gloasAdditionalFields,
)
)
const (
@@ -122,6 +145,7 @@ const (
denebSharedFieldRefCount = 7
electraSharedFieldRefCount = 10
fuluSharedFieldRefCount = 11
gloasSharedFieldRefCount = 12 // Adds PendingBuilderWithdrawal to the shared-ref set and LatestExecutionPayloadHeader is removed
)
// InitializeFromProtoPhase0 the beacon state from a protobuf representation.
@@ -159,6 +183,11 @@ func InitializeFromProtoFulu(st *ethpb.BeaconStateFulu) (state.BeaconState, erro
return InitializeFromProtoUnsafeFulu(proto.Clone(st).(*ethpb.BeaconStateFulu))
}
// InitializeFromProtoGloas the beacon state from a protobuf representation.
func InitializeFromProtoGloas(st *ethpb.BeaconStateGloas) (state.BeaconState, error) {
return InitializeFromProtoUnsafeGloas(proto.Clone(st).(*ethpb.BeaconStateGloas))
}
// InitializeFromProtoUnsafePhase0 directly uses the beacon state protobuf fields
// and sets them as fields of the BeaconState type.
func InitializeFromProtoUnsafePhase0(st *ethpb.BeaconState) (state.BeaconState, error) {
@@ -736,6 +765,111 @@ func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateFulu) (state.BeaconState
return b, nil
}
// InitializeFromProtoUnsafeGloas directly uses the beacon state protobuf fields
// and sets them as fields of the BeaconState type.
func InitializeFromProtoUnsafeGloas(st *ethpb.BeaconStateGloas) (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)
}
proposerLookahead := make([]primitives.ValidatorIndex, len(st.ProposerLookahead))
for i, v := range st.ProposerLookahead {
proposerLookahead[i] = primitives.ValidatorIndex(v)
}
fieldCount := params.BeaconConfig().BeaconStateGloasFieldCount
b := &BeaconState{
version: version.Gloas,
genesisTime: st.GenesisTime,
genesisValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot),
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
eth1DataVotes: st.Eth1DataVotes,
eth1DepositIndex: st.Eth1DepositIndex,
slashings: st.Slashings,
previousEpochParticipation: st.PreviousEpochParticipation,
currentEpochParticipation: st.CurrentEpochParticipation,
justificationBits: st.JustificationBits,
previousJustifiedCheckpoint: st.PreviousJustifiedCheckpoint,
currentJustifiedCheckpoint: st.CurrentJustifiedCheckpoint,
finalizedCheckpoint: st.FinalizedCheckpoint,
currentSyncCommittee: st.CurrentSyncCommittee,
nextSyncCommittee: st.NextSyncCommittee,
nextWithdrawalIndex: st.NextWithdrawalIndex,
nextWithdrawalValidatorIndex: st.NextWithdrawalValidatorIndex,
historicalSummaries: st.HistoricalSummaries,
depositRequestsStartIndex: st.DepositRequestsStartIndex,
depositBalanceToConsume: st.DepositBalanceToConsume,
exitBalanceToConsume: st.ExitBalanceToConsume,
earliestExitEpoch: st.EarliestExitEpoch,
consolidationBalanceToConsume: st.ConsolidationBalanceToConsume,
earliestConsolidationEpoch: st.EarliestConsolidationEpoch,
pendingDeposits: st.PendingDeposits,
pendingPartialWithdrawals: st.PendingPartialWithdrawals,
pendingConsolidations: st.PendingConsolidations,
proposerLookahead: proposerLookahead,
latestExecutionPayloadBid: st.LatestExecutionPayloadBid,
executionPayloadAvailability: st.ExecutionPayloadAvailability,
builderPendingPayments: st.BuilderPendingPayments,
builderPendingWithdrawals: st.BuilderPendingWithdrawals,
latestBlockHash: st.LatestBlockHash,
latestWithdrawalsRoot: st.LatestWithdrawalsRoot,
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),
}
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, gloasSharedFieldRefCount)
for _, f := range gloasFields {
b.dirtyFields[f] = true
b.rebuildTrie[f] = true
b.dirtyIndices[f] = []uint64{}
trie, err := fieldtrie.NewFieldTrie(f, types.BasicArray, nil, 0)
if err != nil {
return nil, err
}
b.stateFieldLeaves[f] = trie
}
// Initialize field reference tracking for shared data.
b.sharedFieldReferences[types.HistoricalRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Eth1DataVotes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PreviousEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.HistoricalSummaries] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingDeposits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingPartialWithdrawals] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingConsolidations] = stateutil.NewRef(1)
b.sharedFieldReferences[types.ProposerLookahead] = stateutil.NewRef(1)
b.sharedFieldReferences[types.BuilderPendingWithdrawals] = stateutil.NewRef(1) // New in Gloas.
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()
@@ -757,6 +891,8 @@ func (b *BeaconState) Copy() state.BeaconState {
fieldCount = params.BeaconConfig().BeaconStateElectraFieldCount
case version.Fulu:
fieldCount = params.BeaconConfig().BeaconStateFuluFieldCount
case version.Gloas:
fieldCount = params.BeaconConfig().BeaconStateGloasFieldCount
}
dst := &BeaconState{
@@ -811,6 +947,12 @@ func (b *BeaconState) Copy() state.BeaconState {
latestExecutionPayloadHeader: b.latestExecutionPayloadHeader.Copy(),
latestExecutionPayloadHeaderCapella: b.latestExecutionPayloadHeaderCapella.Copy(),
latestExecutionPayloadHeaderDeneb: b.latestExecutionPayloadHeaderDeneb.Copy(),
latestExecutionPayloadBid: b.latestExecutionPayloadBid.Copy(),
executionPayloadAvailability: b.executionPayloadAvailabilityVal(),
builderPendingPayments: b.builderPendingPaymentsVal(),
builderPendingWithdrawals: b.builderPendingWithdrawalsVal(),
latestBlockHash: b.latestBlockHashVal(),
latestWithdrawalsRoot: b.latestWithdrawalsRootVal(),
id: types.Enumerator.Inc(),
@@ -847,6 +989,8 @@ func (b *BeaconState) Copy() state.BeaconState {
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, electraSharedFieldRefCount)
case version.Fulu:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, fuluSharedFieldRefCount)
case version.Gloas:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, gloasSharedFieldRefCount)
}
for field, ref := range b.sharedFieldReferences {
@@ -942,6 +1086,8 @@ func (b *BeaconState) initializeMerkleLayers(ctx context.Context) error {
b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateElectraFieldCount)
case version.Fulu:
b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateFuluFieldCount)
case version.Gloas:
b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateGloasFieldCount)
default:
return fmt.Errorf("unknown state version (%s) when computing dirty fields in merklization", version.String(b.version))
}
@@ -1180,6 +1326,19 @@ func (b *BeaconState) rootSelector(ctx context.Context, field types.FieldIndex)
return stateutil.PendingConsolidationsRoot(b.pendingConsolidations)
case types.ProposerLookahead:
return stateutil.ProposerLookaheadRoot(b.proposerLookahead)
case types.LatestExecutionPayloadBid:
return b.latestExecutionPayloadBid.HashTreeRoot()
case types.ExecutionPayloadAvailability:
return stateutil.ExecutionPayloadAvailabilityRoot(b.executionPayloadAvailability)
case types.BuilderPendingPayments:
return stateutil.BuilderPendingPaymentsRoot(b.builderPendingPayments)
case types.BuilderPendingWithdrawals:
return stateutil.BuilderPendingWithdrawalsRoot(b.builderPendingWithdrawals)
case types.LatestBlockHash:
return bytesutil.ToBytes32(b.latestBlockHash), nil
case types.LatestWithdrawalsRoot:
return bytesutil.ToBytes32(b.latestWithdrawalsRoot), nil
}
return [32]byte{}, errors.New("invalid field index provided")
}

View File

@@ -88,6 +88,8 @@ func (f FieldIndex) String() string {
return "latestExecutionPayloadHeaderCapella"
case LatestExecutionPayloadHeaderDeneb:
return "latestExecutionPayloadHeaderDeneb"
case LatestExecutionPayloadBid:
return "latestExecutionPayloadBid"
case NextWithdrawalIndex:
return "nextWithdrawalIndex"
case NextWithdrawalValidatorIndex:
@@ -114,6 +116,16 @@ func (f FieldIndex) String() string {
return "pendingConsolidations"
case ProposerLookahead:
return "proposerLookahead"
case ExecutionPayloadAvailability:
return "executionPayloadAvailability"
case BuilderPendingPayments:
return "builderPendingPayments"
case BuilderPendingWithdrawals:
return "builderPendingWithdrawals"
case LatestBlockHash:
return "latestBlockHash"
case LatestWithdrawalsRoot:
return "latestWithdrawalsRoot"
default:
return fmt.Sprintf("unknown field index number: %d", f)
}
@@ -171,7 +183,7 @@ func (f FieldIndex) RealPosition() int {
return 22
case NextSyncCommittee:
return 23
case LatestExecutionPayloadHeader, LatestExecutionPayloadHeaderCapella, LatestExecutionPayloadHeaderDeneb:
case LatestExecutionPayloadHeader, LatestExecutionPayloadHeaderCapella, LatestExecutionPayloadHeaderDeneb, LatestExecutionPayloadBid:
return 24
case NextWithdrawalIndex:
return 25
@@ -199,6 +211,16 @@ func (f FieldIndex) RealPosition() int {
return 36
case ProposerLookahead:
return 37
case ExecutionPayloadAvailability:
return 38
case BuilderPendingPayments:
return 39
case BuilderPendingWithdrawals:
return 40
case LatestBlockHash:
return 41
case LatestWithdrawalsRoot:
return 42
default:
return -1
}
@@ -251,6 +273,7 @@ const (
LatestExecutionPayloadHeader
LatestExecutionPayloadHeaderCapella
LatestExecutionPayloadHeaderDeneb
LatestExecutionPayloadBid // Gloas: EIP-7732
NextWithdrawalIndex
NextWithdrawalValidatorIndex
HistoricalSummaries
@@ -264,6 +287,11 @@ const (
PendingPartialWithdrawals // Electra: EIP-7251
PendingConsolidations // Electra: EIP-7251
ProposerLookahead // Fulu: EIP-7917
ExecutionPayloadAvailability // Gloas: EIP-7732
BuilderPendingPayments // Gloas: EIP-7732
BuilderPendingWithdrawals // Gloas: EIP-7732
LatestBlockHash // Gloas: EIP-7732
LatestWithdrawalsRoot // Gloas: EIP-7732
)
// Enumerator keeps track of the number of states created since the node's start.

View File

@@ -4,7 +4,10 @@ go_library(
name = "go_default_library",
srcs = [
"block_header_root.go",
"builder_pending_payments_root.go",
"builder_pending_withdrawals_root.go",
"eth1_root.go",
"execution_payload_availability_root.go",
"field_root_attestation.go",
"field_root_eth1.go",
"field_root_validator.go",

View File

@@ -0,0 +1,22 @@
package stateutil
import (
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
)
// BuilderPendingPaymentsRoot computes the merkle root of a slice of BuilderPendingPayment.
func BuilderPendingPaymentsRoot(slice []*ethpb.BuilderPendingPayment) ([32]byte, error) {
roots := make([][32]byte, len(slice))
for i, payment := range slice {
r, err := payment.HashTreeRoot()
if err != nil {
return [32]byte{}, err
}
roots[i] = r
}
return ssz.MerkleizeVector(roots, uint64(len(roots))), nil
}

View File

@@ -0,0 +1,12 @@
package stateutil
import (
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
)
// BuilderPendingWithdrawalsRoot computes the SSZ root of a slice of BuilderPendingWithdrawal.
func BuilderPendingWithdrawalsRoot(slice []*ethpb.BuilderPendingWithdrawal) ([32]byte, error) {
return ssz.SliceRoot(slice, fieldparams.BuilderPendingWithdrawalsLimit)
}

View File

@@ -0,0 +1,25 @@
package stateutil
import (
"fmt"
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
)
// ExecutionPayloadAvailabilityRoot computes the merkle root of an execution payload availability bitvector.
func ExecutionPayloadAvailabilityRoot(bitvector []byte) ([32]byte, error) {
chunkCount := (len(bitvector) + 31) / 32
chunks := make([][32]byte, chunkCount)
for i := range chunks {
start := i * 32
end := min(start+32, len(bitvector))
copy(chunks[i][:], bitvector[start:end])
}
root, err := ssz.BitwiseMerkleize(chunks, uint64(len(chunks)), uint64(len(chunks)))
if err != nil {
return [32]byte{}, fmt.Errorf("could not merkleize execution payload availability: %w", err)
}
return root, nil
}