prysm-pulse/beacon-chain/core/state/transition.go
Raul Jordan cc741ed8af
Ensure New State Type Tests Pass in Prysm (#4646)
* begin state service

* begin on the state trie idea

* created beacon state structure

* add in the full clone getter

* return by value instead

* add all setters

* new state setters are being completed

* arrays roots exposed

*  close to finishing all these headerssss

* functionality complete

* added in proto benchmark test

* test for compatibility

* add test for compat

* comments fixed

* add clone

* add clone

* remove underlying copies

* make it immutable

* integrate it into chainservice

* revert

* wrap up comments for package

* address all comments and godocs

* address all comments

* clone the pending attestation properly

* properly clone remaining items

* tests pass fixed bug

* begin using it instead of head state

* prevent nil pointer exceptions

* begin using new struct in db

* integrated new type into db package

* add proper nil checks

* using new state in archiver

* refactored much of core

* editing all the precompute functions

* done with most core refactor

* fixed up some bugs in the clone comparisons

* append current epoch atts

* add missing setters

* add new setters

* fix other core methods

* fix up transition

* main service and forkchoice

* fix rpc

* integrated to powchain

* some more changes

* fix build

* improve processing of deposits

* fix error

* prevent panic

* comment

* fix process att

* gaz

* fix up att process

* resolve existing review comments

* resolve another batch of gh comments

* resolve broken cpt state

* revise testutil to use the new state

* begin updating the state transition func to pass in more compartmentalized args

* finish editing transition function to return errors

* block operations pretty much done with refactor

* state transition fully refactored

* got epoch processing completed

* fix build in fork choice

* fixing more of the build

* fix up broken sync package

* it builds nowww it buildssss

* revert registry changes

* Recompute on Read (#4627)

* compute on read

* fix up eth1 data votes

* looking into slashings bug introduced in core/

* able to advance more slots

* add logging

* can now sync with testnet yay

* remove the leaves algorithm and other merkle imports

* expose initialize unsafe funcs

* Update beacon-chain/db/kv/state.go

* lint

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* More Optimizations for New State (#4641)

* map optimization

* more optimizations

* use a custom hasher

* comment

* block operations optimizations

* Update beacon-chain/state/types.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* fixed up various operations to use the validator index map access

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* archiver tests pass

* fixing cache tests

* cache tests passing

* edited validator tests

* powchain tests passing

* halfway thru sync tests

* more sync test fixes

* add in tests for state/

* working through rpc tests

* assignments tests passed

* almost done with rpc/beacon tests

* resolved painful validator test

* fixed up even more tests

* resolve tests

* fix build

* reduce a randao mixes copy

* fixes under //beacon-chain/blockchain/...

* build //beacon-chain/core/...

* fixes

* Runtime Optimizations (#4648)

* parallelize shuffling

* clean up

* lint

* fix build

* use callback to read from registry

* fix array roots and size map

* new improvements

* reduce hash allocs

* improved shuffling

* terence's review

* use different method

* raul's comment

* new array roots

* remove clone in pre-compute

* Update beacon-chain/state/types.go

Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com>

* raul's review

* lint

* fix build issues

* fix visibility

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* fix visibility

* build works for all

* fix blockchain test

* fix a few tests

* fix more tests

* update validator in slashing

* archiver passing

* fixed rpc/validator

* progress on core tests

* resolve broken rpc tests

* blockchain tests passed

* fix up some tests in core

* fix message diff

* remove unnecessary save

* Save validator after slashing

* Update validators one by one

* another update

* fix everything

* fix more precompute tests

* fix blocks tests

* more elegant fix

* more helper fixes

* change back ?

* fix test

* fix skip slot

* fix test

* reset caches

* fix testutil

* raceoff fixed

* passing

* Retrieve cached state in the beginning

* lint

* Fixed tests part 1

* Fixed rest of the tests

* Minor changes to avoid copying, small refactor to reduce deplicated code

* Handle att req for slot 0

* New beacon state: Only populate merkle layers as needed, copy merkle layers on copy/clone. (#4689)

* Only populate merkle layers as needed, copy merkle layers on copy/clone.

* use custom copy

* Make maps of correct size

* slightly fast, doesn't wait for lock

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>

* Target root can't be 0x00

* Don't use cache for current slot (may not be the right fix)

* fixed up tests

* Remove some copy for init sync. Not sure if it is safe enough for runtime though... testing...

* Align with prev logic for process slots cachedState.Slot() < slot

* Fix Initial Sync Flag (#4692)

* fixes

* fix up some test failures due to lack of nil checks

* fix up some test failures due to lack of nil checks

* fix up imports

* revert some changes

* imports

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* resolving further conflicts

* Better skip slot cache (#4694)

* Return copy of skip slot cache state, disable skip slot cache on sync

* fix

* Fix pruning

* fix up issues with broken tests

Co-authored-by: Nishant Das <nish1993@hotmail.com>
Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
Co-authored-by: shayzluf <thezluf@gmail.com>
Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2020-01-31 12:57:01 -08:00

661 lines
22 KiB
Go

// Package state implements the whole state transition
// function which consists of per slot, per-epoch transitions.
// It also bootstraps the genesis beacon state for slot 0.
package state
import (
"bytes"
"context"
"fmt"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
e "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state/interop"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/mathutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/stateutil"
"github.com/prysmaticlabs/prysm/shared/traceutil"
"go.opencensus.io/trace"
)
// ExecuteStateTransition defines the procedure for a state transition function.
//
// Spec pseudocode definition:
// def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState:
// # Process slots (including those with no blocks) since block
// process_slots(state, block.slot)
// # Process block
// process_block(state, block)
// # Validate state root (`validate_state_root == True` in production)
// if validate_state_root:
// assert block.state_root == hash_tree_root(state)
// # Return post-state
// return state
func ExecuteStateTransition(
ctx context.Context,
state *stateTrie.BeaconState,
signed *ethpb.SignedBeaconBlock,
) (*stateTrie.BeaconState, error) {
if ctx.Err() != nil {
return nil, ctx.Err()
}
if signed == nil || signed.Block == nil {
return nil, errors.New("nil block")
}
b.ClearEth1DataVoteCache()
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.ExecuteStateTransition")
defer span.End()
var err error
// Execute per slots transition.
state, err = ProcessSlots(ctx, state, signed.Block.Slot)
if err != nil {
return nil, errors.Wrap(err, "could not process slot")
}
// Execute per block transition.
state, err = ProcessBlock(ctx, state, signed)
if err != nil {
return nil, errors.Wrapf(err, "could not process block in slot %d", signed.Block.Slot)
}
interop.WriteBlockToDisk(signed, false)
interop.WriteStateToDisk(state)
postStateRoot, err := state.HashTreeRoot()
if err != nil {
return nil, err
}
if !bytes.Equal(postStateRoot[:], signed.Block.StateRoot) {
return state, fmt.Errorf("validate state root failed, wanted: %#x, received: %#x",
postStateRoot[:], signed.Block.StateRoot)
}
return state, nil
}
// ExecuteStateTransitionNoVerifyAttSigs defines the procedure for a state transition function.
// This does not validate any BLS signatures of attestations in a block, it is used for performing a state transition as quickly
// as possible. This function should only be used when we can trust the data we're receiving entirely, such as
// initial sync or for processing past accepted blocks.
//
// WARNING: This method does not validate any signatures in a block. This method also modifies the passed in state.
//
// Spec pseudocode definition:
// def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState:
// # Process slots (including those with no blocks) since block
// process_slots(state, block.slot)
// # Process block
// process_block(state, block)
// # Return post-state
// return state
func ExecuteStateTransitionNoVerifyAttSigs(
ctx context.Context,
state *stateTrie.BeaconState,
signed *ethpb.SignedBeaconBlock,
) (*stateTrie.BeaconState, error) {
if ctx.Err() != nil {
return nil, ctx.Err()
}
if signed == nil || signed.Block == nil {
return nil, errors.New("nil block")
}
b.ClearEth1DataVoteCache()
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.ExecuteStateTransitionNoVerifyAttSigs")
defer span.End()
var err error
// Execute per slots transition.
state, err = ProcessSlots(ctx, state, signed.Block.Slot)
if err != nil {
return nil, errors.Wrap(err, "could not process slot")
}
// Execute per block transition.
state, err = processBlockNoVerifyAttSigs(ctx, state, signed)
if err != nil {
return nil, errors.Wrap(err, "could not process block")
}
return state, nil
}
// CalculateStateRoot defines the procedure for a state transition function.
// This does not validate any BLS signatures in a block, it is used for calculating the
// state root of the state for the block proposer to use.
// This does not modify state.
//
// WARNING: This method does not validate any BLS signatures. This is used for proposer to compute
// state root before proposing a new block, and this does not modify state.
//
// Spec pseudocode definition:
// def state_transition(state: BeaconState, block: BeaconBlock, validate_state_root: bool=False) -> BeaconState:
// # Process slots (including those with no blocks) since block
// process_slots(state, block.slot)
// # Process block
// process_block(state, block)
// # Return post-state
// return state
func CalculateStateRoot(
ctx context.Context,
state *stateTrie.BeaconState,
signed *ethpb.SignedBeaconBlock,
) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.CalculateStateRoot")
defer span.End()
if ctx.Err() != nil {
traceutil.AnnotateError(span, ctx.Err())
return [32]byte{}, ctx.Err()
}
if signed == nil || signed.Block == nil {
return [32]byte{}, errors.New("nil block")
}
// Copy state to avoid mutating the state reference.
state = state.Copy()
b.ClearEth1DataVoteCache()
// Execute per slots transition.
state, err := ProcessSlots(ctx, state, signed.Block.Slot)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not process slot")
}
// Execute per block transition.
state, err = computeStateRoot(ctx, state, signed)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not process block")
}
return state.HashTreeRoot()
}
// ProcessSlot happens every slot and focuses on the slot counter and block roots record updates.
// It happens regardless if there's an incoming block or not.
// Spec pseudocode definition:
//
// def process_slot(state: BeaconState) -> None:
// # Cache state root
// previous_state_root = hash_tree_root(state)
// state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root
//
// # Cache latest block header state root
// if state.latest_block_header.state_root == Bytes32():
// state.latest_block_header.state_root = previous_state_root
//
// # Cache block root
// previous_block_root = signing_root(state.latest_block_header)
// state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
func ProcessSlot(ctx context.Context, state *stateTrie.BeaconState) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessSlot")
defer span.End()
span.AddAttributes(trace.Int64Attribute("slot", int64(state.Slot())))
prevStateRoot, err := state.HashTreeRoot()
if err != nil {
return nil, err
}
if err := state.UpdateStateRootAtIndex(
state.Slot()%params.BeaconConfig().SlotsPerHistoricalRoot,
prevStateRoot,
); err != nil {
return nil, err
}
zeroHash := params.BeaconConfig().ZeroHash
// Cache latest block header state root.
header := state.LatestBlockHeader()
if header.StateRoot == nil || bytes.Equal(header.StateRoot, zeroHash[:]) {
header.StateRoot = prevStateRoot[:]
if err := state.SetLatestBlockHeader(header); err != nil {
return nil, err
}
}
prevBlockRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not determine prev block root")
}
// Cache the block root.
if err := state.UpdateBlockRootAtIndex(
state.Slot()%params.BeaconConfig().SlotsPerHistoricalRoot,
prevBlockRoot,
); err != nil {
return nil, err
}
return state, nil
}
// ProcessSlots process through skip skips and apply epoch transition when it's needed
//
// Spec pseudocode definition:
// def process_slots(state: BeaconState, slot: Slot) -> None:
// assert state.slot <= slot
// while state.slot < slot:
// process_slot(state)
// # Process epoch on the first slot of the next epoch
// if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
// process_epoch(state)
// state.slot += 1
// ]
func ProcessSlots(ctx context.Context, state *stateTrie.BeaconState, slot uint64) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.ProcessSlots")
defer span.End()
span.AddAttributes(trace.Int64Attribute("slots", int64(slot)-int64(state.Slot())))
if state.Slot() > slot {
err := fmt.Errorf("expected state.slot %d < slot %d", state.Slot(), slot)
traceutil.AnnotateError(span, err)
return nil, err
}
if state.Slot() == slot {
return state, nil
}
highestSlot := state.Slot()
key := state.Slot()
// Restart from cached value, if one exists.
cachedState, err := skipSlotCache.Get(ctx, key)
if err != nil {
return nil, err
}
if cachedState != nil && cachedState.Slot() < slot {
highestSlot = cachedState.Slot()
state = cachedState
}
if err := skipSlotCache.MarkInProgress(key); err == cache.ErrAlreadyInProgress {
cachedState, err = skipSlotCache.Get(ctx, key)
if err != nil {
return nil, err
}
if cachedState != nil && cachedState.Slot() < slot {
highestSlot = cachedState.Slot()
state = cachedState
}
} else if err != nil {
return nil, err
}
defer skipSlotCache.MarkNotInProgress(key)
for state.Slot() < slot {
if ctx.Err() != nil {
traceutil.AnnotateError(span, ctx.Err())
// Cache last best value.
if highestSlot < state.Slot() {
skipSlotCache.Put(ctx, key, state)
}
return nil, ctx.Err()
}
state, err = ProcessSlot(ctx, state)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process slot")
}
if CanProcessEpoch(state) {
state, err = ProcessEpochPrecompute(ctx, state)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process epoch with optimizations")
}
}
state.SetSlot(state.Slot() + 1)
}
if highestSlot < state.Slot() {
skipSlotCache.Put(ctx, key, state)
}
return state, nil
}
// ProcessBlock creates a new, modified beacon state by applying block operation
// transformations as defined in the Ethereum Serenity specification, including processing proposer slashings,
// processing block attestations, and more.
//
// Spec pseudocode definition:
//
// def process_block(state: BeaconState, block: BeaconBlock) -> None:
// process_block_header(state, block)
// process_randao(state, block.body)
// process_eth1_data(state, block.body)
// process_operations(state, block.body)
func ProcessBlock(
ctx context.Context,
state *stateTrie.BeaconState,
signed *ethpb.SignedBeaconBlock,
) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessBlock")
defer span.End()
state, err := b.ProcessBlockHeader(state, signed)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process block header")
}
state, err = b.ProcessRandao(state, signed.Block.Body)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not verify and process randao")
}
state, err = b.ProcessEth1DataInBlock(state, signed.Block)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process eth1 data")
}
state, err = ProcessOperations(ctx, state, signed.Block.Body)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process block operation")
}
return state, nil
}
// processBlockNoVerifyAttSigs creates a new, modified beacon state by applying block operation
// transformations as defined in the Ethereum Serenity specification. It does not validate
// block attestation signatures.
//
// Spec pseudocode definition:
//
// def process_block(state: BeaconState, block: BeaconBlock) -> None:
// process_block_header(state, block)
// process_randao(state, block.body)
// process_eth1_data(state, block.body)
// process_operations(state, block.body)
func processBlockNoVerifyAttSigs(
ctx context.Context,
state *stateTrie.BeaconState,
signed *ethpb.SignedBeaconBlock,
) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessBlock")
defer span.End()
state, err := b.ProcessBlockHeader(state, signed)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process block header")
}
state, err = b.ProcessRandao(state, signed.Block.Body)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not verify and process randao")
}
state, err = b.ProcessEth1DataInBlock(state, signed.Block)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process eth1 data")
}
state, err = processOperationsNoVerify(ctx, state, signed.Block.Body)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process block operation")
}
return state, nil
}
// ProcessOperations processes the operations in the beacon block and updates beacon state
// with the operations in block.
//
// Spec pseudocode definition:
//
// def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
// # Verify that outstanding deposits are processed up to the maximum number of deposits
// assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
// # Verify that there are no duplicate transfers
// assert len(body.transfers) == len(set(body.transfers))
//
// all_operations = (
// (body.proposer_slashings, process_proposer_slashing),
// (body.attester_slashings, process_attester_slashing),
// (body.attestations, process_attestation),
// (body.deposits, process_deposit),
// (body.voluntary_exits, process_voluntary_exit),
// (body.transfers, process_transfer),
// ) # type: Sequence[Tuple[List, Callable]]
// for operations, function in all_operations:
// for operation in operations:
// function(state, operation)
func ProcessOperations(
ctx context.Context,
state *stateTrie.BeaconState,
body *ethpb.BeaconBlockBody) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessOperations")
defer span.End()
if err := verifyOperationLengths(state, body); err != nil {
return nil, errors.Wrap(err, "could not verify operation lengths")
}
state, err := b.ProcessProposerSlashings(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block proposer slashings")
}
state, err = b.ProcessAttesterSlashings(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block attester slashings")
}
state, err = b.ProcessAttestations(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block attestations")
}
state, err = b.ProcessDeposits(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block validator deposits")
}
state, err = b.ProcessVoluntaryExits(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process validator exits")
}
return state, nil
}
// processOperationsNoVerify processes the operations in the beacon block and updates beacon state
// with the operations in block. It does not verify attestation signatures or voluntary exit signatures.
//
// WARNING: This method does not verify attestation signatures or voluntary exit signatures.
// This is used to perform the block operations as fast as possible.
//
// Spec pseudocode definition:
//
// def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
// # Verify that outstanding deposits are processed up to the maximum number of deposits
// assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)
// # Verify that there are no duplicate transfers
// assert len(body.transfers) == len(set(body.transfers))
//
// all_operations = (
// (body.proposer_slashings, process_proposer_slashing),
// (body.attester_slashings, process_attester_slashing),
// (body.attestations, process_attestation),
// (body.deposits, process_deposit),
// (body.voluntary_exits, process_voluntary_exit),
// (body.transfers, process_transfer),
// ) # type: Sequence[Tuple[List, Callable]]
// for operations, function in all_operations:
// for operation in operations:
// function(state, operation)
func processOperationsNoVerify(
ctx context.Context,
state *stateTrie.BeaconState,
body *ethpb.BeaconBlockBody) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessOperations")
defer span.End()
if err := verifyOperationLengths(state, body); err != nil {
return nil, errors.Wrap(err, "could not verify operation lengths")
}
state, err := b.ProcessProposerSlashings(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block proposer slashings")
}
state, err = b.ProcessAttesterSlashings(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block attester slashings")
}
state, err = b.ProcessAttestationsNoVerify(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block attestations")
}
state, err = b.ProcessDeposits(ctx, state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process block validator deposits")
}
state, err = b.ProcessVoluntaryExitsNoVerify(state, body)
if err != nil {
return nil, errors.Wrap(err, "could not process validator exits")
}
return state, nil
}
func verifyOperationLengths(state *stateTrie.BeaconState, body *ethpb.BeaconBlockBody) error {
if uint64(len(body.ProposerSlashings)) > params.BeaconConfig().MaxProposerSlashings {
return fmt.Errorf(
"number of proposer slashings (%d) in block body exceeds allowed threshold of %d",
len(body.ProposerSlashings),
params.BeaconConfig().MaxProposerSlashings,
)
}
if uint64(len(body.AttesterSlashings)) > params.BeaconConfig().MaxAttesterSlashings {
return fmt.Errorf(
"number of attester slashings (%d) in block body exceeds allowed threshold of %d",
len(body.AttesterSlashings),
params.BeaconConfig().MaxAttesterSlashings,
)
}
if uint64(len(body.Attestations)) > params.BeaconConfig().MaxAttestations {
return fmt.Errorf(
"number of attestations (%d) in block body exceeds allowed threshold of %d",
len(body.Attestations),
params.BeaconConfig().MaxAttestations,
)
}
if uint64(len(body.VoluntaryExits)) > params.BeaconConfig().MaxVoluntaryExits {
return fmt.Errorf(
"number of voluntary exits (%d) in block body exceeds allowed threshold of %d",
len(body.VoluntaryExits),
params.BeaconConfig().MaxVoluntaryExits,
)
}
if state.Eth1DepositIndex() > state.Eth1Data().DepositCount {
return fmt.Errorf("expected state.deposit_index %d <= eth1data.deposit_count %d", state.Eth1DepositIndex(), state.Eth1Data().DepositCount)
}
maxDeposits := mathutil.Min(params.BeaconConfig().MaxDeposits, state.Eth1Data().DepositCount-state.Eth1DepositIndex())
// Verify outstanding deposits are processed up to max number of deposits
if len(body.Deposits) != int(maxDeposits) {
return fmt.Errorf("incorrect outstanding deposits in block body, wanted: %d, got: %d",
maxDeposits, len(body.Deposits))
}
return nil
}
// CanProcessEpoch checks the eligibility to process epoch.
// The epoch can be processed at the end of the last slot of every epoch
//
// Spec pseudocode definition:
// If (state.slot + 1) % SLOTS_PER_EPOCH == 0:
func CanProcessEpoch(state *stateTrie.BeaconState) bool {
return (state.Slot()+1)%params.BeaconConfig().SlotsPerEpoch == 0
}
// ProcessEpochPrecompute describes the per epoch operations that are performed on the beacon state.
// It's optimized by pre computing validator attested info and epoch total/attested balances upfront.
func ProcessEpochPrecompute(ctx context.Context, state *stateTrie.BeaconState) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessEpoch")
defer span.End()
span.AddAttributes(trace.Int64Attribute("epoch", int64(helpers.CurrentEpoch(state))))
vp, bp := precompute.New(ctx, state)
vp, bp, err := precompute.ProcessAttestations(ctx, state, vp, bp)
if err != nil {
return nil, err
}
state, err = precompute.ProcessJustificationAndFinalizationPreCompute(state, bp)
if err != nil {
return nil, errors.Wrap(err, "could not process justification")
}
state, err = precompute.ProcessRewardsAndPenaltiesPrecompute(state, bp, vp)
if err != nil {
return nil, errors.Wrap(err, "could not process rewards and penalties")
}
state, err = e.ProcessRegistryUpdates(state)
if err != nil {
return nil, errors.Wrap(err, "could not process registry updates")
}
err = precompute.ProcessSlashingsPrecompute(state, bp)
if err != nil {
return nil, err
}
state, err = e.ProcessFinalUpdates(state)
if err != nil {
return nil, errors.Wrap(err, "could not process final updates")
}
return state, nil
}
// computeStateRoot computes the state root of the block without verifying proposer signature
// and randao.
func computeStateRoot(
ctx context.Context,
state *stateTrie.BeaconState,
signed *ethpb.SignedBeaconBlock,
) (*stateTrie.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.ChainService.state.ProcessBlock")
defer span.End()
state, err := b.ProcessBlockHeaderNoVerify(state, signed.Block)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process block header")
}
state, err = b.ProcessRandaoNoVerify(state, signed.Block.Body)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not verify and process randao")
}
state, err = b.ProcessEth1DataInBlock(state, signed.Block)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process eth1 data")
}
state, err = processOperationsNoVerify(ctx, state, signed.Block.Body)
if err != nil {
traceutil.AnnotateError(span, err)
return nil, errors.Wrap(err, "could not process block operation")
}
return state, nil
}