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 }