github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/state/transition.go (about)

     1  // Package state implements the whole state transition
     2  // function which consists of per slot, per-epoch transitions.
     3  // It also bootstraps the genesis beacon state for slot 0.
     4  package state
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  
    11  	"github.com/pkg/errors"
    12  	types "github.com/prysmaticlabs/eth2-types"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/cache"
    14  	b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
    15  	e "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
    16  	"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    18  	v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
    19  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    20  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    21  	"github.com/prysmaticlabs/prysm/shared/mathutil"
    22  	"github.com/prysmaticlabs/prysm/shared/params"
    23  	"github.com/prysmaticlabs/prysm/shared/traceutil"
    24  	"go.opencensus.io/trace"
    25  )
    26  
    27  // processFunc is a function that processes a block with a given state. State is mutated.
    28  type processFunc func(context.Context, iface.BeaconState, interfaces.SignedBeaconBlock) (iface.BeaconState, error)
    29  
    30  var processDepositsFunc = func(ctx context.Context, s iface.BeaconState, blk interfaces.SignedBeaconBlock) (iface.BeaconState, error) {
    31  	return b.ProcessDeposits(ctx, s, blk.Block().Body().Deposits())
    32  }
    33  var processProposerSlashingFunc = func(ctx context.Context, s iface.BeaconState, blk interfaces.SignedBeaconBlock) (iface.BeaconState, error) {
    34  	return b.ProcessProposerSlashings(ctx, s, blk.Block().Body().ProposerSlashings(), v.SlashValidator)
    35  }
    36  
    37  var processAttesterSlashingFunc = func(ctx context.Context, s iface.BeaconState, blk interfaces.SignedBeaconBlock) (iface.BeaconState, error) {
    38  	return b.ProcessAttesterSlashings(ctx, s, blk.Block().Body().AttesterSlashings(), v.SlashValidator)
    39  }
    40  
    41  var processEth1DataFunc = func(ctx context.Context, s iface.BeaconState, blk interfaces.SignedBeaconBlock) (iface.BeaconState, error) {
    42  	return b.ProcessEth1DataInBlock(ctx, s, blk.Block().Body().Eth1Data())
    43  }
    44  
    45  var processExitFunc = func(ctx context.Context, s iface.BeaconState, blk interfaces.SignedBeaconBlock) (iface.BeaconState, error) {
    46  	return b.ProcessVoluntaryExits(ctx, s, blk.Block().Body().VoluntaryExits())
    47  }
    48  
    49  // This defines the processing block routine as outlined in the Ethereum Beacon Chain spec:
    50  // https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#block-processing
    51  var processingPipeline = []processFunc{
    52  	b.ProcessBlockHeader,
    53  	b.ProcessRandao,
    54  	processEth1DataFunc,
    55  	VerifyOperationLengths,
    56  	processProposerSlashingFunc,
    57  	processAttesterSlashingFunc,
    58  	b.ProcessAttestations,
    59  	processDepositsFunc,
    60  	processExitFunc,
    61  }
    62  
    63  // ExecuteStateTransition defines the procedure for a state transition function.
    64  //
    65  // Note: This method differs from the spec pseudocode as it uses a batch signature verification.
    66  // See: ExecuteStateTransitionNoVerifyAnySig
    67  //
    68  // Spec pseudocode definition:
    69  //  def state_transition(state: BeaconState, signed_block: SignedBeaconBlock, validate_result: bool=True) -> None:
    70  //    block = signed_block.message
    71  //    # Process slots (including those with no blocks) since block
    72  //    process_slots(state, block.slot)
    73  //    # Verify signature
    74  //    if validate_result:
    75  //        assert verify_block_signature(state, signed_block)
    76  //    # Process block
    77  //    process_block(state, block)
    78  //    # Verify state root
    79  //    if validate_result:
    80  //        assert block.state_root == hash_tree_root(state)
    81  func ExecuteStateTransition(
    82  	ctx context.Context,
    83  	state iface.BeaconState,
    84  	signed interfaces.SignedBeaconBlock,
    85  ) (iface.BeaconState, error) {
    86  	if ctx.Err() != nil {
    87  		return nil, ctx.Err()
    88  	}
    89  	if signed == nil || signed.IsNil() || signed.Block().IsNil() {
    90  		return nil, errors.New("nil block")
    91  	}
    92  
    93  	ctx, span := trace.StartSpan(ctx, "core.state.ExecuteStateTransition")
    94  	defer span.End()
    95  	var err error
    96  
    97  	set, postState, err := ExecuteStateTransitionNoVerifyAnySig(ctx, state, signed)
    98  	if err != nil {
    99  		return nil, errors.Wrap(err, "could not execute state transition")
   100  	}
   101  	valid, err := set.Verify()
   102  	if err != nil {
   103  		return nil, errors.Wrap(err, "could not batch verify signature")
   104  	}
   105  	if !valid {
   106  		return nil, errors.New("signature in block failed to verify")
   107  	}
   108  
   109  	return postState, nil
   110  }
   111  
   112  // ProcessSlot happens every slot and focuses on the slot counter and block roots record updates.
   113  // It happens regardless if there's an incoming block or not.
   114  // Spec pseudocode definition:
   115  //
   116  //  def process_slot(state: BeaconState) -> None:
   117  //    # Cache state root
   118  //    previous_state_root = hash_tree_root(state)
   119  //    state.state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_state_root
   120  //    # Cache latest block header state root
   121  //    if state.latest_block_header.state_root == Bytes32():
   122  //        state.latest_block_header.state_root = previous_state_root
   123  //    # Cache block root
   124  //    previous_block_root = hash_tree_root(state.latest_block_header)
   125  //    state.block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = previous_block_root
   126  func ProcessSlot(ctx context.Context, state iface.BeaconState) (iface.BeaconState, error) {
   127  	ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlot")
   128  	defer span.End()
   129  	span.AddAttributes(trace.Int64Attribute("slot", int64(state.Slot())))
   130  
   131  	prevStateRoot, err := state.HashTreeRoot(ctx)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	if err := state.UpdateStateRootAtIndex(
   136  		uint64(state.Slot()%params.BeaconConfig().SlotsPerHistoricalRoot),
   137  		prevStateRoot,
   138  	); err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	zeroHash := params.BeaconConfig().ZeroHash
   143  	// Cache latest block header state root.
   144  	header := state.LatestBlockHeader()
   145  	if header.StateRoot == nil || bytes.Equal(header.StateRoot, zeroHash[:]) {
   146  		header.StateRoot = prevStateRoot[:]
   147  		if err := state.SetLatestBlockHeader(header); err != nil {
   148  			return nil, err
   149  		}
   150  	}
   151  	prevBlockRoot, err := state.LatestBlockHeader().HashTreeRoot()
   152  	if err != nil {
   153  		traceutil.AnnotateError(span, err)
   154  		return nil, errors.Wrap(err, "could not determine prev block root")
   155  	}
   156  	// Cache the block root.
   157  	if err := state.UpdateBlockRootAtIndex(
   158  		uint64(state.Slot()%params.BeaconConfig().SlotsPerHistoricalRoot),
   159  		prevBlockRoot,
   160  	); err != nil {
   161  		return nil, err
   162  	}
   163  	return state, nil
   164  }
   165  
   166  // ProcessSlotsUsingNextSlotCache processes slots by using next slot cache for higher efficiency.
   167  func ProcessSlotsUsingNextSlotCache(
   168  	ctx context.Context,
   169  	parentState iface.BeaconState,
   170  	parentRoot []byte,
   171  	slot types.Slot) (iface.BeaconState, error) {
   172  	ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlotsUsingNextSlotCache")
   173  	defer span.End()
   174  
   175  	// Check whether the parent state has been advanced by 1 slot in next slot cache.
   176  	nextSlotState, err := NextSlotState(ctx, parentRoot)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	// If the next slot state is not nil (i.e. cache hit).
   181  	// We replace next slot state with parent state.
   182  	if nextSlotState != nil && !nextSlotState.IsNil() {
   183  		parentState = nextSlotState
   184  	}
   185  
   186  	// Since next slot cache only advances state by 1 slot,
   187  	// we check if there's more slots that need to process.
   188  	if slot > parentState.Slot() {
   189  		parentState, err = ProcessSlots(ctx, parentState, slot)
   190  		if err != nil {
   191  			return nil, errors.Wrap(err, "could not process slots")
   192  		}
   193  	}
   194  	return parentState, nil
   195  }
   196  
   197  // ProcessSlots process through skip slots and apply epoch transition when it's needed
   198  //
   199  // Spec pseudocode definition:
   200  //  def process_slots(state: BeaconState, slot: Slot) -> None:
   201  //    assert state.slot < slot
   202  //    while state.slot < slot:
   203  //        process_slot(state)
   204  //        # Process epoch on the start slot of the next epoch
   205  //        if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
   206  //            process_epoch(state)
   207  //        state.slot = Slot(state.slot + 1)
   208  func ProcessSlots(ctx context.Context, state iface.BeaconState, slot types.Slot) (iface.BeaconState, error) {
   209  	ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlots")
   210  	defer span.End()
   211  	if state == nil || state.IsNil() {
   212  		return nil, errors.New("nil state")
   213  	}
   214  	span.AddAttributes(trace.Int64Attribute("slots", int64(slot)-int64(state.Slot())))
   215  
   216  	// The block must have a higher slot than parent state.
   217  	if state.Slot() >= slot {
   218  		err := fmt.Errorf("expected state.slot %d < slot %d", state.Slot(), slot)
   219  		traceutil.AnnotateError(span, err)
   220  		return nil, err
   221  	}
   222  
   223  	highestSlot := state.Slot()
   224  	key, err := cacheKey(ctx, state)
   225  	if err != nil {
   226  		return nil, err
   227  	}
   228  
   229  	// Restart from cached value, if one exists.
   230  	cachedState, err := SkipSlotCache.Get(ctx, key)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	if cachedState != nil && !cachedState.IsNil() && cachedState.Slot() < slot {
   236  		highestSlot = cachedState.Slot()
   237  		state = cachedState
   238  	}
   239  	if err := SkipSlotCache.MarkInProgress(key); errors.Is(err, cache.ErrAlreadyInProgress) {
   240  		cachedState, err = SkipSlotCache.Get(ctx, key)
   241  		if err != nil {
   242  			return nil, err
   243  		}
   244  		if cachedState != nil && !cachedState.IsNil() && cachedState.Slot() < slot {
   245  			highestSlot = cachedState.Slot()
   246  			state = cachedState
   247  		}
   248  	} else if err != nil {
   249  		return nil, err
   250  	}
   251  	defer func() {
   252  		if err := SkipSlotCache.MarkNotInProgress(key); err != nil {
   253  			traceutil.AnnotateError(span, err)
   254  			log.WithError(err).Error("Failed to mark skip slot no longer in progress")
   255  		}
   256  	}()
   257  
   258  	for state.Slot() < slot {
   259  		if ctx.Err() != nil {
   260  			traceutil.AnnotateError(span, ctx.Err())
   261  			// Cache last best value.
   262  			if highestSlot < state.Slot() {
   263  				if err := SkipSlotCache.Put(ctx, key, state); err != nil {
   264  					log.WithError(err).Error("Failed to put skip slot cache value")
   265  				}
   266  			}
   267  			return nil, ctx.Err()
   268  		}
   269  		state, err = ProcessSlot(ctx, state)
   270  		if err != nil {
   271  			traceutil.AnnotateError(span, err)
   272  			return nil, errors.Wrap(err, "could not process slot")
   273  		}
   274  		if CanProcessEpoch(state) {
   275  			state, err = ProcessEpochPrecompute(ctx, state)
   276  			if err != nil {
   277  				traceutil.AnnotateError(span, err)
   278  				return nil, errors.Wrap(err, "could not process epoch with optimizations")
   279  			}
   280  		}
   281  		if err := state.SetSlot(state.Slot() + 1); err != nil {
   282  			traceutil.AnnotateError(span, err)
   283  			return nil, errors.Wrap(err, "failed to increment state slot")
   284  		}
   285  	}
   286  
   287  	if highestSlot < state.Slot() {
   288  		if err := SkipSlotCache.Put(ctx, key, state); err != nil {
   289  			log.WithError(err).Error("Failed to put skip slot cache value")
   290  			traceutil.AnnotateError(span, err)
   291  		}
   292  	}
   293  
   294  	return state, nil
   295  }
   296  
   297  // ProcessBlock creates a new, modified beacon state by applying block operation
   298  // transformations as defined in the Ethereum Serenity specification, including processing proposer slashings,
   299  // processing block attestations, and more.
   300  //
   301  // Spec pseudocode definition:
   302  //
   303  //  def process_block(state: BeaconState, block: BeaconBlock) -> None:
   304  //    process_block_header(state, block)
   305  //    process_randao(state, block.body)
   306  //    process_eth1_data(state, block.body)
   307  //    process_operations(state, block.body)
   308  func ProcessBlock(
   309  	ctx context.Context,
   310  	state iface.BeaconState,
   311  	signed interfaces.SignedBeaconBlock,
   312  ) (iface.BeaconState, error) {
   313  	ctx, span := trace.StartSpan(ctx, "core.state.ProcessBlock")
   314  	defer span.End()
   315  
   316  	var err error
   317  	if err = helpers.VerifyNilBeaconBlock(signed); err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	for _, p := range processingPipeline {
   322  		state, err = p(ctx, state, signed)
   323  		if err != nil {
   324  			return nil, errors.Wrap(err, "Could not process block")
   325  		}
   326  	}
   327  
   328  	return state, nil
   329  }
   330  
   331  // VerifyOperationLengths verifies that block operation lengths are valid.
   332  func VerifyOperationLengths(_ context.Context, state iface.BeaconState, b interfaces.SignedBeaconBlock) (iface.BeaconState, error) {
   333  	if err := helpers.VerifyNilBeaconBlock(b); err != nil {
   334  		return nil, err
   335  	}
   336  	body := b.Block().Body()
   337  
   338  	if uint64(len(body.ProposerSlashings())) > params.BeaconConfig().MaxProposerSlashings {
   339  		return nil, fmt.Errorf(
   340  			"number of proposer slashings (%d) in block body exceeds allowed threshold of %d",
   341  			len(body.ProposerSlashings()),
   342  			params.BeaconConfig().MaxProposerSlashings,
   343  		)
   344  	}
   345  
   346  	if uint64(len(body.AttesterSlashings())) > params.BeaconConfig().MaxAttesterSlashings {
   347  		return nil, fmt.Errorf(
   348  			"number of attester slashings (%d) in block body exceeds allowed threshold of %d",
   349  			len(body.AttesterSlashings()),
   350  			params.BeaconConfig().MaxAttesterSlashings,
   351  		)
   352  	}
   353  
   354  	if uint64(len(body.Attestations())) > params.BeaconConfig().MaxAttestations {
   355  		return nil, fmt.Errorf(
   356  			"number of attestations (%d) in block body exceeds allowed threshold of %d",
   357  			len(body.Attestations()),
   358  			params.BeaconConfig().MaxAttestations,
   359  		)
   360  	}
   361  
   362  	if uint64(len(body.VoluntaryExits())) > params.BeaconConfig().MaxVoluntaryExits {
   363  		return nil, fmt.Errorf(
   364  			"number of voluntary exits (%d) in block body exceeds allowed threshold of %d",
   365  			len(body.VoluntaryExits()),
   366  			params.BeaconConfig().MaxVoluntaryExits,
   367  		)
   368  	}
   369  	eth1Data := state.Eth1Data()
   370  	if eth1Data == nil {
   371  		return nil, errors.New("nil eth1data in state")
   372  	}
   373  	if state.Eth1DepositIndex() > eth1Data.DepositCount {
   374  		return nil, fmt.Errorf("expected state.deposit_index %d <= eth1data.deposit_count %d", state.Eth1DepositIndex(), eth1Data.DepositCount)
   375  	}
   376  	maxDeposits := mathutil.Min(params.BeaconConfig().MaxDeposits, eth1Data.DepositCount-state.Eth1DepositIndex())
   377  	// Verify outstanding deposits are processed up to max number of deposits
   378  	if uint64(len(body.Deposits())) != maxDeposits {
   379  		return nil, fmt.Errorf("incorrect outstanding deposits in block body, wanted: %d, got: %d",
   380  			maxDeposits, len(body.Deposits()))
   381  	}
   382  
   383  	return state, nil
   384  }
   385  
   386  // CanProcessEpoch checks the eligibility to process epoch.
   387  // The epoch can be processed at the end of the last slot of every epoch
   388  //
   389  // Spec pseudocode definition:
   390  //    If (state.slot + 1) % SLOTS_PER_EPOCH == 0:
   391  func CanProcessEpoch(state iface.ReadOnlyBeaconState) bool {
   392  	return (state.Slot()+1)%params.BeaconConfig().SlotsPerEpoch == 0
   393  }
   394  
   395  // ProcessEpochPrecompute describes the per epoch operations that are performed on the beacon state.
   396  // It's optimized by pre computing validator attested info and epoch total/attested balances upfront.
   397  func ProcessEpochPrecompute(ctx context.Context, state iface.BeaconState) (iface.BeaconState, error) {
   398  	ctx, span := trace.StartSpan(ctx, "core.state.ProcessEpochPrecompute")
   399  	defer span.End()
   400  	span.AddAttributes(trace.Int64Attribute("epoch", int64(helpers.CurrentEpoch(state))))
   401  
   402  	if state == nil || state.IsNil() {
   403  		return nil, errors.New("nil state")
   404  	}
   405  	vp, bp, err := precompute.New(ctx, state)
   406  	if err != nil {
   407  		return nil, err
   408  	}
   409  	vp, bp, err = precompute.ProcessAttestations(ctx, state, vp, bp)
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  
   414  	state, err = precompute.ProcessJustificationAndFinalizationPreCompute(state, bp)
   415  	if err != nil {
   416  		return nil, errors.Wrap(err, "could not process justification")
   417  	}
   418  
   419  	state, err = precompute.ProcessRewardsAndPenaltiesPrecompute(state, bp, vp, precompute.AttestationsDelta, precompute.ProposersDelta)
   420  	if err != nil {
   421  		return nil, errors.Wrap(err, "could not process rewards and penalties")
   422  	}
   423  
   424  	state, err = e.ProcessRegistryUpdates(state)
   425  	if err != nil {
   426  		return nil, errors.Wrap(err, "could not process registry updates")
   427  	}
   428  
   429  	err = precompute.ProcessSlashingsPrecompute(state, bp)
   430  	if err != nil {
   431  		return nil, err
   432  	}
   433  
   434  	state, err = e.ProcessFinalUpdates(state)
   435  	if err != nil {
   436  		return nil, errors.Wrap(err, "could not process final updates")
   437  	}
   438  	return state, nil
   439  }