Added reverse beacon changeset for beacon state rewind (#7185)

Added changesets for beacon chain to implement memory efficient fork
choice
This commit is contained in:
Giulio rebuffo 2023-03-27 00:25:08 +02:00 committed by GitHub
parent e38605b8b2
commit 628f52dd6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1035 additions and 203 deletions

View File

@ -531,7 +531,6 @@ func (a *PendingAttestation) EncodeSSZ(buf []byte) (dst []byte, err error) {
if dst, err = a.Data.EncodeSSZ(dst); err != nil {
return
}
fmt.Println(dst)
dst = append(dst, ssz.Uint64SSZ(a.InclusionDelay)...)
dst = append(dst, ssz.Uint64SSZ(a.ProposerIndex)...)

View File

@ -33,3 +33,7 @@ func (j JustificationBits) CheckRange(start int, end int) bool {
}
return true
}
func (j JustificationBits) Copy() JustificationBits {
return JustificationBits{j[0], j[1], j[2], j[3]}
}

View File

@ -25,6 +25,12 @@ func (p ParticipationFlagsList) Bytes() []byte {
return b
}
func (p ParticipationFlagsList) Copy() ParticipationFlagsList {
c := make(ParticipationFlagsList, len(p))
copy(c, p)
return c
}
func ParticipationFlagsListFromBytes(buf []byte) ParticipationFlagsList {
flagsList := make([]ParticipationFlags, len(buf))
for i := range flagsList {

View File

@ -20,6 +20,7 @@ func forkTest(context testContext) error {
return err
}
preState.StartCollectingReverseChangeSet()
if preState.Version() == clparams.Phase0Version {
if err := preState.UpgradeToAltair(); err != nil {
return err
@ -33,6 +34,8 @@ func forkTest(context testContext) error {
return err
}
}
change := preState.StopCollectingReverseChangeSet()
if expectedError {
return fmt.Errorf("expected error")
}
@ -47,5 +50,25 @@ func forkTest(context testContext) error {
if root != expectedRoot {
return fmt.Errorf("mismatching state roots")
}
if context.version == clparams.AltairVersion {
return nil
}
// now do unwind
initialState, err := decodeStateFromFile(prevContext, "pre.ssz_snappy")
if err != nil {
return err
}
preState.RevertWithChangeset(change)
root, err = preState.HashSSZ()
if err != nil {
return err
}
expectedRoot, err = initialState.HashSSZ()
if err != nil {
return err
}
if root != expectedRoot {
return fmt.Errorf("mismatching state roots with unwind")
}
return nil
}

View File

@ -4,7 +4,9 @@ import (
"fmt"
"os"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/beacon_changeset"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/transition"
)
@ -28,12 +30,16 @@ func testSanityFunction(context testContext) error {
return err
}
startSlot := testState.Slot()
changes := []*beacon_changeset.ReverseBeaconStateChangeSet{}
var block *cltypes.SignedBeaconBlock
for _, block = range blocks {
testState.StartCollectingReverseChangeSet()
err = transition.TransitionState(testState, block, true)
if err != nil {
break
}
changes = append(changes, testState.StopCollectingReverseChangeSet())
}
// Deal with transition error
if expectedError && err == nil {
@ -45,7 +51,7 @@ func testSanityFunction(context testContext) error {
}
return fmt.Errorf("cannot transition state: %s. slot=%d. start_slot=%d", err, block.Block.Slot, startSlot)
}
expectedRoot, err := expectedState.HashSSZ()
finalRoot, err := expectedState.HashSSZ()
if err != nil {
return err
}
@ -53,9 +59,47 @@ func testSanityFunction(context testContext) error {
if err != nil {
return err
}
if haveRoot != expectedRoot {
if haveRoot != finalRoot {
return fmt.Errorf("mismatching state roots")
}
if context.version == clparams.Phase0Version {
return nil
}
// Now do the unwind
initialState, err := decodeStateFromFile(context, "pre.ssz_snappy")
if err != nil {
return err
}
_ = initialState
for i := len(changes) - 1; i >= 0; i-- {
testState.RevertWithChangeset(changes[i])
}
expectedRoot, err := initialState.HashSSZ()
if err != nil {
return err
}
haveRoot, err = testState.HashSSZ()
if err != nil {
return err
}
if haveRoot != expectedRoot {
return fmt.Errorf("mismatching state roots with unwind")
}
// Execute them back (ensure cache is good.)
for _, block = range blocks {
testState.StartCollectingReverseChangeSet()
err = transition.TransitionState(testState, block, true)
if err != nil {
break
}
changes = append(changes, testState.StopCollectingReverseChangeSet())
}
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,146 @@
package beacon_changeset
import (
"sort"
)
type ListChangeSet[T any] struct {
list []*listElementChangeset[T]
listLength int
nextId int
compact bool
}
type listElementChangeset[T any] struct {
value T
listIndex int
id int
}
// NewListChangeSet creates new list with given length.
func NewListChangeSet[T any](length int) *ListChangeSet[T] {
return &ListChangeSet[T]{listLength: length}
}
// AddChange appens to a new change to the changeset of the list.
func (l *ListChangeSet[T]) AddChange(index int, elem T) {
l.compact = false
l.list = append(l.list, &listElementChangeset[T]{
value: elem,
listIndex: index,
id: l.nextId,
})
l.nextId++
}
// CompactChanges removes duplicates from a list using QuickSort and linear scan.
// duplicates may appear if one state parameter is changed more than once.
func (l *ListChangeSet[T]) CompactChanges() {
if l.compact {
return
}
l.compact = true
// Check if there are any duplicates to remove.
if len(l.list) < 2 {
return
}
// Sort the list using QuickSort.
sort.Slice(l.list, func(i, j int) bool {
if l.list[i].listIndex == l.list[j].listIndex {
return l.list[i].id < l.list[j].id
}
return l.list[i].listIndex < l.list[j].listIndex
})
// Create a new list buffer for the compacted list.
compactList := []*listElementChangeset[T]{}
// Do a linear scan through the sorted list and remove duplicates.
previousIndexElement := l.list[0]
for _, listElement := range l.list {
if listElement.listIndex != previousIndexElement.listIndex {
compactList = append(compactList, previousIndexElement)
}
previousIndexElement = listElement
}
compactList = append(compactList, previousIndexElement)
// Update the original list with the compacted list.
l.list = compactList
}
// CompactChangesReverse removes duplicates from a list using QuickSort and linear scan.
// duplicates may appear if one state parameter is changed more than once.
// Difference with CompactChanges is that the sorting is reversed.
func (l *ListChangeSet[T]) CompactChangesReverse() {
if l.compact {
return
}
l.compact = true
// Check if there are any duplicates to remove.
if len(l.list) < 2 {
return
}
// Sort the list using QuickSort.
sort.Slice(l.list, func(i, j int) bool {
if l.list[i].listIndex == l.list[j].listIndex {
return l.list[i].id > l.list[j].id
}
return l.list[i].listIndex < l.list[j].listIndex
})
// Create a new list buffer for the compacted list.
compactList := []*listElementChangeset[T]{}
// Do a linear scan through the sorted list and remove duplicates.
previousIndexElement := l.list[0]
for _, listElement := range l.list {
if listElement.listIndex != previousIndexElement.listIndex {
compactList = append(compactList, previousIndexElement)
}
previousIndexElement = listElement
}
compactList = append(compactList, previousIndexElement)
// Update the original list with the compacted list.
l.list = compactList
}
// ApplyChanges Apply changes without any mercy. if it is reverse, you need to call CompactChangesReverse before.
func (l *ListChangeSet[T]) ApplyChanges(input []T) (output []T, changed bool) {
if len(l.list) == 0 && l.listLength == len(input) {
output = input
return
}
changed = true
// Re-adjust list size.
output = make([]T, l.listLength)
copy(output, input)
// Now apply changes to the given list
for _, elem := range l.list {
if elem.listIndex >= len(output) {
continue
}
output[elem.listIndex] = elem.value
}
return
}
// ChangesWithHandler uses custom handler to handle changes.
func (l *ListChangeSet[T]) ChangesWithHandler(fn func(value T, index int)) {
// Now apply changes to the given list
for _, elem := range l.list {
fn(elem.value, elem.listIndex)
}
}
// ListLength return full list length
func (l *ListChangeSet[T]) ListLength() int {
return l.listLength
}
// Empty return whether current list diff is empty
func (l *ListChangeSet[T]) Empty() bool {
return len(l.list) == 0
}

View File

@ -0,0 +1,45 @@
package beacon_changeset
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestListChangeset(t *testing.T) {
pre := []int{6, 8, 9}
changeset := NewListChangeSet[int](3)
changeset.AddChange(1, 45)
changeset.AddChange(1, 1)
changeset.AddChange(2, 45)
changeset.CompactChanges()
require.Equal(t, len(changeset.list), 2)
post, changed := changeset.ApplyChanges(pre)
require.Equal(t, post, []int{6, 1, 45})
require.Equal(t, changed, true)
}
func TestListChangesetWithReverse(t *testing.T) {
pre := []int{6, 8, 9}
changeset := NewListChangeSet[int](3)
changeset.AddChange(1, 45)
changeset.AddChange(1, 1)
changeset.AddChange(2, 45)
changeset.CompactChangesReverse()
require.Equal(t, len(changeset.list), 2)
post, changed := changeset.ApplyChanges(pre)
require.Equal(t, post, []int{6, 45, 45})
require.Equal(t, changed, true)
}
func TestListChangesetWithoutCompact(t *testing.T) {
pre := []int{6, 8, 9}
changeset := NewListChangeSet[int](3)
changeset.AddChange(1, 45)
changeset.AddChange(1, 1)
changeset.AddChange(2, 45)
require.Equal(t, len(changeset.list), 3)
post, changed := changeset.ApplyChanges(pre)
require.Equal(t, post, []int{6, 1, 45})
require.Equal(t, changed, true)
}

View File

@ -0,0 +1,241 @@
package beacon_changeset
import (
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
)
// This type of changeset is the diff beetwen next state and input state and is used to reverse beacon state.
// It does not work the other way around. So they apply [curr state] + [reverse change set] = [prev state]
type ReverseBeaconStateChangeSet struct {
// Single types.
SlotChange *uint64
ForkChange *cltypes.Fork
LatestBlockHeaderChange *cltypes.BeaconBlockHeader
Eth1DataChange *cltypes.Eth1Data
Eth1DepositIndexChange *uint64
JustificationBitsChange *cltypes.JustificationBits
PreviousJustifiedCheckpointChange *cltypes.Checkpoint
CurrentJustifiedCheckpointChange *cltypes.Checkpoint
FinalizedCheckpointChange *cltypes.Checkpoint
CurrentSyncCommitteeChange *cltypes.SyncCommittee
NextSyncCommitteeChange *cltypes.SyncCommittee
LatestExecutionPayloadHeaderChange *cltypes.Eth1Header
NextWithdrawalIndexChange *uint64
NextWithdrawalValidatorIndexChange *uint64
VersionChange *clparams.StateVersion
// Lists and arrays changesets
BlockRootsChanges *ListChangeSet[libcommon.Hash]
StateRootsChanges *ListChangeSet[libcommon.Hash]
HistoricalRootsChanges *ListChangeSet[libcommon.Hash]
Eth1DataVotesChanges *ListChangeSet[cltypes.Eth1Data]
BalancesChanges *ListChangeSet[uint64]
RandaoMixesChanges *ListChangeSet[libcommon.Hash]
SlashingsChanges *ListChangeSet[uint64]
PreviousEpochParticipationChanges *ListChangeSet[cltypes.ParticipationFlags]
CurrentEpochParticipationChanges *ListChangeSet[cltypes.ParticipationFlags]
InactivityScoresChanges *ListChangeSet[uint64]
HistoricalSummaryChange *ListChangeSet[cltypes.HistoricalSummary]
// Validator fields.
WithdrawalCredentialsChange *ListChangeSet[libcommon.Hash]
EffectiveBalanceChange *ListChangeSet[uint64]
SlashedChange *ListChangeSet[bool]
ActivationEligibilityEpochChange *ListChangeSet[uint64]
ActivationEpochChange *ListChangeSet[uint64]
ExitEpochChange *ListChangeSet[uint64]
WithdrawalEpochChange *ListChangeSet[uint64]
// Efficient unwinding on reset (only applicable at epoch boundaries)
PreviousEpochParticipationAtReset cltypes.ParticipationFlagsList
CurrentEpochParticipationAtReset cltypes.ParticipationFlagsList
Eth1DataVotesAtReset []*cltypes.Eth1Data
}
func (r *ReverseBeaconStateChangeSet) OnSlotChange(prevSlot uint64) {
if r.SlotChange != nil {
return
}
r.SlotChange = new(uint64)
*r.SlotChange = prevSlot
}
func (r *ReverseBeaconStateChangeSet) OnForkChange(fork *cltypes.Fork) {
if r.ForkChange != nil {
return
}
r.ForkChange = new(cltypes.Fork)
*r.ForkChange = *fork
}
func (r *ReverseBeaconStateChangeSet) OnLatestHeaderChange(h *cltypes.BeaconBlockHeader) {
if r.LatestBlockHeaderChange != nil {
return
}
r.LatestBlockHeaderChange = new(cltypes.BeaconBlockHeader)
*r.LatestBlockHeaderChange = *h
}
func (r *ReverseBeaconStateChangeSet) OnEth1DataChange(e *cltypes.Eth1Data) {
if r.LatestBlockHeaderChange != nil {
return
}
r.Eth1DataChange = new(cltypes.Eth1Data)
*r.Eth1DataChange = *e
}
func (r *ReverseBeaconStateChangeSet) OnJustificationBitsChange(j cltypes.JustificationBits) {
if r.JustificationBitsChange != nil {
return
}
r.JustificationBitsChange = new(cltypes.JustificationBits)
*r.JustificationBitsChange = j.Copy()
}
func (r *ReverseBeaconStateChangeSet) OnEth1DepositIndexChange(e uint64) {
if r.Eth1DepositIndexChange != nil {
return
}
r.Eth1DepositIndexChange = new(uint64)
*r.Eth1DepositIndexChange = e
}
func (r *ReverseBeaconStateChangeSet) OnPreviousJustifiedCheckpointChange(c *cltypes.Checkpoint) {
if r.PreviousJustifiedCheckpointChange != nil {
return
}
r.PreviousJustifiedCheckpointChange = new(cltypes.Checkpoint)
*r.PreviousJustifiedCheckpointChange = *c
}
func (r *ReverseBeaconStateChangeSet) OnCurrentJustifiedCheckpointChange(c *cltypes.Checkpoint) {
if r.CurrentJustifiedCheckpointChange != nil {
return
}
r.CurrentJustifiedCheckpointChange = new(cltypes.Checkpoint)
*r.CurrentJustifiedCheckpointChange = *c
}
func (r *ReverseBeaconStateChangeSet) OnFinalizedCheckpointChange(c *cltypes.Checkpoint) {
if r.FinalizedCheckpointChange != nil {
return
}
r.FinalizedCheckpointChange = new(cltypes.Checkpoint)
*r.FinalizedCheckpointChange = *c
}
func (r *ReverseBeaconStateChangeSet) OnCurrentSyncCommitteeChange(c *cltypes.SyncCommittee) {
if r.CurrentSyncCommitteeChange != nil {
return
}
r.CurrentSyncCommitteeChange = new(cltypes.SyncCommittee)
*r.CurrentSyncCommitteeChange = *c
}
func (r *ReverseBeaconStateChangeSet) OnNextSyncCommitteeChange(c *cltypes.SyncCommittee) {
if r.NextSyncCommitteeChange != nil {
return
}
r.NextSyncCommitteeChange = new(cltypes.SyncCommittee)
*r.NextSyncCommitteeChange = *c
}
func (r *ReverseBeaconStateChangeSet) OnEth1Header(e *cltypes.Eth1Header) {
if r.LatestExecutionPayloadHeaderChange != nil {
return
}
r.LatestExecutionPayloadHeaderChange = new(cltypes.Eth1Header)
*r.LatestExecutionPayloadHeaderChange = *e
}
func (r *ReverseBeaconStateChangeSet) OnNextWithdrawalIndexChange(index uint64) {
if r.NextWithdrawalIndexChange != nil {
return
}
r.NextWithdrawalIndexChange = new(uint64)
*r.NextWithdrawalIndexChange = index
}
func (r *ReverseBeaconStateChangeSet) OnNextWithdrawalValidatorIndexChange(index uint64) {
if r.NextWithdrawalValidatorIndexChange != nil {
return
}
r.NextWithdrawalValidatorIndexChange = new(uint64)
*r.NextWithdrawalValidatorIndexChange = index
}
func (r *ReverseBeaconStateChangeSet) OnVersionChange(v clparams.StateVersion) {
if r.VersionChange != nil {
return
}
r.VersionChange = new(clparams.StateVersion)
*r.VersionChange = v
}
func (r *ReverseBeaconStateChangeSet) HasValidatorSetNotChanged(validatorSetLength int) bool {
return validatorSetLength == r.WithdrawalCredentialsChange.ListLength() && r.WithdrawalCredentialsChange.Empty() && r.ActivationEligibilityEpochChange.Empty() && r.ActivationEpochChange.Empty() &&
r.EffectiveBalanceChange.Empty() && r.SlashedChange.Empty() && r.ExitEpochChange.Empty() && r.WithdrawalEpochChange.Empty()
}
func (r *ReverseBeaconStateChangeSet) ApplyEth1DataVotesChanges(input []*cltypes.Eth1Data) (output []*cltypes.Eth1Data, changed bool) {
output = input
if r.Eth1DataVotesChanges.Empty() && r.Eth1DataVotesChanges.ListLength() == len(output) {
return
}
changed = true
if r.Eth1DataVotesChanges.ListLength() != len(output) {
output = make([]*cltypes.Eth1Data, r.Eth1DataVotesChanges.ListLength())
copy(output, input)
}
r.Eth1DataVotesChanges.ChangesWithHandler(func(value cltypes.Eth1Data, index int) {
*output[index] = value
})
return
}
func (r *ReverseBeaconStateChangeSet) ApplyHistoricalSummaryChanges(input []*cltypes.HistoricalSummary) (output []*cltypes.HistoricalSummary, changed bool) {
output = input
if r.HistoricalSummaryChange.Empty() && r.Eth1DataVotesChanges.ListLength() == len(output) {
return
}
changed = true
historicalSummarryLength := r.HistoricalSummaryChange.ListLength()
if historicalSummarryLength != len(output) {
output = make([]*cltypes.HistoricalSummary, historicalSummarryLength)
copy(output, input)
}
r.HistoricalSummaryChange.ChangesWithHandler(func(value cltypes.HistoricalSummary, index int) {
*output[index] = value
})
return
}
func (r *ReverseBeaconStateChangeSet) CompactChanges() {
r.BlockRootsChanges.CompactChangesReverse()
r.StateRootsChanges.CompactChangesReverse()
r.HistoricalRootsChanges.CompactChangesReverse()
r.SlashingsChanges.CompactChangesReverse()
r.RandaoMixesChanges.CompactChangesReverse()
r.BalancesChanges.CompactChangesReverse()
if len(r.Eth1DataVotesAtReset) > 0 {
r.Eth1DataVotesChanges = nil
} else {
r.Eth1DataVotesChanges.CompactChangesReverse()
}
if len(r.PreviousEpochParticipationAtReset) > 0 {
r.PreviousEpochParticipationChanges = nil
r.CurrentEpochParticipationChanges = nil
} else {
r.PreviousEpochParticipationChanges.CompactChangesReverse()
r.CurrentEpochParticipationChanges.CompactChangesReverse()
}
r.InactivityScoresChanges.CompactChangesReverse()
r.HistoricalRootsChanges.CompactChangesReverse()
r.WithdrawalCredentialsChange.CompactChangesReverse()
r.EffectiveBalanceChange.CompactChangesReverse()
r.ExitEpochChange.CompactChangesReverse()
r.ActivationEligibilityEpochChange.CompactChangesReverse()
r.ActivationEpochChange.CompactChangesReverse()
r.SlashedChange.CompactChangesReverse()
r.WithdrawalEpochChange.CompactChangesReverse()
}

View File

@ -70,7 +70,7 @@ func (b *BeaconState) GetUnslashedParticipatingIndices(flagIndex int, epoch uint
return nil, fmt.Errorf("getUnslashedParticipatingIndices: only epoch and previous epoch can be used")
}
// Iterate over all validators and include the active ones that have flag_index enabled and are not slashed.
for i, validator := range b.Validators() {
for i, validator := range b.validators {
if !validator.Active(epoch) ||
!participation[i].HasFlag(flagIndex) ||
validator.Slashed {
@ -228,7 +228,7 @@ func (b *BeaconState) ComputeProposerIndex(indices []uint64, seed [32]byte) (uin
input := append(seed[:], buf...)
randomByte := uint64(utils.Keccak256(input)[i%32])
validator, err := b.ValidatorAt(int(candidateIndex))
validator, err := b.ValidatorForValidatorIndex(int(candidateIndex))
if err != nil {
return 0, err
}
@ -565,7 +565,7 @@ func (b *BeaconState) ComputeNextSyncCommittee() (*cltypes.SyncCommittee, error)
input := append(seed[:], buf...)
randomByte := uint64(utils.Keccak256(input)[i%32])
// retrieve validator.
validator, err := b.ValidatorAt(int(candidateIndex))
validator, err := b.ValidatorForValidatorIndex(int(candidateIndex))
if err != nil {
return nil, err
}

View File

@ -33,33 +33,6 @@ func getTestState(t *testing.T) *state.BeaconState {
return b
}
func TestActiveValidatorIndices(t *testing.T) {
epoch := uint64(2)
testState := state.GetEmptyBeaconState()
// Not Active validator
testState.AddValidator(&cltypes.Validator{
ActivationEpoch: 3,
ExitEpoch: 9,
EffectiveBalance: 2e9,
}, 2e9)
// Active Validator
testState.AddValidator(&cltypes.Validator{
ActivationEpoch: 1,
ExitEpoch: 9,
EffectiveBalance: 2e9,
}, 2e9)
testState.SetSlot(epoch * 32) // Epoch
testFlags := cltypes.ParticipationFlagsListFromBytes([]byte{1, 1})
testState.SetCurrentEpochParticipation(testFlags)
// Only validator at index 1 (second validator) is active.
require.Equal(t, testState.GetActiveValidatorsIndices(epoch), []uint64{1})
set, err := testState.GetUnslashedParticipatingIndices(0x00, epoch)
require.NoError(t, err)
require.Equal(t, set, []uint64{1})
// Check if balances are retrieved correctly
require.Equal(t, testState.GetTotalActiveBalance(), uint64(2e9))
}
func TestGetBlockRoot(t *testing.T) {
epoch := uint64(2)
testState := state.GetEmptyBeaconState()

View File

@ -0,0 +1,260 @@
package state
import (
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/beacon_changeset"
)
// StartCollectingReverseChangeSet starts collection change sets.
func (b *BeaconState) StartCollectingReverseChangeSet() {
b.reverseChangeset = &beacon_changeset.ReverseBeaconStateChangeSet{
BlockRootsChanges: beacon_changeset.NewListChangeSet[libcommon.Hash](len(b.blockRoots)),
StateRootsChanges: beacon_changeset.NewListChangeSet[libcommon.Hash](len(b.stateRoots)),
HistoricalRootsChanges: beacon_changeset.NewListChangeSet[libcommon.Hash](len(b.historicalRoots)),
Eth1DataVotesChanges: beacon_changeset.NewListChangeSet[cltypes.Eth1Data](len(b.eth1DataVotes)),
BalancesChanges: beacon_changeset.NewListChangeSet[uint64](len(b.balances)),
RandaoMixesChanges: beacon_changeset.NewListChangeSet[libcommon.Hash](len(b.randaoMixes)),
SlashingsChanges: beacon_changeset.NewListChangeSet[uint64](len(b.slashings)),
PreviousEpochParticipationChanges: beacon_changeset.NewListChangeSet[cltypes.ParticipationFlags](len(b.previousEpochParticipation)),
CurrentEpochParticipationChanges: beacon_changeset.NewListChangeSet[cltypes.ParticipationFlags](len(b.currentEpochParticipation)),
InactivityScoresChanges: beacon_changeset.NewListChangeSet[uint64](len(b.inactivityScores)),
HistoricalSummaryChange: beacon_changeset.NewListChangeSet[cltypes.HistoricalSummary](len(b.historicalSummaries)),
// Validators section
WithdrawalCredentialsChange: beacon_changeset.NewListChangeSet[libcommon.Hash](len(b.validators)),
EffectiveBalanceChange: beacon_changeset.NewListChangeSet[uint64](len(b.validators)),
ActivationEligibilityEpochChange: beacon_changeset.NewListChangeSet[uint64](len(b.validators)),
ActivationEpochChange: beacon_changeset.NewListChangeSet[uint64](len(b.validators)),
ExitEpochChange: beacon_changeset.NewListChangeSet[uint64](len(b.validators)),
WithdrawalEpochChange: beacon_changeset.NewListChangeSet[uint64](len(b.validators)),
SlashedChange: beacon_changeset.NewListChangeSet[bool](len(b.validators)),
}
}
// StopCollectingReverseChangeSet stops collection change sets.
func (b *BeaconState) StopCollectingReverseChangeSet() *beacon_changeset.ReverseBeaconStateChangeSet {
ret := b.reverseChangeset
b.reverseChangeset = nil
return ret
}
func (b *BeaconState) RevertWithChangeset(changeset *beacon_changeset.ReverseBeaconStateChangeSet) {
changeset.CompactChanges()
beforeSlot := b.slot
var touched bool
// Updates all single types accordingly.
if changeset.SlotChange != nil {
b.slot = *changeset.SlotChange
b.touchedLeaves[SlotLeafIndex] = true
}
if changeset.ForkChange != nil {
b.fork = changeset.ForkChange
b.touchedLeaves[ForkLeafIndex] = true
}
if changeset.LatestBlockHeaderChange != nil {
b.latestBlockHeader = changeset.LatestBlockHeaderChange
b.touchedLeaves[LatestBlockHeaderLeafIndex] = true
}
if changeset.Eth1DataChange != nil {
b.eth1Data = changeset.Eth1DataChange
b.touchedLeaves[Eth1DataLeafIndex] = true
}
if changeset.Eth1DepositIndexChange != nil {
b.eth1DepositIndex = *changeset.Eth1DepositIndexChange
b.touchedLeaves[Eth1DepositIndexLeafIndex] = true
}
if changeset.JustificationBitsChange != nil {
b.justificationBits = *changeset.JustificationBitsChange
b.touchedLeaves[JustificationBitsLeafIndex] = true
}
if changeset.PreviousJustifiedCheckpointChange != nil {
b.previousJustifiedCheckpoint = changeset.PreviousJustifiedCheckpointChange
b.touchedLeaves[PreviousJustifiedCheckpointLeafIndex] = true
}
if changeset.CurrentJustifiedCheckpointChange != nil {
b.currentJustifiedCheckpoint = changeset.CurrentJustifiedCheckpointChange
b.touchedLeaves[CurrentJustifiedCheckpointLeafIndex] = true
}
if changeset.FinalizedCheckpointChange != nil {
b.finalizedCheckpoint = changeset.FinalizedCheckpointChange
b.touchedLeaves[FinalizedCheckpointLeafIndex] = true
}
if changeset.CurrentSyncCommitteeChange != nil {
b.currentSyncCommittee = changeset.CurrentSyncCommitteeChange
b.touchedLeaves[CurrentSyncCommitteeLeafIndex] = true
}
if changeset.NextSyncCommitteeChange != nil {
b.nextSyncCommittee = changeset.NextSyncCommitteeChange
b.touchedLeaves[NextSyncCommitteeLeafIndex] = true
}
if changeset.LatestExecutionPayloadHeaderChange != nil {
b.latestExecutionPayloadHeader = changeset.LatestExecutionPayloadHeaderChange
b.touchedLeaves[LatestExecutionPayloadHeaderLeafIndex] = true
}
if changeset.NextWithdrawalIndexChange != nil {
b.nextWithdrawalIndex = *changeset.NextWithdrawalIndexChange
b.touchedLeaves[NextWithdrawalIndexLeafIndex] = true
}
if changeset.NextWithdrawalValidatorIndexChange != nil {
b.nextWithdrawalValidatorIndex = *changeset.NextWithdrawalValidatorIndexChange
b.touchedLeaves[NextWithdrawalValidatorIndexLeafIndex] = true
}
if changeset.VersionChange != nil {
b.version = *changeset.VersionChange
if b.version == clparams.AltairVersion {
b.leaves[LatestExecutionPayloadHeaderLeafIndex] = libcommon.Hash{}
b.touchedLeaves[LatestExecutionPayloadHeaderLeafIndex] = false
}
if b.version == clparams.BellatrixVersion {
b.leaves[NextWithdrawalIndexLeafIndex] = libcommon.Hash{}
b.leaves[NextWithdrawalValidatorIndexLeafIndex] = libcommon.Hash{}
b.leaves[HistoricalSummariesLeafIndex] = libcommon.Hash{}
b.touchedLeaves[NextWithdrawalIndexLeafIndex] = false
b.touchedLeaves[NextWithdrawalValidatorIndexLeafIndex] = false
b.touchedLeaves[HistoricalSummariesLeafIndex] = false
}
}
// Process all the lists now.
// Start with arrays first
changeset.BlockRootsChanges.ChangesWithHandler(func(value libcommon.Hash, index int) {
b.blockRoots[index] = value
b.touchedLeaves[BlockRootsLeafIndex] = true
})
changeset.StateRootsChanges.ChangesWithHandler(func(value libcommon.Hash, index int) {
b.stateRoots[index] = value
b.touchedLeaves[StateRootsLeafIndex] = true
})
changeset.RandaoMixesChanges.ChangesWithHandler(func(value libcommon.Hash, index int) {
b.randaoMixes[index] = value
b.touchedLeaves[RandaoMixesLeafIndex] = true
})
changeset.SlashingsChanges.ChangesWithHandler(func(value uint64, index int) {
b.slashings[index] = value
b.touchedLeaves[SlashingsLeafIndex] = true
})
// Process the lists now.
b.historicalRoots, touched = changeset.HistoricalRootsChanges.ApplyChanges(b.historicalRoots)
if touched {
b.touchedLeaves[HistoricalRootsLeafIndex] = true
}
// This is a special case, as reset will lead to complete change of votes
if len(changeset.Eth1DataVotesAtReset) == 0 {
b.eth1DataVotes, touched = changeset.ApplyEth1DataVotesChanges(b.eth1DataVotes)
if touched {
b.touchedLeaves[Eth1DataVotesLeafIndex] = true
}
} else {
b.eth1DataVotes = changeset.Eth1DataVotesAtReset
b.touchedLeaves[Eth1DataVotesLeafIndex] = true
}
b.balances, touched = changeset.BalancesChanges.ApplyChanges(b.balances)
if touched {
b.touchedLeaves[BalancesLeafIndex] = true
}
// This also a special case, as this is another victim of reset, we use rotation with curr and prev to handle it efficiently
if len(changeset.PreviousEpochParticipationAtReset) == 0 && len(changeset.CurrentEpochParticipationAtReset) == 0 {
b.previousEpochParticipation, touched = changeset.PreviousEpochParticipationChanges.ApplyChanges(b.previousEpochParticipation)
if touched {
b.touchedLeaves[PreviousEpochParticipationLeafIndex] = true
}
b.currentEpochParticipation, touched = changeset.CurrentEpochParticipationChanges.ApplyChanges(b.currentEpochParticipation)
if touched {
b.touchedLeaves[CurrentEpochParticipationLeafIndex] = true
}
} else {
b.touchedLeaves[PreviousEpochParticipationLeafIndex] = true
b.touchedLeaves[CurrentEpochParticipationLeafIndex] = true
b.previousEpochParticipation = changeset.PreviousEpochParticipationAtReset.Copy()
b.currentEpochParticipation = changeset.CurrentEpochParticipationAtReset.Copy()
}
b.inactivityScores, touched = changeset.InactivityScoresChanges.ApplyChanges(b.inactivityScores)
if touched {
b.touchedLeaves[InactivityScoresLeafIndex] = true
}
b.historicalSummaries, touched = changeset.ApplyHistoricalSummaryChanges(b.historicalSummaries)
if touched {
b.touchedLeaves[HistoricalSummariesLeafIndex] = true
}
// Now start processing validators if there are any.
if changeset.HasValidatorSetNotChanged(len(b.validators)) {
b.revertCachesOnBoundary(beforeSlot)
return
}
// We do it like this because validators diff can get quite big so we only save individual fields.
b.touchedLeaves[ValidatorsLeafIndex] = true
newValidatorsSet := b.validators
// All changes habe same length
previousValidatorSetLength := changeset.WithdrawalCredentialsChange.ListLength()
if previousValidatorSetLength != len(b.validators) {
for _, removedValidator := range b.validators[previousValidatorSetLength:] {
delete(b.publicKeyIndicies, removedValidator.PublicKey)
}
newValidatorsSet = make([]*cltypes.Validator, previousValidatorSetLength)
copy(newValidatorsSet, b.validators)
}
b.validators = newValidatorsSet
// Now start processing all of the validator fields
changeset.WithdrawalCredentialsChange.ChangesWithHandler(func(value libcommon.Hash, index int) {
if index >= len(b.validators) {
return
}
b.validators[index].WithdrawalCredentials = value
})
changeset.ExitEpochChange.ChangesWithHandler(func(value uint64, index int) {
if index >= len(b.validators) {
return
}
b.validators[index].ExitEpoch = value
})
changeset.ActivationEligibilityEpochChange.ChangesWithHandler(func(value uint64, index int) {
if index >= len(b.validators) {
return
}
b.validators[index].ActivationEligibilityEpoch = value
})
changeset.ActivationEpochChange.ChangesWithHandler(func(value uint64, index int) {
if index >= len(b.validators) {
return
}
b.validators[index].ActivationEpoch = value
})
changeset.SlashedChange.ChangesWithHandler(func(value bool, index int) {
if index >= len(b.validators) {
return
}
b.validators[index].Slashed = value
})
changeset.WithdrawalEpochChange.ChangesWithHandler(func(value uint64, index int) {
if index >= len(b.validators) {
return
}
b.validators[index].WithdrawableEpoch = value
})
changeset.EffectiveBalanceChange.ChangesWithHandler(func(value uint64, index int) {
if index >= len(b.validators) {
return
}
b.validators[index].EffectiveBalance = value
})
b.revertCachesOnBoundary(beforeSlot)
}
func (b *BeaconState) revertCachesOnBoundary(beforeSlot uint64) {
b.activeValidatorsCache.Purge()
beforeEpoch := beforeSlot / b.beaconConfig.SlotsPerEpoch
epoch := b.Epoch()
b.committeeCache.Purge()
b.previousStateRoot = libcommon.Hash{}
b.proposerIndex = nil
b.totalActiveBalanceCache = nil
if epoch <= beforeEpoch {
return
}
for epochToBeRemoved := beforeEpoch; epochToBeRemoved < epoch+1; beforeEpoch++ {
b.shuffledSetsCache.Remove(b.GetSeed(epochToBeRemoved, b.beaconConfig.DomainBeaconAttester))
b.activeValidatorsCache.Remove(epochToBeRemoved)
}
}

View File

@ -39,8 +39,8 @@ func (b *BeaconState) Fork() *cltypes.Fork {
return b.fork
}
func (b *BeaconState) LatestBlockHeader() *cltypes.BeaconBlockHeader {
return b.latestBlockHeader
func (b *BeaconState) LatestBlockHeader() cltypes.BeaconBlockHeader {
return *b.latestBlockHeader
}
func (b *BeaconState) BlockRoots() [blockRootsLength]libcommon.Hash {
@ -71,7 +71,7 @@ func (b *BeaconState) Validators() []*cltypes.Validator {
return b.validators
}
func (b *BeaconState) ValidatorAt(index int) (*cltypes.Validator, error) {
func (b *BeaconState) ValidatorForValidatorIndex(index int) (*cltypes.Validator, error) {
if index >= len(b.validators) {
return nil, ErrInvalidValidatorIndex
}
@ -101,18 +101,24 @@ func (b *BeaconState) SlashingSegmentAt(pos int) uint64 {
return b.slashings[pos]
}
func (b *BeaconState) PreviousEpochParticipation() cltypes.ParticipationFlagsList {
func (b *BeaconState) EpochParticipation(currentEpoch bool) cltypes.ParticipationFlagsList {
if currentEpoch {
return b.currentEpochParticipation
}
return b.previousEpochParticipation
}
func (b *BeaconState) CurrentEpochParticipation() cltypes.ParticipationFlagsList {
return b.currentEpochParticipation
}
func (b *BeaconState) JustificationBits() cltypes.JustificationBits {
return b.justificationBits
}
func (b *BeaconState) EpochParticipationForValidatorIndex(isCurrentEpoch bool, index int) cltypes.ParticipationFlags {
if isCurrentEpoch {
return b.currentEpochParticipation[index]
}
return b.previousEpochParticipation[index]
}
func (b *BeaconState) PreviousJustifiedCheckpoint() *cltypes.Checkpoint {
return b.previousJustifiedCheckpoint
}

View File

@ -60,12 +60,13 @@ func (b *BeaconState) InitiateValidatorExit(index uint64) error {
exitQueueEpoch += 1
}
b.validators[index].ExitEpoch = exitQueueEpoch
var overflow bool
if b.validators[index].WithdrawableEpoch, overflow = math.SafeAdd(b.validators[index].ExitEpoch, b.beaconConfig.MinValidatorWithdrawabilityDelay); overflow {
var newWithdrawableEpoch uint64
if newWithdrawableEpoch, overflow = math.SafeAdd(exitQueueEpoch, b.beaconConfig.MinValidatorWithdrawabilityDelay); overflow {
return fmt.Errorf("withdrawable epoch is too big")
}
b.touchedLeaves[ValidatorsLeafIndex] = true
b.SetExitEpochForValidatorAtIndex(int(index), exitQueueEpoch)
b.SetWithdrawableEpochForValidatorAtIndex(int(index), newWithdrawableEpoch)
return nil
}
@ -81,12 +82,20 @@ func (b *BeaconState) SlashValidator(slashedInd uint64, whistleblowerInd *uint64
if err := b.InitiateValidatorExit(slashedInd); err != nil {
return err
}
// Record changes in changeset
slashingsIndex := int(epoch % b.beaconConfig.EpochsPerSlashingsVector)
if b.reverseChangeset != nil {
b.reverseChangeset.SlashedChange.AddChange(int(slashedInd), b.validators[slashedInd].Slashed)
b.reverseChangeset.WithdrawalEpochChange.AddChange(int(slashedInd), b.validators[slashedInd].WithdrawableEpoch)
b.reverseChangeset.SlashingsChanges.AddChange(slashingsIndex, b.slashings[slashingsIndex])
}
// Change the validator to be slashed
b.validators[slashedInd].Slashed = true
b.validators[slashedInd].WithdrawableEpoch = utils.Max64(b.validators[slashedInd].WithdrawableEpoch, epoch+b.beaconConfig.EpochsPerSlashingsVector)
b.touchedLeaves[ValidatorsLeafIndex] = true
// Update slashings vector
b.slashings[epoch%b.beaconConfig.EpochsPerSlashingsVector] += b.validators[slashedInd].EffectiveBalance
b.slashings[slashingsIndex] += b.validators[slashedInd].EffectiveBalance
b.touchedLeaves[SlashingsLeafIndex] = true
if err := b.DecreaseBalance(slashedInd, b.validators[slashedInd].EffectiveBalance/b.beaconConfig.GetMinSlashingPenaltyQuotient(b.version)); err != nil {
return err

View File

@ -119,7 +119,7 @@ func TestInitiatieValidatorExit(t *testing.T) {
state.SetValidators(append(state.Validators(), tc.validator))
testInd := uint64(len(state.Validators()) - 1)
state.InitiateValidatorExit(testInd)
val, err := state.ValidatorAt(int(testInd))
val, err := state.ValidatorForValidatorIndex(int(testInd))
require.NoError(t, err)
if val.ExitEpoch != tc.expectedExitEpoch {
t.Errorf("unexpected exit epoch: got %d, want %d", val.ExitEpoch, tc.expectedExitEpoch)
@ -146,9 +146,9 @@ func TestSlashValidator(t *testing.T) {
// Set up slashed balance.
preSlashBalance := uint64(1 << 20)
successState.Balances()[slashedInd] = preSlashBalance
vali, err := successState.ValidatorAt(slashedInd)
vali, err := successState.ValidatorForValidatorIndex(slashedInd)
require.NoError(t, err)
successState.SetValidatorAt(slashedInd, vali)
successState.SetValidatorAtIndex(slashedInd, vali)
vali.EffectiveBalance = preSlashBalance
testCases := []struct {
@ -177,7 +177,7 @@ func TestSlashValidator(t *testing.T) {
if err != nil {
t.Errorf("unexpected error, wanted success: %v", err)
}
vali, err := tc.state.ValidatorAt(slashedInd)
vali, err := tc.state.ValidatorForValidatorIndex(slashedInd)
require.NoError(t, err)
// Check that the validator is slashed.
if !vali.Slashed {

View File

@ -4,31 +4,34 @@ type StateLeafIndex uint
// All position of all the leaves of the state merkle tree.
const (
GenesisTimeLeafIndex StateLeafIndex = 0
GenesisValidatorsRootLeafIndex StateLeafIndex = 1
SlotLeafIndex StateLeafIndex = 2
ForkLeafIndex StateLeafIndex = 3
LatestBlockHeaderLeafIndex StateLeafIndex = 4
BlockRootsLeafIndex StateLeafIndex = 5
StateRootsLeafIndex StateLeafIndex = 6
HistoricalRootsLeafIndex StateLeafIndex = 7
Eth1DataLeafIndex StateLeafIndex = 8
Eth1DataVotesLeafIndex StateLeafIndex = 9
Eth1DepositIndexLeafIndex StateLeafIndex = 10
ValidatorsLeafIndex StateLeafIndex = 11
BalancesLeafIndex StateLeafIndex = 12
RandaoMixesLeafIndex StateLeafIndex = 13
SlashingsLeafIndex StateLeafIndex = 14
PreviousEpochParticipationLeafIndex StateLeafIndex = 15
CurrentEpochParticipationLeafIndex StateLeafIndex = 16
JustificationBitsLeafIndex StateLeafIndex = 17
PreviousJustifiedCheckpointLeafIndex StateLeafIndex = 18
CurrentJustifiedCheckpointLeafIndex StateLeafIndex = 19
FinalizedCheckpointLeafIndex StateLeafIndex = 20
InactivityScoresLeafIndex StateLeafIndex = 21
CurrentSyncCommitteeLeafIndex StateLeafIndex = 22
NextSyncCommitteeLeafIndex StateLeafIndex = 23
GenesisTimeLeafIndex StateLeafIndex = 0
GenesisValidatorsRootLeafIndex StateLeafIndex = 1
SlotLeafIndex StateLeafIndex = 2
ForkLeafIndex StateLeafIndex = 3
LatestBlockHeaderLeafIndex StateLeafIndex = 4
BlockRootsLeafIndex StateLeafIndex = 5
StateRootsLeafIndex StateLeafIndex = 6
HistoricalRootsLeafIndex StateLeafIndex = 7
Eth1DataLeafIndex StateLeafIndex = 8
Eth1DataVotesLeafIndex StateLeafIndex = 9
Eth1DepositIndexLeafIndex StateLeafIndex = 10
ValidatorsLeafIndex StateLeafIndex = 11
BalancesLeafIndex StateLeafIndex = 12
RandaoMixesLeafIndex StateLeafIndex = 13
SlashingsLeafIndex StateLeafIndex = 14
PreviousEpochParticipationLeafIndex StateLeafIndex = 15
CurrentEpochParticipationLeafIndex StateLeafIndex = 16
JustificationBitsLeafIndex StateLeafIndex = 17
PreviousJustifiedCheckpointLeafIndex StateLeafIndex = 18
CurrentJustifiedCheckpointLeafIndex StateLeafIndex = 19
FinalizedCheckpointLeafIndex StateLeafIndex = 20
// Altair
InactivityScoresLeafIndex StateLeafIndex = 21
CurrentSyncCommitteeLeafIndex StateLeafIndex = 22
NextSyncCommitteeLeafIndex StateLeafIndex = 23
// Bellatrix
LatestExecutionPayloadHeaderLeafIndex StateLeafIndex = 24
// Capella
NextWithdrawalIndexLeafIndex StateLeafIndex = 25
NextWithdrawalValidatorIndexLeafIndex StateLeafIndex = 26
HistoricalSummariesLeafIndex StateLeafIndex = 27

View File

@ -3,7 +3,6 @@ package state
import (
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
)
@ -11,17 +10,10 @@ const maxEth1Votes = 2048
// Below are setters. Note that they also dirty the state.
func (b *BeaconState) SetGenesisTime(genesisTime uint64) {
b.touchedLeaves[GenesisTimeLeafIndex] = true
b.genesisTime = genesisTime
}
func (b *BeaconState) SetGenesisValidatorsRoot(genesisValidatorRoot libcommon.Hash) {
b.touchedLeaves[GenesisValidatorsRootLeafIndex] = true
b.genesisValidatorsRoot = genesisValidatorRoot
}
func (b *BeaconState) SetSlot(slot uint64) {
if b.reverseChangeset != nil {
b.reverseChangeset.OnSlotChange(b.slot)
}
b.touchedLeaves[SlotLeafIndex] = true
b.slot = slot
b.proposerIndex = nil
@ -32,47 +24,97 @@ func (b *BeaconState) SetSlot(slot uint64) {
func (b *BeaconState) SetFork(fork *cltypes.Fork) {
b.touchedLeaves[ForkLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnForkChange(b.fork)
}
b.fork = fork
}
func (b *BeaconState) SetLatestBlockHeader(header *cltypes.BeaconBlockHeader) {
b.touchedLeaves[LatestBlockHeaderLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnLatestHeaderChange(b.latestBlockHeader)
}
b.latestBlockHeader = header
}
func (b *BeaconState) SetHistoricalRoots(historicalRoots []libcommon.Hash) {
b.touchedLeaves[HistoricalRootsLeafIndex] = true
b.historicalRoots = historicalRoots
}
func (b *BeaconState) SetBlockRootAt(index int, root libcommon.Hash) {
b.touchedLeaves[BlockRootsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.BlockRootsChanges.AddChange(index, b.blockRoots[index])
}
b.blockRoots[index] = root
}
func (b *BeaconState) SetStateRootAt(index int, root libcommon.Hash) {
b.touchedLeaves[StateRootsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.StateRootsChanges.AddChange(index, b.stateRoots[index])
}
b.stateRoots[index] = root
}
func (b *BeaconState) SetHistoricalRootAt(index int, root [32]byte) {
b.touchedLeaves[HistoricalRootsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.HistoricalRootsChanges.AddChange(index, b.historicalRoots[index])
}
b.historicalRoots[index] = root
}
func (b *BeaconState) SetValidatorAt(index int, validator *cltypes.Validator) error {
if index >= len(b.validators) {
return ErrInvalidValidatorIndex
}
b.validators[index] = validator
func (b *BeaconState) SetWithdrawalCredentialForValidatorAtIndex(index int, creds libcommon.Hash) {
b.touchedLeaves[ValidatorsLeafIndex] = true
// change in validator set means cache purging
b.totalActiveBalanceCache = nil
return nil
if b.reverseChangeset != nil {
b.reverseChangeset.WithdrawalCredentialsChange.AddChange(index, b.validators[index].WithdrawalCredentials)
}
b.validators[index].WithdrawalCredentials = creds
}
func (b *BeaconState) SetExitEpochForValidatorAtIndex(index int, epoch uint64) {
b.touchedLeaves[ValidatorsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.ExitEpochChange.AddChange(index, b.validators[index].ExitEpoch)
}
b.validators[index].ExitEpoch = epoch
}
func (b *BeaconState) SetWithdrawableEpochForValidatorAtIndex(index int, epoch uint64) {
b.touchedLeaves[ValidatorsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.WithdrawalEpochChange.AddChange(index, b.validators[index].WithdrawableEpoch)
}
b.validators[index].WithdrawableEpoch = epoch
}
func (b *BeaconState) SetEffectiveBalanceForValidatorAtIndex(index int, balance uint64) {
b.touchedLeaves[ValidatorsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.EffectiveBalanceChange.AddChange(index, b.validators[index].EffectiveBalance)
}
b.validators[index].EffectiveBalance = balance
}
func (b *BeaconState) SetActivationEpochForValidatorAtIndex(index int, epoch uint64) {
b.touchedLeaves[ValidatorsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.ActivationEpochChange.AddChange(index, b.validators[index].ActivationEpoch)
}
b.validators[index].ActivationEpoch = epoch
}
func (b *BeaconState) SetActivationEligibilityEpochForValidatorAtIndex(index int, epoch uint64) {
b.touchedLeaves[ValidatorsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.ActivationEligibilityEpochChange.AddChange(index, b.validators[index].ActivationEligibilityEpoch)
}
b.validators[index].ActivationEligibilityEpoch = epoch
}
func (b *BeaconState) SetEth1Data(eth1Data *cltypes.Eth1Data) {
b.touchedLeaves[Eth1DataLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnEth1DataChange(eth1Data)
}
b.eth1Data = eth1Data
}
@ -82,12 +124,18 @@ func (b *BeaconState) AddEth1DataVote(vote *cltypes.Eth1Data) {
}
func (b *BeaconState) ResetEth1DataVotes() {
if b.reverseChangeset != nil {
b.reverseChangeset.Eth1DataVotesAtReset = b.eth1DataVotes
}
b.touchedLeaves[Eth1DataVotesLeafIndex] = true
b.eth1DataVotes = b.eth1DataVotes[:0]
b.eth1DataVotes = nil
}
func (b *BeaconState) SetEth1DepositIndex(eth1DepositIndex uint64) {
b.touchedLeaves[Eth1DepositIndexLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnEth1DepositIndexChange(b.eth1DepositIndex)
}
b.eth1DepositIndex = eth1DepositIndex
}
@ -120,72 +168,131 @@ func (b *BeaconState) SetValidatorBalance(index int, balance uint64) error {
}
b.touchedLeaves[BalancesLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.BalancesChanges.AddChange(index, b.balances[index])
}
b.balances[index] = balance
return nil
}
func (b *BeaconState) SetRandaoMixAt(index int, mix libcommon.Hash) {
b.touchedLeaves[RandaoMixesLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.RandaoMixesChanges.AddChange(index, b.randaoMixes[index])
}
b.randaoMixes[index] = mix
}
func (b *BeaconState) SetSlashingSegmentAt(index int, segment uint64) {
b.touchedLeaves[SlashingsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.SlashingsChanges.AddChange(index, b.slashings[index])
}
b.slashings[index] = segment
}
func (b *BeaconState) SetPreviousEpochParticipation(previousEpochParticipation []cltypes.ParticipationFlags) {
func (b *BeaconState) SetEpochParticipationForValidatorIndex(isCurrentEpoch bool, index int, flags cltypes.ParticipationFlags) {
if isCurrentEpoch {
if b.reverseChangeset != nil {
b.reverseChangeset.CurrentEpochParticipationChanges.AddChange(index, b.currentEpochParticipation[index])
}
b.touchedLeaves[CurrentEpochParticipationLeafIndex] = true
b.currentEpochParticipation[index] = flags
return
}
if b.reverseChangeset != nil {
b.reverseChangeset.PreviousEpochParticipationChanges.AddChange(index, b.previousEpochParticipation[index])
}
b.touchedLeaves[PreviousEpochParticipationLeafIndex] = true
b.previousEpochParticipation = previousEpochParticipation
b.previousEpochParticipation[index] = flags
}
func (b *BeaconState) SetCurrentEpochParticipation(currentEpochParticipation []cltypes.ParticipationFlags) {
func (b *BeaconState) SetValidatorAtIndex(index int, validator *cltypes.Validator) {
b.touchedLeaves[ValidatorsLeafIndex] = true
b.validators[index] = validator
}
func (b *BeaconState) ResetEpochParticipation() {
if b.reverseChangeset != nil && len(b.reverseChangeset.CurrentEpochParticipationAtReset) == 0 &&
len(b.reverseChangeset.PreviousEpochParticipationAtReset) == 0 {
b.reverseChangeset.CurrentEpochParticipationAtReset = b.currentEpochParticipation.Copy()
b.reverseChangeset.PreviousEpochParticipationAtReset = b.previousEpochParticipation.Copy()
}
b.touchedLeaves[PreviousEpochParticipationLeafIndex] = true
b.touchedLeaves[CurrentEpochParticipationLeafIndex] = true
b.currentEpochParticipation = currentEpochParticipation
b.previousEpochParticipation = b.currentEpochParticipation
b.currentEpochParticipation = make(cltypes.ParticipationFlagsList, len(b.validators))
}
func (b *BeaconState) SetJustificationBits(justificationBits cltypes.JustificationBits) {
b.touchedLeaves[JustificationBitsLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnJustificationBitsChange(b.justificationBits)
}
b.justificationBits = justificationBits
}
func (b *BeaconState) SetPreviousJustifiedCheckpoint(previousJustifiedCheckpoint *cltypes.Checkpoint) {
b.touchedLeaves[PreviousJustifiedCheckpointLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnPreviousJustifiedCheckpointChange(b.previousJustifiedCheckpoint)
}
b.previousJustifiedCheckpoint = previousJustifiedCheckpoint
}
func (b *BeaconState) SetCurrentJustifiedCheckpoint(currentJustifiedCheckpoint *cltypes.Checkpoint) {
b.touchedLeaves[CurrentJustifiedCheckpointLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnCurrentJustifiedCheckpointChange(b.currentJustifiedCheckpoint)
}
b.currentJustifiedCheckpoint = currentJustifiedCheckpoint
}
func (b *BeaconState) SetFinalizedCheckpoint(finalizedCheckpoint *cltypes.Checkpoint) {
b.touchedLeaves[FinalizedCheckpointLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnFinalizedCheckpointChange(b.finalizedCheckpoint)
}
b.finalizedCheckpoint = finalizedCheckpoint
}
func (b *BeaconState) SetCurrentSyncCommittee(currentSyncCommittee *cltypes.SyncCommittee) {
b.touchedLeaves[CurrentSyncCommitteeLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnCurrentSyncCommitteeChange(b.currentSyncCommittee)
}
b.currentSyncCommittee = currentSyncCommittee
}
func (b *BeaconState) SetNextSyncCommittee(nextSyncCommittee *cltypes.SyncCommittee) {
b.touchedLeaves[NextSyncCommitteeLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnNextSyncCommitteeChange(b.nextSyncCommittee)
}
b.nextSyncCommittee = nextSyncCommittee
}
func (b *BeaconState) SetLatestExecutionPayloadHeader(header *cltypes.Eth1Header) {
b.touchedLeaves[LatestExecutionPayloadHeaderLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnEth1Header(b.latestExecutionPayloadHeader)
}
b.latestExecutionPayloadHeader = header
}
func (b *BeaconState) SetNextWithdrawalIndex(index uint64) {
b.touchedLeaves[NextWithdrawalIndexLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnNextWithdrawalIndexChange(b.nextWithdrawalIndex)
}
b.nextWithdrawalIndex = index
}
func (b *BeaconState) SetNextWithdrawalValidatorIndex(index uint64) {
b.touchedLeaves[NextWithdrawalValidatorIndexLeafIndex] = true
if b.reverseChangeset != nil {
b.reverseChangeset.OnNextWithdrawalValidatorIndexChange(b.nextWithdrawalValidatorIndex)
}
b.nextWithdrawalValidatorIndex = index
}
@ -208,55 +315,40 @@ func (b *BeaconState) SetValidatorInactivityScore(index int, score uint64) error
if index >= len(b.inactivityScores) {
return ErrInvalidValidatorIndex
}
if b.reverseChangeset != nil {
b.reverseChangeset.InactivityScoresChanges.AddChange(index, b.inactivityScores[index])
}
b.touchedLeaves[InactivityScoresLeafIndex] = true
b.inactivityScores[index] = score
return nil
}
func (b *BeaconState) AddCurrentEpochParticipationFlags(flags cltypes.ParticipationFlags) {
if b.version == clparams.Phase0Version {
panic("cannot call AddCurrentEpochParticipationFlags on phase0")
}
b.touchedLeaves[CurrentEpochParticipationLeafIndex] = true
b.currentEpochParticipation = append(b.currentEpochParticipation, flags)
}
func (b *BeaconState) AddPreviousEpochParticipationFlags(flags cltypes.ParticipationFlags) {
if b.version == clparams.Phase0Version {
panic("cannot call AddPreviousEpochParticipationFlags on phase0")
}
b.touchedLeaves[PreviousEpochParticipationLeafIndex] = true
b.previousEpochParticipation = append(b.previousEpochParticipation, flags)
}
func (b *BeaconState) AddCurrentEpochAtteastation(attestation *cltypes.PendingAttestation) {
if b.version != clparams.Phase0Version {
panic("can call AddCurrentEpochAtteastation only on phase0")
}
b.touchedLeaves[CurrentEpochParticipationLeafIndex] = true
b.currentEpochAttestations = append(b.currentEpochAttestations, attestation)
}
func (b *BeaconState) AddPreviousEpochAtteastation(attestation *cltypes.PendingAttestation) {
if b.version != clparams.Phase0Version {
panic("can call AddPreviousEpochAtteastation only on phase0")
}
func (b *BeaconState) AddPreviousEpochAttestation(attestation *cltypes.PendingAttestation) {
b.touchedLeaves[PreviousEpochParticipationLeafIndex] = true
b.previousEpochAttestations = append(b.previousEpochAttestations, attestation)
}
func (b *BeaconState) SetCurrentEpochAtteastations(attestations []*cltypes.PendingAttestation) {
if b.version != clparams.Phase0Version {
panic("can call SetCurrentEpochAtteastations only on phase0")
}
func (b *BeaconState) ResetCurrentEpochAttestations() {
b.touchedLeaves[CurrentEpochParticipationLeafIndex] = true
b.currentEpochAttestations = attestations
b.currentEpochAttestations = nil
}
func (b *BeaconState) SetPreviousEpochAtteastations(attestations []*cltypes.PendingAttestation) {
if b.version != clparams.Phase0Version {
panic("can call SetPreviousEpochAtteastations only on phase0")
}
func (b *BeaconState) SetPreviousEpochAttestations(attestations []*cltypes.PendingAttestation) {
b.touchedLeaves[PreviousEpochParticipationLeafIndex] = true
b.previousEpochAttestations = attestations
}

View File

@ -11,6 +11,7 @@ import (
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/utils"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/beacon_changeset"
)
type HashFunc func([]byte) ([32]byte, error)
@ -73,6 +74,8 @@ type BeaconState struct {
previousStateRoot libcommon.Hash
// Configs
beaconConfig *clparams.BeaconChainConfig
// Changesets
reverseChangeset *beacon_changeset.ReverseBeaconStateChangeSet
}
func New(cfg *clparams.BeaconChainConfig) *BeaconState {

View File

@ -59,6 +59,10 @@ func (b *BeaconState) UpgradeToAltair() error {
func (b *BeaconState) UpgradeToBellatrix() error {
b.previousStateRoot = libcommon.Hash{}
epoch := b.Epoch()
if b.reverseChangeset != nil {
b.reverseChangeset.OnVersionChange(b.version)
b.reverseChangeset.OnForkChange(b.fork)
}
// update version
b.fork.Epoch = epoch
b.fork.PreviousVersion = b.fork.CurrentVersion
@ -74,6 +78,11 @@ func (b *BeaconState) UpgradeToBellatrix() error {
func (b *BeaconState) UpgradeToCapella() error {
b.previousStateRoot = libcommon.Hash{}
epoch := b.Epoch()
if b.reverseChangeset != nil {
b.reverseChangeset.OnVersionChange(b.version)
b.reverseChangeset.OnForkChange(b.fork)
b.reverseChangeset.OnEth1Header(b.latestExecutionPayloadHeader)
}
// update version
b.fork.Epoch = epoch
b.fork.PreviousVersion = b.fork.CurrentVersion

View File

@ -84,7 +84,7 @@ func ProcessJustificationBitsAndFinality(state *state.BeaconState) error {
}
} else {
// Use bitlists to determine finality.
previousParticipation, currentParticipation := state.PreviousEpochParticipation(), state.CurrentEpochParticipation()
previousParticipation, currentParticipation := state.EpochParticipation(false), state.EpochParticipation(true)
for i, validator := range state.Validators() {
if validator.Slashed {
continue

View File

@ -26,7 +26,7 @@ func isValidIndexedAttestation(state *state.BeaconState, att *cltypes.IndexedAtt
pks := [][]byte{}
for _, v := range inds {
val, err := state.ValidatorAt(int(v))
val, err := state.ValidatorForValidatorIndex(int(v))
if err != nil {
return false, err
}
@ -77,7 +77,7 @@ func ProcessProposerSlashing(state *state.BeaconState, propSlashing *cltypes.Pro
return fmt.Errorf("propose slashing headers are the same: %v == %v", h1Root, h2Root)
}
proposer, err := state.ValidatorAt(int(h1.ProposerIndex))
proposer, err := state.ValidatorForValidatorIndex(int(h1.ProposerIndex))
if err != nil {
return err
}
@ -135,7 +135,7 @@ func ProcessAttesterSlashing(state *state.BeaconState, attSlashing *cltypes.Atte
slashedAny := false
currentEpoch := state.GetEpochAtSlot(state.Slot())
for _, ind := range utils.IntersectionOfSortedSets(att1.AttestingIndices, att2.AttestingIndices) {
validator, err := state.ValidatorAt(int(ind))
validator, err := state.ValidatorForValidatorIndex(int(ind))
if err != nil {
return err
}
@ -217,7 +217,7 @@ func ProcessVoluntaryExit(state *state.BeaconState, signedVoluntaryExit *cltypes
// Sanity checks so that we know it is good.
voluntaryExit := signedVoluntaryExit.VolunaryExit
currentEpoch := state.Epoch()
validator, err := state.ValidatorAt(int(voluntaryExit.ValidatorIndex))
validator, err := state.ValidatorForValidatorIndex(int(voluntaryExit.ValidatorIndex))
if err != nil {
return err
}

View File

@ -78,7 +78,7 @@ func getSuccessfulAttesterSlashing() *cltypes.AttesterSlashing {
func TestProcessProposerSlashing(t *testing.T) {
unchangingState := getTestState(t)
unchangingState.SetValidatorAt(propInd, &cltypes.Validator{
unchangingState.SetValidatorAtIndex(propInd, &cltypes.Validator{
Slashed: false,
ActivationEpoch: 0,
WithdrawableEpoch: 10000,
@ -86,7 +86,7 @@ func TestProcessProposerSlashing(t *testing.T) {
})
successState := getTestState(t)
successState.SetValidatorAt(propInd, &cltypes.Validator{
successState.SetValidatorAtIndex(propInd, &cltypes.Validator{
Slashed: false,
ActivationEpoch: 0,
WithdrawableEpoch: 10000,
@ -187,13 +187,13 @@ func TestProcessProposerSlashing(t *testing.T) {
func TestProcessAttesterSlashing(t *testing.T) {
unchangingState := getTestState(t)
unchangingState.SetValidatorAt(0, &cltypes.Validator{
unchangingState.SetValidatorAtIndex(0, &cltypes.Validator{
Slashed: false,
ActivationEpoch: 0,
WithdrawableEpoch: 10000,
PublicKey: testPublicKeySlashing,
})
unchangingState.SetValidatorAt(1, &cltypes.Validator{
unchangingState.SetValidatorAtIndex(1, &cltypes.Validator{
Slashed: false,
ActivationEpoch: 0,
WithdrawableEpoch: 10000,
@ -201,13 +201,13 @@ func TestProcessAttesterSlashing(t *testing.T) {
})
successState := getTestState(t)
successState.SetValidatorAt(0, &cltypes.Validator{
successState.SetValidatorAtIndex(0, &cltypes.Validator{
Slashed: false,
ActivationEpoch: 0,
WithdrawableEpoch: 10000,
PublicKey: testPublicKeySlashing,
})
successState.SetValidatorAt(1, &cltypes.Validator{
successState.SetValidatorAtIndex(1, &cltypes.Validator{
Slashed: false,
ActivationEpoch: 0,
WithdrawableEpoch: 10000,

View File

@ -52,21 +52,17 @@ func processAttestationPostAltair(state *state.BeaconState, attestation *cltypes
}
var proposerRewardNumerator uint64
var epochParticipation cltypes.ParticipationFlagsList
if data.Target.Epoch == currentEpoch {
epochParticipation = state.CurrentEpochParticipation()
} else {
epochParticipation = state.PreviousEpochParticipation()
}
validators := state.Validators()
isCurrentEpoch := data.Target.Epoch == currentEpoch
validators := state.Validators()
for _, attesterIndex := range attestingIndicies {
baseReward := (validators[attesterIndex].EffectiveBalance / beaconConfig.EffectiveBalanceIncrement) * baseRewardPerIncrement
for flagIndex, weight := range beaconConfig.ParticipationWeights() {
if !slices.Contains(participationFlagsIndicies, uint8(flagIndex)) || epochParticipation[attesterIndex].HasFlag(flagIndex) {
flagParticipation := state.EpochParticipationForValidatorIndex(isCurrentEpoch, int(attesterIndex))
if !slices.Contains(participationFlagsIndicies, uint8(flagIndex)) || flagParticipation.HasFlag(flagIndex) {
continue
}
epochParticipation[attesterIndex] = epochParticipation[attesterIndex].Add(flagIndex)
state.SetEpochParticipationForValidatorIndex(isCurrentEpoch, int(attesterIndex), flagParticipation.Add(flagIndex))
proposerRewardNumerator += baseReward * weight
}
}
@ -75,12 +71,6 @@ func processAttestationPostAltair(state *state.BeaconState, attestation *cltypes
if err != nil {
return nil, err
}
// Set participation
if data.Target.Epoch == currentEpoch {
state.SetCurrentEpochParticipation(epochParticipation)
} else {
state.SetPreviousEpochParticipation(epochParticipation)
}
proposerRewardDenominator := (beaconConfig.WeightDenominator - beaconConfig.ProposerWeight) * beaconConfig.WeightDenominator / beaconConfig.ProposerWeight
reward := proposerRewardNumerator / proposerRewardDenominator
return attestingIndicies, state.IncreaseBalance(proposer, reward)
@ -120,7 +110,7 @@ func processAttestationPhase0(state *state.BeaconState, attestation *cltypes.Att
if !data.Source.Equal(state.PreviousJustifiedCheckpoint()) {
return nil, fmt.Errorf("processAttestationPhase0: mismatching sources")
}
state.AddPreviousEpochAtteastation(pendingAttestation)
state.AddPreviousEpochAttestation(pendingAttestation)
}
// Not required by specs but needed if we want performant epoch transition.
indicies, err := state.GetAttestingIndicies(attestation.Data, attestation.AggregationBits, true)
@ -137,7 +127,7 @@ func processAttestationPhase0(state *state.BeaconState, attestation *cltypes.Att
}
// Basically we flag all validators we are currently attesting. will be important for rewards/finalization processing.
for _, index := range indicies {
validator, err := state.ValidatorAt(int(index))
validator, err := state.ValidatorForValidatorIndex(int(index))
if err != nil {
return nil, err
}
@ -169,10 +159,6 @@ func processAttestationPhase0(state *state.BeaconState, attestation *cltypes.Att
validator.IsPreviousMatchingHeadAttester = true
}
}
if err := state.SetValidatorAt(int(index), validator); err != nil {
return nil, err
}
}
return indicies, nil
}

View File

@ -16,7 +16,7 @@ func ProcessBlsToExecutionChange(state *state.BeaconState, signedChange *cltypes
change := signedChange.Message
beaconConfig := state.BeaconConfig()
validator, err := state.ValidatorAt(int(change.ValidatorIndex))
validator, err := state.ValidatorForValidatorIndex(int(change.ValidatorIndex))
if err != nil {
return err
}
@ -51,12 +51,13 @@ func ProcessBlsToExecutionChange(state *state.BeaconState, signedChange *cltypes
return fmt.Errorf("invalid signature")
}
}
credentials := validator.WithdrawalCredentials
// Reset the validator's withdrawal credentials.
validator.WithdrawalCredentials[0] = beaconConfig.ETH1AddressWithdrawalPrefixByte
copy(validator.WithdrawalCredentials[1:], make([]byte, 11))
copy(validator.WithdrawalCredentials[12:], change.To[:])
credentials[0] = beaconConfig.ETH1AddressWithdrawalPrefixByte
copy(credentials[1:], make([]byte, 11))
copy(credentials[12:], change.To[:])
// Update the state with the modified validator.
return state.SetValidatorAt(int(change.ValidatorIndex), validator)
state.SetWithdrawalCredentialForValidatorAtIndex(int(change.ValidatorIndex), credentials)
return nil
}

View File

@ -21,10 +21,8 @@ func ProcessEffectiveBalanceUpdates(state *state.BeaconState) error {
if balance+downwardThreshold < validator.EffectiveBalance ||
validator.EffectiveBalance+upwardThreshold < balance {
// Set new effective balance
validator.EffectiveBalance = utils.Min64(balance-(balance%beaconConfig.EffectiveBalanceIncrement), beaconConfig.MaxEffectiveBalance)
if err := state.SetValidatorAt(index, validator); err != nil {
return err
}
effectiveBalance := utils.Min64(balance-(balance%beaconConfig.EffectiveBalanceIncrement), beaconConfig.MaxEffectiveBalance)
state.SetEffectiveBalanceForValidatorAtIndex(index, effectiveBalance)
}
}
return nil

View File

@ -49,10 +49,10 @@ func ProcessEpoch(state *state.BeaconState) error {
}
func ProcessParticipationRecordUpdates(state *state.BeaconState) error {
state.SetPreviousEpochAtteastations(state.CurrentEpochAttestations())
state.SetCurrentEpochAtteastations(nil)
state.SetPreviousEpochAttestations(state.CurrentEpochAttestations())
state.ResetCurrentEpochAttestations()
// Also mark all current attesters as previous
for validatorIndex, validator := range state.Validators() {
for _, validator := range state.Validators() {
// Previous sources/target/head
validator.IsPreviousMatchingSourceAttester = validator.IsCurrentMatchingSourceAttester
validator.IsPreviousMatchingTargetAttester = validator.IsCurrentMatchingTargetAttester
@ -63,10 +63,6 @@ func ProcessParticipationRecordUpdates(state *state.BeaconState) error {
validator.IsCurrentMatchingSourceAttester = false
validator.IsCurrentMatchingTargetAttester = false
validator.IsCurrentMatchingHeadAttester = false
// Setting the validator
if err := state.SetValidatorAt(validatorIndex, validator); err != nil {
return err
}
}
return nil
}

View File

@ -22,10 +22,7 @@ func ProcessRegistryUpdates(state *state.BeaconState) error {
// Process activation eligibility and ejections.
for validatorIndex, validator := range validators {
if state.IsValidatorEligibleForActivationQueue(validator) {
validator.ActivationEligibilityEpoch = currentEpoch + 1
if err := state.SetValidatorAt(validatorIndex, validator); err != nil {
return err
}
state.SetActivationEligibilityEpochForValidatorAtIndex(validatorIndex, currentEpoch+1)
}
if validator.Active(currentEpoch) && validator.EffectiveBalance <= beaconConfig.EjectionBalance {
if err := state.InitiateValidatorExit(uint64(validatorIndex)); err != nil {
@ -51,14 +48,7 @@ func ProcessRegistryUpdates(state *state.BeaconState) error {
}
// Only process up to epoch limit.
for _, validatorIndex := range activationQueue {
validator, err := state.ValidatorAt(int(validatorIndex))
if err != nil {
return err
}
validator.ActivationEpoch = computeActivationExitEpoch(beaconConfig, currentEpoch)
if err := state.SetValidatorAt(int(validatorIndex), validator); err != nil {
return err
}
state.SetActivationEpochForValidatorAtIndex(int(validatorIndex), computeActivationExitEpoch(beaconConfig, currentEpoch))
}
return nil
}

View File

@ -70,10 +70,11 @@ func transitionSlot(state *state.BeaconState) error {
latestBlockHeader := state.LatestBlockHeader()
if latestBlockHeader.Root == [32]byte{} {
latestBlockHeader.Root = previousStateRoot
state.SetLatestBlockHeader(latestBlockHeader)
state.SetLatestBlockHeader(&latestBlockHeader)
}
blockHeader := state.LatestBlockHeader()
previousBlockRoot, err := state.LatestBlockHeader().HashSSZ()
previousBlockRoot, err := (&blockHeader).HashSSZ()
if err != nil {
return err
}
@ -127,7 +128,7 @@ func ProcessSlots(state *state.BeaconState, slot uint64) error {
}
func verifyBlockSignature(state *state.BeaconState, block *cltypes.SignedBeaconBlock) (bool, error) {
proposer, err := state.ValidatorAt(int(block.Block.ProposerIndex))
proposer, err := state.ValidatorForValidatorIndex(int(block.Block.ProposerIndex))
if err != nil {
return false, err
}

View File

@ -54,7 +54,7 @@ func prepareNextBeaconState(t *testing.T, slots []uint64, stateHashs, blockHashs
// Only copy if the previous is empty.
if latestBlockHeader.Root == [32]byte{} {
latestBlockHeader.Root = libcommon.BytesToHash(hash)
nextState.SetLatestBlockHeader(latestBlockHeader)
nextState.SetLatestBlockHeader(&latestBlockHeader)
}
hash, err = hex.DecodeString(blockHashs[i])
if err != nil {

View File

@ -33,7 +33,8 @@ func ProcessBlockHeader(state *state.BeaconState, block *cltypes.BeaconBlock, fu
if block.ProposerIndex != propInd {
return fmt.Errorf("block proposer index: %d, does not match beacon proposer index: %d", block.ProposerIndex, propInd)
}
latestRoot, err := state.LatestBlockHeader().HashSSZ()
blockHeader := state.LatestBlockHeader()
latestRoot, err := (&blockHeader).HashSSZ()
if err != nil {
return fmt.Errorf("unable to hash tree root of latest block header: %v", err)
}
@ -53,7 +54,7 @@ func ProcessBlockHeader(state *state.BeaconState, block *cltypes.BeaconBlock, fu
BodyRoot: bodyRoot,
})
proposer, err := state.ValidatorAt(int(block.ProposerIndex))
proposer, err := state.ValidatorForValidatorIndex(int(block.ProposerIndex))
if err != nil {
return err
}
@ -65,7 +66,7 @@ func ProcessBlockHeader(state *state.BeaconState, block *cltypes.BeaconBlock, fu
func ProcessRandao(state *state.BeaconState, randao [96]byte, proposerIndex uint64, fullValidation bool) error {
epoch := state.Epoch()
proposer, err := state.ValidatorAt(int(proposerIndex))
proposer, err := state.ValidatorForValidatorIndex(int(proposerIndex))
if err != nil {
return err
}
@ -93,7 +94,6 @@ func ProcessRandao(state *state.BeaconState, randao [96]byte, proposerIndex uint
for i := range mix {
mix[i] = randaoMixes[i] ^ randaoHash[i]
}
state.SetRandaoMixAt(int(epoch%state.BeaconConfig().EpochsPerHistoricalVector), mix)
return nil
}

View File

@ -83,10 +83,10 @@ func TestProcessBlockHeader(t *testing.T) {
badBlockBodyHash.Body.Attestations = append(badBlockBodyHash.Body.Attestations, &cltypes.Attestation{})
badStateSlashed := getTestState(t)
validator, err := badStateSlashed.ValidatorAt(int(testBlock.ProposerIndex))
validator, err := badStateSlashed.ValidatorForValidatorIndex(int(testBlock.ProposerIndex))
require.NoError(t, err)
validator.Slashed = true
badStateSlashed.SetValidatorAt(int(testBlock.ProposerIndex), validator)
badStateSlashed.SetValidatorAtIndex(int(testBlock.ProposerIndex), validator)
testCases := []struct {
description string
@ -160,10 +160,10 @@ func TestProcessRandao(t *testing.T) {
if err != nil {
t.Fatalf("unable to get proposer index: %v", err)
}
validator, err := testStateSuccess.ValidatorAt(int(propInd))
validator, err := testStateSuccess.ValidatorForValidatorIndex(int(propInd))
require.NoError(t, err)
validator.PublicKey = testPublicKeyRandao
testStateSuccess.SetValidatorAt(int(propInd), validator)
testStateSuccess.SetValidatorAtIndex(int(propInd), validator)
testBlock := getTestBlock(t)
testBlock.Body.RandaoReveal = testSignatureRandao
testBody := testBlock.Body

View File

@ -1,7 +1,6 @@
package transition
import (
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state"
)
@ -24,6 +23,5 @@ func ProcessRandaoMixesReset(state *state.BeaconState) {
}
func ProcessParticipationFlagUpdates(state *state.BeaconState) {
state.SetPreviousEpochParticipation(state.CurrentEpochParticipation())
state.SetCurrentEpochParticipation(make([]cltypes.ParticipationFlags, len(state.Validators())))
state.ResetEpochParticipation()
}

View File

@ -64,9 +64,8 @@ func SpawnStageBeaconsBlocks(cfg StageBeaconsBlockCfg, s *stagedsync.StageState,
log.Info(fmt.Sprintf("[%s] Started", s.LogPrefix()), "start", progress, "target", targetSlot)
cfg.downloader.SetHighestProcessedSlot(progress)
if cfg.downloader.HighestProcessedRoot() == (libcommon.Hash{}) {
cfg.downloader.SetHighestProcessedRoot(lastRoot)
}
cfg.downloader.SetHighestProcessedRoot(lastRoot)
cfg.downloader.SetTargetSlot(targetSlot)
cfg.downloader.SetLimitSegmentsLength(1024)
// On new blocks we just check slot sequencing for now :)