transition

package
v5.2.0-rc.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 9, 2024 License: GPL-3.0 Imports: 41 Imported by: 0

Documentation

Overview

Package transition implements the whole state transition function which consists of per slot, per-epoch transitions. It also bootstraps the genesis beacon state for slot 0.

Index

Constants

This section is empty.

Variables

View Source
var SkipSlotCache = cache.NewSkipSlotCache()

SkipSlotCache exists for the unlikely scenario that is a large gap between the head state and the current slot. If the beacon chain were ever to be stalled for several epochs, it may be difficult or impossible to compute the appropriate beacon state for assignments within a reasonable amount of time.

Functions

func CalculateStateRoot

func CalculateStateRoot(
	ctx context.Context,
	state state.BeaconState,
	signed interfaces.ReadOnlySignedBeaconBlock,
) ([32]byte, error)

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 (i.e. calling `state_transition()` with `validate_result=False`). 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, signed_block: ReadOnlySignedBeaconBlock, validate_result: bool=True) -> None:
  block = signed_block.message
  # Process slots (including those with no blocks) since block
  process_slots(state, block.slot)
  # Verify signature
  if validate_result:
      assert verify_block_signature(state, signed_block)
  # Process block
  process_block(state, block)
  # Verify state root
  if validate_result:
      assert block.state_root == hash_tree_root(state)

func EmptyGenesisState

func EmptyGenesisState() (state.BeaconState, error)

EmptyGenesisState returns an empty beacon state object.

func EmptyGenesisStateBellatrix

func EmptyGenesisStateBellatrix() (state.BeaconState, error)

EmptyGenesisStateBellatrix returns an empty beacon state object.

func ExecuteStateTransition

func ExecuteStateTransition(
	ctx context.Context,
	state state.BeaconState,
	signed interfaces.ReadOnlySignedBeaconBlock,
) (state.BeaconState, error)

ExecuteStateTransition defines the procedure for a state transition function.

Note: This method differs from the spec pseudocode as it uses a batch signature verification. See: ExecuteStateTransitionNoVerifyAnySig

Spec pseudocode definition:

def state_transition(state: BeaconState, signed_block: ReadOnlySignedBeaconBlock, validate_result: bool=True) -> None:
  block = signed_block.message
  # Process slots (including those with no blocks) since block
  process_slots(state, block.slot)
  # Verify signature
  if validate_result:
      assert verify_block_signature(state, signed_block)
  # Process block
  process_block(state, block)
  # Verify state root
  if validate_result:
      assert block.state_root == hash_tree_root(state)

func ExecuteStateTransitionNoVerifyAnySig

func ExecuteStateTransitionNoVerifyAnySig(
	ctx context.Context,
	st state.BeaconState,
	signed interfaces.ReadOnlySignedBeaconBlock,
) (*bls.SignatureBatch, state.BeaconState, error)

ExecuteStateTransitionNoVerifyAnySig defines the procedure for a state transition function. This does not validate any BLS signatures of attestations, block proposer signature, randao signature, it is used for performing a state transition as quickly as possible. This function also returns a signature set of all signatures not verified, so that they can be stored and verified later.

WARNING: This method does not validate any signatures (i.e. calling `state_transition()` with `validate_result=False`). This method also modifies the passed in state.

Spec pseudocode definition:

def state_transition(state: BeaconState, signed_block: ReadOnlySignedBeaconBlock, validate_result: bool=True) -> None:
  block = signed_block.message
  # Process slots (including those with no blocks) since block
  process_slots(state, block.slot)
  # Verify signature
  if validate_result:
      assert verify_block_signature(state, signed_block)
  # Process block
  process_block(state, block)
  # Verify state root
  if validate_result:
      assert block.state_root == hash_tree_root(state)

func GenesisBeaconState

func GenesisBeaconState(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data) (state.BeaconState, error)

GenesisBeaconState gets called when MinGenesisActiveValidatorCount count of full deposits were made to the deposit contract and the ChainStart log gets emitted.

Spec pseudocode definition:

def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
                                    eth1_timestamp: uint64,
                                    deposits: Sequence[Deposit]) -> BeaconState:
  fork = Fork(
      previous_version=GENESIS_FORK_VERSION,
      current_version=GENESIS_FORK_VERSION,
      epoch=GENESIS_EPOCH,
  )
  state = BeaconState(
      genesis_time=eth1_timestamp + GENESIS_DELAY,
      fork=fork,
      eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
      latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
      randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR,  # Seed RANDAO with Eth1 entropy
  )

  # Process deposits
  leaves = list(map(lambda deposit: deposit.data, deposits))
  for index, deposit in enumerate(deposits):
      deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
      state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
      process_deposit(state, deposit)

  # Process activations
  for index, validator in enumerate(state.validators):
      balance = state.balances[index]
      validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
      if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
          validator.activation_eligibility_epoch = GENESIS_EPOCH
          validator.activation_epoch = GENESIS_EPOCH

  # Set genesis validators root for domain separation and chain versioning
  state.genesis_validators_root = hash_tree_root(state.validators)

  return state

