Files
prysm/beacon-chain/state/interfaces.go
Manu NALEPA 2620d0af66 Field Trie: Implement copy on write and base/overlay scheme. (#16512)
**What type of PR is this?**
Optimization (initial idea @nisdas)

> [!NOTE] 
> On a **Hoodi supernode**, this PR saves **~200MB-350MB** of heap
usage, representing a **~6.5%-9.5%** saving.
> <img width="943" height="924" alt="image"
src="https://github.com/user-attachments/assets/175cfa8e-384b-4adf-8114-07f1208c02b2"
/>

**What does this PR do? Why is it needed?**
This PR introduces 3 main features on field tries: Copy on write,
base/overlay scheme, and internal reference responsibilities.

### Copy on write
Before this PR, if a trie was copied (`CopyTrie`) but then not modified,
then the copy was wasteful, because only a reference to the original
trie would have been enough.
With this PR, `CopyTrie` does not actually copy the trie, it only
increments a reference count. If the trie needs to be later modified, a
(lightweight) copy is done only at the time of modification.

### Base/overlay scheme
With this PR, at the time a copied trie is modified, a link to the
original trie is made, and only the diff between the original trie and
the copied, modified trie is stored in the modified trie. (If the diff
is too big, then the copied, modified trie is "promoted" into fully
"owned" node.)

### Internal reference responsibilities
Before this PR, the caller had to manually manage the references count
of the tries. An oversight in this management and a whole trie would
create a leak in the heap memory.
With this PR, the caller doesn't have any more to manage references
count. It is internally handled in the field trie package. (The
reference count is incremented when a new trie is created, decremented
when the trie is garbage collected.)

**How to review this PR**
This PR has 3 independants commits.
The reviewer should review the first and second commits separatedly.
The third commit basically rewrites the whole field trie package. So
reading diff of the field trie package would be quite inefficient.

So, once the first and second commits are reviewed, the best is to:
1. Read the `doc.md` file in the fieldtrie package. This is a design
document
2. Read the final state of the fieldtrie package itself
3. Read the diffs introduced in third commit, without the fieldtrie
package.

**Acknowledgements**

- [x] I have read
[CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md).
- [x] I have included a uniquely named [changelog fragment
file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd).
- [x] I have added a description with sufficient context for reviewers
to understand this PR.
- [x] I have tested that my changes work as expected and I added a
testing plan to the PR description (if applicable).

---------

Co-authored-by: Bastin <43618253+Inspector-Butters@users.noreply.github.com>
2026-04-20 09:33:39 +00:00

367 lines
14 KiB
Go

// Package state defines the actual beacon state interface used
// by a Prysm beacon node, also containing useful, scoped interfaces such as
// a ReadOnlyState and WriteOnlyBeaconState.
package state
import (
"context"
"encoding/json"
"time"
"github.com/OffchainLabs/go-bitfield"
customtypes "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
)
// BeaconState has read and write access to beacon state methods.
type BeaconState interface {
SpecParametersProvider
ReadOnlyBeaconState
WriteOnlyBeaconState
Defragment()
HashTreeRoot(ctx context.Context) ([32]byte, error)
Prover
json.Marshaler
}
// SpecParametersProvider provides fork-specific configuration parameters as
// defined in the consensus specification for the beacon chain.
type SpecParametersProvider interface {
InactivityPenaltyQuotient() (uint64, error)
ProportionalSlashingMultiplier() (uint64, error)
}
// StateProver defines the ability to create Merkle proofs for beacon state fields.
type Prover interface {
FinalizedRootProof(ctx context.Context) ([][]byte, error)
CurrentSyncCommitteeProof(ctx context.Context) ([][]byte, error)
NextSyncCommitteeProof(ctx context.Context) ([][]byte, error)
ProofByFieldIndex(ctx context.Context, f types.FieldIndex) ([][]byte, error)
}
// ReadOnlyBeaconState defines a struct which only has read access to beacon state methods.
type ReadOnlyBeaconState interface {
ReadOnlyBlockRoots
ReadOnlyStateRoots
ReadOnlyRandaoMixes
ReadOnlyEth1Data
ReadOnlyExits
ReadOnlyValidators
ReadOnlyBalances
ReadOnlyCheckpoint
ReadOnlyAttestations
ReadOnlyWithdrawals
ReadOnlyParticipation
ReadOnlyInactivity
ReadOnlySyncCommittee
ReadOnlyDeposits
ReadOnlyConsolidations
ReadOnlyProposerLookahead
readOnlyGloasFields
ToProtoUnsafe() any
ToProto() any
Copy() BeaconState
GenesisTime() time.Time
GenesisValidatorsRoot() []byte
Slot() primitives.Slot
Fork() *ethpb.Fork
LatestBlockHeader() *ethpb.BeaconBlockHeader
HistoricalRoots() [][]byte
HistoricalSummaries() ([]*ethpb.HistoricalSummary, error)
Slashings() []uint64
FieldReferencesCount() map[string]uint64
RecordStateMetrics()
MarshalSSZ() ([]byte, error)
IsNil() bool
Version() int
LatestExecutionPayloadHeader() (interfaces.ExecutionData, error)
}
// WriteOnlyBeaconState defines a struct which only has write access to beacon state methods.
type WriteOnlyBeaconState interface {
WriteOnlyBlockRoots
WriteOnlyStateRoots
WriteOnlyRandaoMixes
WriteOnlyEth1Data
WriteOnlyValidators
WriteOnlyBalances
WriteOnlyCheckpoint
WriteOnlyAttestations
WriteOnlyParticipation
WriteOnlyInactivity
WriteOnlySyncCommittee
WriteOnlyConsolidations
WriteOnlyWithdrawals
WriteOnlyDeposits
WriteOnlyProposerLookahead
writeOnlyGloasFields
SetGenesisTime(val time.Time) error
SetGenesisValidatorsRoot(val []byte) error
SetSlot(val primitives.Slot) error
SetFork(val *ethpb.Fork) error
SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error
SetHistoricalRoots(val [][]byte) error
SetSlashings(val []uint64) error
UpdateSlashingsAtIndex(idx, val uint64) error
AppendHistoricalRoots(root [32]byte) error
AppendHistoricalSummaries(*ethpb.HistoricalSummary) error
SetLatestExecutionPayloadHeader(payload interfaces.ExecutionData) error
}
// ReadOnlyValidator defines a struct which only has read access to validator methods.
type ReadOnlyValidator interface {
EffectiveBalance() uint64
ActivationEligibilityEpoch() primitives.Epoch
ActivationEpoch() primitives.Epoch
WithdrawableEpoch() primitives.Epoch
ExitEpoch() primitives.Epoch
PublicKey() [fieldparams.BLSPubkeyLength]byte
GetWithdrawalCredentials() []byte
Copy() *ethpb.Validator
Slashed() bool
HasETH1WithdrawalCredentials() bool
HasCompoundingWithdrawalCredentials() bool
HasExecutionWithdrawalCredentials() bool
}
// ReadOnlyValidators defines a struct which only has read access to validators methods.
type ReadOnlyValidators interface {
Validators() []*ethpb.Validator
ValidatorsReadOnly() []ReadOnlyValidator
ValidatorAtIndex(idx primitives.ValidatorIndex) (*ethpb.Validator, error)
ValidatorAtIndexReadOnly(idx primitives.ValidatorIndex) (ReadOnlyValidator, error)
ValidatorIndexByPubkey(key [fieldparams.BLSPubkeyLength]byte) (primitives.ValidatorIndex, bool)
PublicKeys() ([][fieldparams.BLSPubkeyLength]byte, error)
PubkeyAtIndex(idx primitives.ValidatorIndex) [fieldparams.BLSPubkeyLength]byte
AggregateKeyFromIndices(idxs []uint64) (bls.PublicKey, error)
NumValidators() int
ReadFromEveryValidator(f func(idx int, val ReadOnlyValidator) error) error
}
// ReadOnlyBalances defines a struct which only has read access to balances methods.
type ReadOnlyBalances interface {
Balances() []uint64
BalanceAtIndex(idx primitives.ValidatorIndex) (uint64, error)
BalancesLength() int
EffectiveBalanceSum([]primitives.ValidatorIndex) (uint64, error)
}
// ReadOnlyCheckpoint defines a struct which only has read access to checkpoint methods.
type ReadOnlyCheckpoint interface {
PreviousJustifiedCheckpoint() *ethpb.Checkpoint
CurrentJustifiedCheckpoint() *ethpb.Checkpoint
MatchCurrentJustifiedCheckpoint(c *ethpb.Checkpoint) bool
MatchPreviousJustifiedCheckpoint(c *ethpb.Checkpoint) bool
FinalizedCheckpoint() *ethpb.Checkpoint
FinalizedCheckpointEpoch() primitives.Epoch
JustificationBits() bitfield.Bitvector4
UnrealizedCheckpointBalances() (uint64, uint64, uint64, error)
}
// ReadOnlyBlockRoots defines a struct which only has read access to block roots methods.
type ReadOnlyBlockRoots interface {
BlockRoots() [][]byte
BlockRootAtIndex(idx uint64) ([]byte, error)
}
// ReadOnlyStateRoots defines a struct which only has read access to state roots methods.
type ReadOnlyStateRoots interface {
StateRoots() [][]byte
StateRootAtIndex(idx uint64) ([]byte, error)
}
// ReadOnlyRandaoMixes defines a struct which only has read access to randao mixes methods.
type ReadOnlyRandaoMixes interface {
RandaoMixes() [][]byte
RandaoMixAtIndex(idx uint64) ([]byte, error)
RandaoMixesLength() int
}
// ReadOnlyEth1Data defines a struct which only has read access to eth1 data methods.
type ReadOnlyEth1Data interface {
Eth1Data() *ethpb.Eth1Data
Eth1DataVotes() []*ethpb.Eth1Data
Eth1DepositIndex() uint64
}
// ReadOnlyExits defines a struct which only has read access to Exit related methods.
type ReadOnlyExits interface {
ExitBalanceToConsume() (primitives.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)
CurrentEpochAttestations() ([]*ethpb.PendingAttestation, error)
}
// ReadOnlyWithdrawals defines a struct which only has read access to withdrawal methods.
type ReadOnlyWithdrawals interface {
ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, error)
NextWithdrawalValidatorIndex() (primitives.ValidatorIndex, error)
NextWithdrawalIndex() (uint64, error)
PendingBalanceToWithdraw(idx primitives.ValidatorIndex) (uint64, error)
PendingPartialWithdrawals() ([]*ethpb.PendingPartialWithdrawal, error)
NumPendingPartialWithdrawals() (uint64, error)
HasPendingBalanceToWithdraw(idx primitives.ValidatorIndex) (bool, error)
}
// ReadOnlyParticipation defines a struct which only has read access to participation methods.
type ReadOnlyParticipation interface {
CurrentEpochParticipation() ([]byte, error)
PreviousEpochParticipation() ([]byte, error)
CurrentEpochParticipationReadOnly() (customtypes.ReadOnlyParticipation, error)
PreviousEpochParticipationReadOnly() (customtypes.ReadOnlyParticipation, error)
}
// ReadOnlyInactivity defines a struct which only has read access to inactivity methods.
type ReadOnlyInactivity interface {
InactivityScores() ([]uint64, error)
}
// ReadOnlySyncCommittee defines a struct which only has read access to sync committee methods.
type ReadOnlySyncCommittee interface {
CurrentSyncCommittee() (*ethpb.SyncCommittee, error)
NextSyncCommittee() (*ethpb.SyncCommittee, error)
}
type ReadOnlyDeposits interface {
DepositBalanceToConsume() (primitives.Gwei, error)
DepositRequestsStartIndex() (uint64, error)
PendingDeposits() ([]*ethpb.PendingDeposit, error)
IsPendingValidator(pubkey []byte) (bool, error)
}
type ReadOnlyConsolidations interface {
ConsolidationBalanceToConsume() (primitives.Gwei, error)
EarliestConsolidationEpoch() (primitives.Epoch, error)
PendingConsolidations() ([]*ethpb.PendingConsolidation, error)
NumPendingConsolidations() (uint64, error)
}
type ReadOnlyProposerLookahead interface {
ProposerLookahead() ([]primitives.ValidatorIndex, error)
}
// WriteOnlyBlockRoots defines a struct which only has write access to block roots methods.
type WriteOnlyBlockRoots interface {
SetBlockRoots(val [][]byte) error
UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error
}
// WriteOnlyStateRoots defines a struct which only has write access to state roots methods.
type WriteOnlyStateRoots interface {
SetStateRoots(val [][]byte) error
UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) error
}
// WriteOnlyEth1Data defines a struct which only has write access to eth1 data methods.
type WriteOnlyEth1Data interface {
SetEth1Data(val *ethpb.Eth1Data) error
SetEth1DataVotes(val []*ethpb.Eth1Data) error
AppendEth1DataVotes(val *ethpb.Eth1Data) error
SetEth1DepositIndex(val uint64) error
ExitEpochAndUpdateChurn(exitBalance primitives.Gwei) (primitives.Epoch, error)
ExitEpochAndUpdateChurnForTotalBal(totalActiveBalance primitives.Gwei, exitBalance primitives.Gwei) (primitives.Epoch, error)
SetExitBalanceToConsume(val primitives.Gwei) error
SetEarliestExitEpoch(val primitives.Epoch) error
}
// WriteOnlyValidators defines a struct which only has write access to validators methods.
type WriteOnlyValidators interface {
SetValidators(val []*ethpb.Validator) error
ApplyToEveryValidator(f func(idx int, val ReadOnlyValidator) (*ethpb.Validator, error)) error
UpdateValidatorAtIndex(idx primitives.ValidatorIndex, val *ethpb.Validator) error
AppendValidator(val *ethpb.Validator) error
}
// WriteOnlyBalances defines a struct which only has write access to balances methods.
type WriteOnlyBalances interface {
SetBalances(val []uint64) error
UpdateBalancesAtIndex(idx primitives.ValidatorIndex, val uint64) error
AppendBalance(bal uint64) error
}
// WriteOnlyRandaoMixes defines a struct which only has write access to randao mixes methods.
type WriteOnlyRandaoMixes interface {
SetRandaoMixes(val [][]byte) error
UpdateRandaoMixesAtIndex(idx uint64, val [32]byte) error
}
// WriteOnlyCheckpoint defines a struct which only has write access to check point methods.
type WriteOnlyCheckpoint interface {
SetFinalizedCheckpoint(val *ethpb.Checkpoint) error
SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) error
SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error
SetJustificationBits(val bitfield.Bitvector4) error
}
// WriteOnlyAttestations defines a struct which only has write access to attestations methods.
type WriteOnlyAttestations interface {
AppendCurrentEpochAttestations(val *ethpb.PendingAttestation) error
AppendPreviousEpochAttestations(val *ethpb.PendingAttestation) error
SetPreviousEpochAttestations([]*ethpb.PendingAttestation) error
SetCurrentEpochAttestations([]*ethpb.PendingAttestation) error
RotateAttestations() error
}
// WriteOnlyParticipation defines a struct which only has write access to participation methods.
type WriteOnlyParticipation interface {
AppendCurrentParticipationBits(val byte) error
AppendPreviousParticipationBits(val byte) error
SetPreviousParticipationBits(val []byte) error
SetCurrentParticipationBits(val []byte) error
ModifyCurrentParticipationBits(func(val []byte) ([]byte, error)) error
ModifyPreviousParticipationBits(func(val []byte) ([]byte, error)) error
}
// WriteOnlyInactivity defines a struct which only has write access to inactivity methods.
type WriteOnlyInactivity interface {
AppendInactivityScore(s uint64) error
SetInactivityScores(val []uint64) error
}
// WriteOnlySyncCommittee defines a struct which only has write access to sync committee methods.
type WriteOnlySyncCommittee interface {
SetCurrentSyncCommittee(val *ethpb.SyncCommittee) error
SetNextSyncCommittee(val *ethpb.SyncCommittee) error
}
type WriteOnlyWithdrawals interface {
AppendPendingPartialWithdrawal(ppw *ethpb.PendingPartialWithdrawal) error
DequeuePendingPartialWithdrawals(num uint64) error
SetNextWithdrawalIndex(i uint64) error
SetNextWithdrawalValidatorIndex(i primitives.ValidatorIndex) error
SetPendingPartialWithdrawals(val []*ethpb.PendingPartialWithdrawal) error
}
type WriteOnlyConsolidations interface {
AppendPendingConsolidation(val *ethpb.PendingConsolidation) error
SetConsolidationBalanceToConsume(primitives.Gwei) error
SetEarliestConsolidationEpoch(epoch primitives.Epoch) error
SetPendingConsolidations(val []*ethpb.PendingConsolidation) error
}
type WriteOnlyDeposits interface {
AppendPendingDeposit(pd *ethpb.PendingDeposit) error
SetDepositRequestsStartIndex(index uint64) error
SetPendingDeposits(val []*ethpb.PendingDeposit) error
SetDepositBalanceToConsume(primitives.Gwei) error
}
type WriteOnlyProposerLookahead interface {
SetProposerLookahead([]primitives.ValidatorIndex) error
}
func IsNil(s BeaconState) bool {
return s == nil || s.IsNil()
}