erigon-pulse/cmd/erigon-cl/core/state/root.go
2023-03-09 17:34:49 +00:00

293 lines
8.3 KiB
Go

package state
import (
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/merkle_tree"
"github.com/ledgerwatch/erigon/cl/utils"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state/state_encoding"
)
func (b *BeaconState) HashSSZ() ([32]byte, error) {
var err error
if err = b.computeDirtyLeaves(); err != nil {
return [32]byte{}, err
}
// Pad to 32 of length
return merkle_tree.MerkleRootFromLeaves(b.leaves[:])
}
func (b *BeaconState) SetPreviousStateRoot(root libcommon.Hash) {
b.previousStateRoot = root
}
func (b *BeaconState) computeDirtyLeaves() error {
// Update all dirty leafs
// ----
// Field(0): GenesisTime
if b.isLeafDirty(GenesisTimeLeafIndex) {
b.updateLeaf(GenesisTimeLeafIndex, merkle_tree.Uint64Root(b.genesisTime))
}
// Field(1): GenesisValidatorsRoot
if b.isLeafDirty(GenesisValidatorsRootLeafIndex) {
b.updateLeaf(GenesisValidatorsRootLeafIndex, b.genesisValidatorsRoot)
}
// Field(2): Slot
if b.isLeafDirty(SlotLeafIndex) {
b.updateLeaf(SlotLeafIndex, merkle_tree.Uint64Root(b.slot))
}
// Field(3): Fork
if b.isLeafDirty(ForkLeafIndex) {
forkRoot, err := b.fork.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(ForkLeafIndex, forkRoot)
}
// Field(4): LatestBlockHeader
if b.isLeafDirty(LatestBlockHeaderLeafIndex) {
headerRoot, err := b.latestBlockHeader.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(LatestBlockHeaderLeafIndex, headerRoot)
}
// Field(5): BlockRoots
if b.isLeafDirty(BlockRootsLeafIndex) {
root, err := merkle_tree.ArraysRoot(utils.PreparateRootsForHashing(b.blockRoots[:]), state_encoding.BlockRootsLength)
if err != nil {
return err
}
b.updateLeaf(BlockRootsLeafIndex, root)
}
// Field(6): StateRoots
if b.isLeafDirty(StateRootsLeafIndex) {
root, err := merkle_tree.ArraysRoot(utils.PreparateRootsForHashing(b.stateRoots[:]), state_encoding.StateRootsLength)
if err != nil {
return err
}
b.updateLeaf(StateRootsLeafIndex, root)
}
// Field(7): HistoricalRoots
if b.isLeafDirty(HistoricalRootsLeafIndex) {
root, err := merkle_tree.ArraysRootWithLimit(utils.PreparateRootsForHashing(b.historicalRoots), state_encoding.HistoricalRootsLength)
if err != nil {
return err
}
b.updateLeaf(HistoricalRootsLeafIndex, root)
}
// Field(8): Eth1Data
if b.isLeafDirty(Eth1DataLeafIndex) {
dataRoot, err := b.eth1Data.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(Eth1DataLeafIndex, dataRoot)
}
// Field(9): Eth1DataVotes
if b.isLeafDirty(Eth1DataVotesLeafIndex) {
root, err := merkle_tree.ListObjectSSZRoot(b.eth1DataVotes, maxEth1Votes)
if err != nil {
return err
}
b.updateLeaf(Eth1DataVotesLeafIndex, root)
}
// Field(10): Eth1DepositIndex
if b.isLeafDirty(Eth1DepositIndexLeafIndex) {
b.updateLeaf(Eth1DepositIndexLeafIndex, merkle_tree.Uint64Root(b.eth1DepositIndex))
}
// Field(11): Validators
if b.isLeafDirty(ValidatorsLeafIndex) {
root, err := merkle_tree.ListObjectSSZRoot(b.validators, state_encoding.ValidatorRegistryLimit)
if err != nil {
return err
}
b.updateLeaf(ValidatorsLeafIndex, root)
}
// Field(12): Balances
if b.isLeafDirty(BalancesLeafIndex) {
root, err := merkle_tree.Uint64ListRootWithLimit(b.balances, state_encoding.ValidatorLimitForBalancesChunks())
if err != nil {
return err
}
b.updateLeaf(BalancesLeafIndex, root)
}
// Field(13): RandaoMixes
if b.isLeafDirty(RandaoMixesLeafIndex) {
root, err := merkle_tree.ArraysRoot(preparateRootsForHashing(b.randaoMixes[:]), state_encoding.RandaoMixesLength)
if err != nil {
return err
}
b.updateLeaf(RandaoMixesLeafIndex, root)
}
// Field(14): Slashings
if b.isLeafDirty(SlashingsLeafIndex) {
root, err := state_encoding.SlashingsRoot(b.slashings[:])
if err != nil {
return err
}
b.updateLeaf(SlashingsLeafIndex, root)
}
// Field(15) and Field(16) are special due to the fact that they have different format in Phase0.
// Field(15): PreviousEpochParticipation
if b.isLeafDirty(PreviousEpochParticipationLeafIndex) {
var root libcommon.Hash
var err error
if b.version == clparams.Phase0Version {
root, err = merkle_tree.ListObjectSSZRoot(b.previousEpochAttestations, b.beaconConfig.SlotsPerEpoch*b.beaconConfig.MaxAttestations)
} else {
root, err = merkle_tree.BitlistRootWithLimitForState(b.previousEpochParticipation.Bytes(), state_encoding.ValidatorRegistryLimit)
}
if err != nil {
return err
}
b.updateLeaf(PreviousEpochParticipationLeafIndex, root)
}
// Field(16): CurrentEpochParticipation
if b.isLeafDirty(CurrentEpochParticipationLeafIndex) {
var root libcommon.Hash
var err error
if b.version == clparams.Phase0Version {
root, err = merkle_tree.ListObjectSSZRoot(b.currentEpochAttestations, b.beaconConfig.SlotsPerEpoch*b.beaconConfig.MaxAttestations)
} else {
root, err = merkle_tree.BitlistRootWithLimitForState(b.currentEpochParticipation.Bytes(), state_encoding.ValidatorRegistryLimit)
}
if err != nil {
return err
}
b.updateLeaf(CurrentEpochParticipationLeafIndex, root)
}
// Field(17): JustificationBits
if b.isLeafDirty(JustificationBitsLeafIndex) {
var root [32]byte
root[0] = b.justificationBits.Byte()
b.updateLeaf(JustificationBitsLeafIndex, root)
}
// Field(18): PreviousJustifiedCheckpoint
if b.isLeafDirty(PreviousJustifiedCheckpointLeafIndex) {
checkpointRoot, err := b.previousJustifiedCheckpoint.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(PreviousJustifiedCheckpointLeafIndex, checkpointRoot)
}
// Field(19): CurrentJustifiedCheckpoint
if b.isLeafDirty(CurrentJustifiedCheckpointLeafIndex) {
checkpointRoot, err := b.currentJustifiedCheckpoint.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(CurrentJustifiedCheckpointLeafIndex, checkpointRoot)
}
// Field(20): FinalizedCheckpoint
if b.isLeafDirty(FinalizedCheckpointLeafIndex) {
checkpointRoot, err := b.finalizedCheckpoint.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(FinalizedCheckpointLeafIndex, checkpointRoot)
}
if b.version == clparams.Phase0Version {
return nil
}
// Field(21): Inactivity Scores
if b.isLeafDirty(InactivityScoresLeafIndex) {
root, err := merkle_tree.Uint64ListRootWithLimit(b.inactivityScores, state_encoding.ValidatorLimitForBalancesChunks())
if err != nil {
return err
}
b.updateLeaf(InactivityScoresLeafIndex, root)
}
// Field(22): CurrentSyncCommitte
if b.isLeafDirty(CurrentSyncCommitteeLeafIndex) {
committeeRoot, err := b.currentSyncCommittee.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(CurrentSyncCommitteeLeafIndex, committeeRoot)
}
// Field(23): NextSyncCommitte
if b.isLeafDirty(NextSyncCommitteeLeafIndex) {
committeeRoot, err := b.nextSyncCommittee.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(NextSyncCommitteeLeafIndex, committeeRoot)
}
if b.version < clparams.BellatrixVersion {
return nil
}
// Field(24): LatestExecutionPayloadHeader
if b.isLeafDirty(LatestExecutionPayloadHeaderLeafIndex) {
headerRoot, err := b.latestExecutionPayloadHeader.HashSSZ()
if err != nil {
return err
}
b.updateLeaf(LatestExecutionPayloadHeaderLeafIndex, headerRoot)
}
if b.version < clparams.CapellaVersion {
return nil
}
// Field(25): NextWithdrawalIndex
if b.isLeafDirty(NextWithdrawalIndexLeafIndex) {
b.updateLeaf(NextWithdrawalIndexLeafIndex, merkle_tree.Uint64Root(b.nextWithdrawalIndex))
}
// Field(26): NextWithdrawalValidatorIndex
if b.isLeafDirty(NextWithdrawalValidatorIndexLeafIndex) {
b.updateLeaf(NextWithdrawalValidatorIndexLeafIndex, merkle_tree.Uint64Root(b.nextWithdrawalValidatorIndex))
}
// Field(27): HistoricalSummaries
if b.isLeafDirty(HistoricalSummariesLeafIndex) {
root, err := merkle_tree.ListObjectSSZRoot(b.historicalSummaries, state_encoding.HistoricalRootsLength)
if err != nil {
return err
}
b.updateLeaf(HistoricalSummariesLeafIndex, root)
}
return nil
}
func (b *BeaconState) updateLeaf(idx StateLeafIndex, leaf libcommon.Hash) {
// Update leaf with new value.
b.leaves[idx] = leaf
// Now leaf is clean :).
b.touchedLeaves[idx] = false
}
func (b *BeaconState) isLeafDirty(idx StateLeafIndex) bool {
// If leaf is non-initialized or if it was touched then we change it.
touched, isInitialized := b.touchedLeaves[idx]
return !isInitialized || touched // change only if the leaf was touched or root is non-initialized.
}