This method differs from the spec so as to process deposits beforehand instead of the end of the function.

func GenesisBeaconStateBellatrix

func GenesisBeaconStateBellatrix(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data, ep *enginev1.ExecutionPayload) (state.BeaconState, error)

GenesisBeaconStateBellatrix gets called when MinGenesisActiveValidatorCount count of full deposits were made to the deposit contract and the ChainStart log gets emitted.

Spec pseudocode definition:

def initialize_beacon_state_from_eth1(eth1_block_hash: Bytes32,
                                    eth1_timestamp: uint64,
                                    deposits: Sequence[Deposit]) -> BeaconState:
  fork = Fork(
      previous_version=GENESIS_FORK_VERSION,
      current_version=GENESIS_FORK_VERSION,
      epoch=GENESIS_EPOCH,
  )
  state = BeaconState(
      genesis_time=eth1_timestamp + GENESIS_DELAY,
      fork=fork,
      eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
      latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
      randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR,  # Seed RANDAO with Eth1 entropy
  )

  # Process deposits
  leaves = list(map(lambda deposit: deposit.data, deposits))
  for index, deposit in enumerate(deposits):
      deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
      state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
      process_deposit(state, deposit)

  # Process activations
  for index, validator in enumerate(state.validators):
      balance = state.balances[index]
      validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE)
      if validator.effective_balance == MAX_EFFECTIVE_BALANCE:
          validator.activation_eligibility_epoch = GENESIS_EPOCH
          validator.activation_epoch = GENESIS_EPOCH

  # Set genesis validators root for domain separation and chain versioning
  state.genesis_validators_root = hash_tree_root(state.validators)

  return state

This method differs from the spec so as to process deposits beforehand instead of the end of the function.

func IsValidGenesisState

func IsValidGenesisState(chainStartDepositCount, currentTime uint64) bool

IsValidGenesisState gets called whenever there's a deposit event, it checks whether there's enough effective balance to trigger and if the minimum genesis time arrived already.

Spec pseudocode definition:

def is_valid_genesis_state(state: BeaconState) -> bool:
   if state.genesis_time < MIN_GENESIS_TIME:
       return False
   if len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
       return False
   return True

This method has been modified from the spec to allow whole states not to be saved but instead only cache the relevant information.

func LastCachedState

func LastCachedState() ([]byte, state.BeaconState)

LastCachedState returns the last cached state and root in the cache

func NextSlotState

func NextSlotState(root []byte, wantedSlot types.Slot) state.BeaconState

NextSlotState returns the saved state for the given blockroot. It returns the last updated state if it matches. Otherwise it returns the previously updated state if it matches its root. If no root matches it returns nil

func OptimizedGenesisBeaconState

func OptimizedGenesisBeaconState(genesisTime uint64, preState state.BeaconState, eth1Data *ethpb.Eth1Data) (state.BeaconState, error)

OptimizedGenesisBeaconState is used to create a state that has already processed deposits. This is to efficiently create a mainnet state at chainstart.

func OptimizedGenesisBeaconStateBellatrix

func OptimizedGenesisBeaconStateBellatrix(genesisTime uint64, preState state.BeaconState, eth1Data *ethpb.Eth1Data, ep *enginev1.ExecutionPayload) (state.BeaconState, error)

OptimizedGenesisBeaconStateBellatrix is used to create a state that has already processed deposits. This is to efficiently create a mainnet state at chainstart.

func PreminedGenesisBeaconState

func PreminedGenesisBeaconState(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data) (state.BeaconState, error)

PreminedGenesisBeaconState works almost exactly like GenesisBeaconState, except that it assumes that genesis deposits are not represented in the deposit contract and are only found in the genesis state validator registry. In order to ensure the deposit root and count match the empty deposit contract deployed in a testnet genesis block, the root of an empty deposit trie is computed and used as Eth1Data.deposit_root, and the deposit count is set to 0.

func ProcessBlockForStateRoot

func ProcessBlockForStateRoot(
	ctx context.Context,
	state state.BeaconState,
	signed interfaces.ReadOnlySignedBeaconBlock,
) (state.BeaconState, error)

ProcessBlockForStateRoot processes the state for state root computation. It skips proposer signature and randao signature verifications.

Spec pseudocode definition: def process_block(state: BeaconState, block: ReadOnlyBeaconBlock) -> None:

process_block_header(state, block)
if is_execution_enabled(state, block.body):
    process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE)  # [New in Bellatrix]
process_randao(state, block.body)
process_eth1_data(state, block.body)
process_operations(state, block.body)
process_sync_aggregate(state, block.body.sync_aggregate)

func ProcessBlockNoVerifyAnySig

func ProcessBlockNoVerifyAnySig(
	ctx context.Context,
	st state.BeaconState,
	signed interfaces.ReadOnlySignedBeaconBlock,
) (*bls.SignatureBatch, state.BeaconState, error)

ProcessBlockNoVerifyAnySig creates a new, modified beacon state by applying block operation transformations as defined in the Ethereum Serenity specification. It does not validate any block signature except for deposit and slashing signatures. It also returns the relevant signature set from all the respective methods.

Spec pseudocode definition:

def process_block(state: BeaconState, block: ReadOnlyBeaconBlock) -> None:
  process_block_header(state, block)
  process_randao(state, block.body)
  process_eth1_data(state, block.body)
  process_operations(state, block.body)

func ProcessEpoch added in v5.1.0

func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconState, error)

ProcessEpoch is a wrapper on fork specific epoch processing

func ProcessEpochPrecompute

func ProcessEpochPrecompute(ctx context.Context, state state.BeaconState) (state.BeaconState, error)

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 ProcessOperationsNoVerifyAttsSigs

func ProcessOperationsNoVerifyAttsSigs(
	ctx context.Context,
	state state.BeaconState,
	beaconBlock interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error)

ProcessOperationsNoVerifyAttsSigs processes the operations in the beacon block and updates beacon state with the operations in block. It does not verify attestation signatures.

WARNING: This method does not verify attestation signatures. This is used to perform the block operations as fast as possible.

Spec pseudocode definition:

def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
    # [Modified in Electra:EIP6110]
    # Disable former deposit mechanism once all prior deposits are processed
    eth1_deposit_index_limit = min(state.eth1_data.deposit_count, state.deposit_requests_start_index)
    if state.eth1_deposit_index < eth1_deposit_index_limit:
        assert len(body.deposits) == min(MAX_DEPOSITS, eth1_deposit_index_limit - state.eth1_deposit_index)
    else:
        assert len(body.deposits) == 0

    def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
        for operation in operations:
            fn(state, operation)

    for_ops(body.proposer_slashings, process_proposer_slashing)
    for_ops(body.attester_slashings, process_attester_slashing)
    for_ops(body.attestations, process_attestation)  # [Modified in Electra:EIP7549]
    for_ops(body.deposits, process_deposit)  # [Modified in Electra:EIP7251]
    for_ops(body.voluntary_exits, process_voluntary_exit)  # [Modified in Electra:EIP7251]
    for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
    # [New in Electra:EIP7002:EIP7251]
    for_ops(body.execution_payload.withdrawal_requests, process_execution_layer_withdrawal_request)
    for_ops(body.execution_payload.deposit_requests, process_deposit_requests)  # [New in Electra:EIP6110]
    for_ops(body.consolidations, process_consolidation)  # [New in Electra:EIP7251]

func ProcessSlot

func ProcessSlot(ctx context.Context, state state.BeaconState) (state.BeaconState, error)

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 = hash_tree_root(state.latest_block_header)
  state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root

func ProcessSlots

func ProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.Slot) (state.BeaconState, error)

ProcessSlots includes core slot processing as well as a cache

func ProcessSlotsCore added in v5.1.0

func ProcessSlotsCore(ctx context.Context, span trace.Span, state state.BeaconState, slot primitives.Slot, fn customProcessingFn) (state.BeaconState, error)

ProcessSlotsCore process through skip slots 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 start slot of the next epoch
      if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
          process_epoch(state)
      state.slot = Slot(state.slot + 1)

func ProcessSlotsIfPossible

func ProcessSlotsIfPossible(ctx context.Context, state state.BeaconState, targetSlot primitives.Slot) (state.BeaconState, error)

ProcessSlotsIfPossible executes ProcessSlots on the input state when target slot is above the state's slot. Otherwise, it returns the input state unchanged.

func ProcessSlotsUsingNextSlotCache

func ProcessSlotsUsingNextSlotCache(
	ctx context.Context,
	parentState state.BeaconState,
	parentRoot []byte,
	slot primitives.Slot) (state.BeaconState, error)

ProcessSlotsUsingNextSlotCache processes slots by using next slot cache for higher efficiency.

func UpdateNextSlotCache

func UpdateNextSlotCache(ctx context.Context, root []byte, state state.BeaconState) error

UpdateNextSlotCache updates the `nextSlotCache`. It saves the input state after advancing the state slot by 1 by calling `ProcessSlots`, it also saves the input root for later look up. This is useful to call after successfully processing a block.

func UpgradeState

func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconState, error)

UpgradeState upgrades the state to the next version if possible.

func VerifyOperationLengths

func VerifyOperationLengths(_ context.Context, state state.BeaconState, b interfaces.ReadOnlyBeaconBlock) (state.BeaconState, error)

VerifyOperationLengths verifies that block operation lengths are valid.

Types

This section is empty.

Directories

Path Synopsis
Package interop contains useful utilities for persisting ssz-encoded states and blocks to disk during each state transition for development purposes.
Package interop contains useful utilities for persisting ssz-encoded states and blocks to disk during each state transition for development purposes.
Package stateutils contains useful tools for faster computation of state transitions using maps to represent validators instead of slices.
Package stateutils contains useful tools for faster computation of state transitions using maps to represent validators instead of slices.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL