github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/blockchain/process_block_helpers.go (about) 1 package blockchain 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 8 "github.com/pkg/errors" 9 types "github.com/prysmaticlabs/eth2-types" 10 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 11 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 12 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 13 "github.com/prysmaticlabs/prysm/proto/interfaces" 14 "github.com/prysmaticlabs/prysm/shared/attestationutil" 15 "github.com/prysmaticlabs/prysm/shared/bytesutil" 16 "github.com/prysmaticlabs/prysm/shared/featureconfig" 17 "github.com/prysmaticlabs/prysm/shared/params" 18 "github.com/prysmaticlabs/prysm/shared/traceutil" 19 "go.opencensus.io/trace" 20 ) 21 22 // CurrentSlot returns the current slot based on time. 23 func (s *Service) CurrentSlot() types.Slot { 24 return helpers.CurrentSlot(uint64(s.genesisTime.Unix())) 25 } 26 27 // getBlockPreState returns the pre state of an incoming block. It uses the parent root of the block 28 // to retrieve the state in DB. It verifies the pre state's validity and the incoming block 29 // is in the correct time window. 30 func (s *Service) getBlockPreState(ctx context.Context, b interfaces.BeaconBlock) (iface.BeaconState, error) { 31 ctx, span := trace.StartSpan(ctx, "blockChain.getBlockPreState") 32 defer span.End() 33 34 // Verify incoming block has a valid pre state. 35 if err := s.verifyBlkPreState(ctx, b); err != nil { 36 return nil, err 37 } 38 39 preState, err := s.cfg.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(b.ParentRoot())) 40 if err != nil { 41 return nil, errors.Wrapf(err, "could not get pre state for slot %d", b.Slot()) 42 } 43 if preState == nil || preState.IsNil() { 44 return nil, errors.Wrapf(err, "nil pre state for slot %d", b.Slot()) 45 } 46 47 // Verify block slot time is not from the future. 48 if err := helpers.VerifySlotTime(preState.GenesisTime(), b.Slot(), params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil { 49 return nil, err 50 } 51 52 // Verify block is later than the finalized epoch slot. 53 if err := s.verifyBlkFinalizedSlot(b); err != nil { 54 return nil, err 55 } 56 57 return preState, nil 58 } 59 60 // verifyBlkPreState validates input block has a valid pre-state. 61 func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.BeaconBlock) error { 62 ctx, span := trace.StartSpan(ctx, "blockChain.verifyBlkPreState") 63 defer span.End() 64 65 parentRoot := bytesutil.ToBytes32(b.ParentRoot()) 66 // Loosen the check to HasBlock because state summary gets saved in batches 67 // during initial syncing. There's no risk given a state summary object is just a 68 // a subset of the block object. 69 if !s.cfg.BeaconDB.HasStateSummary(ctx, parentRoot) && !s.cfg.BeaconDB.HasBlock(ctx, parentRoot) { 70 return errors.New("could not reconstruct parent state") 71 } 72 73 if err := s.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(b.ParentRoot())); err != nil { 74 return err 75 } 76 77 has, err := s.cfg.StateGen.HasState(ctx, parentRoot) 78 if err != nil { 79 return err 80 } 81 if !has { 82 if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil { 83 return errors.Wrap(err, "could not save initial sync blocks") 84 } 85 s.clearInitSyncBlocks() 86 } 87 return nil 88 } 89 90 // VerifyBlkDescendant validates input block root is a descendant of the 91 // current finalized block root. 92 func (s *Service) VerifyBlkDescendant(ctx context.Context, root [32]byte) error { 93 ctx, span := trace.StartSpan(ctx, "blockChain.VerifyBlkDescendant") 94 defer span.End() 95 fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.finalizedCheckpt.Root)) 96 finalizedBlkSigned, err := s.cfg.BeaconDB.Block(ctx, fRoot) 97 if err != nil { 98 return err 99 } 100 if finalizedBlkSigned == nil || finalizedBlkSigned.IsNil() || finalizedBlkSigned.Block().IsNil() { 101 return errors.New("nil finalized block") 102 } 103 finalizedBlk := finalizedBlkSigned.Block() 104 bFinalizedRoot, err := s.ancestor(ctx, root[:], finalizedBlk.Slot()) 105 if err != nil { 106 return errors.Wrap(err, "could not get finalized block root") 107 } 108 if bFinalizedRoot == nil { 109 return fmt.Errorf("no finalized block known for block %#x", bytesutil.Trunc(root[:])) 110 } 111 112 if !bytes.Equal(bFinalizedRoot, fRoot[:]) { 113 err := fmt.Errorf("block %#x is not a descendent of the current finalized block slot %d, %#x != %#x", 114 bytesutil.Trunc(root[:]), finalizedBlk.Slot(), bytesutil.Trunc(bFinalizedRoot), 115 bytesutil.Trunc(fRoot[:])) 116 traceutil.AnnotateError(span, err) 117 return err 118 } 119 return nil 120 } 121 122 // verifyBlkFinalizedSlot validates input block is not less than or equal 123 // to current finalized slot. 124 func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error { 125 finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch) 126 if err != nil { 127 return err 128 } 129 if finalizedSlot >= b.Slot() { 130 return fmt.Errorf("block is equal or earlier than finalized block, slot %d < slot %d", b.Slot(), finalizedSlot) 131 } 132 return nil 133 } 134 135 // shouldUpdateCurrentJustified prevents bouncing attack, by only update conflicting justified 136 // checkpoints in the fork choice if in the early slots of the epoch. 137 // Otherwise, delay incorporation of new justified checkpoint until next epoch boundary. 138 // See https://ethresear.ch/t/prevention-of-bouncing-attack-on-ffg/6114 for more detailed analysis and discussion. 139 func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustifiedCheckpt *ethpb.Checkpoint) (bool, error) { 140 if helpers.SlotsSinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified { 141 return true, nil 142 } 143 var newJustifiedBlockSigned interfaces.SignedBeaconBlock 144 justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(newJustifiedCheckpt.Root)) 145 var err error 146 if s.hasInitSyncBlock(justifiedRoot) { 147 newJustifiedBlockSigned = s.getInitSyncBlock(justifiedRoot) 148 } else { 149 newJustifiedBlockSigned, err = s.cfg.BeaconDB.Block(ctx, justifiedRoot) 150 if err != nil { 151 return false, err 152 } 153 } 154 if newJustifiedBlockSigned == nil || newJustifiedBlockSigned.IsNil() || newJustifiedBlockSigned.Block().IsNil() { 155 return false, errors.New("nil new justified block") 156 } 157 158 newJustifiedBlock := newJustifiedBlockSigned.Block() 159 jSlot, err := helpers.StartSlot(s.justifiedCheckpt.Epoch) 160 if err != nil { 161 return false, err 162 } 163 if newJustifiedBlock.Slot() <= jSlot { 164 return false, nil 165 } 166 var justifiedBlockSigned interfaces.SignedBeaconBlock 167 cachedJustifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root)) 168 if s.hasInitSyncBlock(cachedJustifiedRoot) { 169 justifiedBlockSigned = s.getInitSyncBlock(cachedJustifiedRoot) 170 } else { 171 justifiedBlockSigned, err = s.cfg.BeaconDB.Block(ctx, cachedJustifiedRoot) 172 if err != nil { 173 return false, err 174 } 175 } 176 177 if justifiedBlockSigned == nil || justifiedBlockSigned.IsNil() || justifiedBlockSigned.Block().IsNil() { 178 return false, errors.New("nil justified block") 179 } 180 justifiedBlock := justifiedBlockSigned.Block() 181 b, err := s.ancestor(ctx, justifiedRoot[:], justifiedBlock.Slot()) 182 if err != nil { 183 return false, err 184 } 185 if !bytes.Equal(b, s.justifiedCheckpt.Root) { 186 return false, nil 187 } 188 return true, nil 189 } 190 191 func (s *Service) updateJustified(ctx context.Context, state iface.ReadOnlyBeaconState) error { 192 cpt := state.CurrentJustifiedCheckpoint() 193 if cpt.Epoch > s.bestJustifiedCheckpt.Epoch { 194 s.bestJustifiedCheckpt = cpt 195 } 196 canUpdate, err := s.shouldUpdateCurrentJustified(ctx, cpt) 197 if err != nil { 198 return err 199 } 200 201 if canUpdate { 202 s.prevJustifiedCheckpt = s.justifiedCheckpt 203 s.justifiedCheckpt = cpt 204 if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil { 205 return err 206 } 207 } 208 209 return s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, cpt) 210 } 211 212 // This caches input checkpoint as justified for the service struct. It rotates current justified to previous justified, 213 // caches justified checkpoint balances for fork choice and save justified checkpoint in DB. 214 // This method does not have defense against fork choice bouncing attack, which is why it's only recommend to be used during initial syncing. 215 func (s *Service) updateJustifiedInitSync(ctx context.Context, cp *ethpb.Checkpoint) error { 216 s.prevJustifiedCheckpt = s.justifiedCheckpt 217 s.justifiedCheckpt = cp 218 if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil { 219 return err 220 } 221 222 return s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, cp) 223 } 224 225 func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) error { 226 // Blocks need to be saved so that we can retrieve finalized block from 227 // DB when migrating states. 228 if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil { 229 return err 230 } 231 s.clearInitSyncBlocks() 232 233 if err := s.cfg.BeaconDB.SaveFinalizedCheckpoint(ctx, cp); err != nil { 234 return err 235 } 236 if !featureconfig.Get().UpdateHeadTimely { 237 s.prevFinalizedCheckpt = s.finalizedCheckpt 238 s.finalizedCheckpt = cp 239 } 240 241 fRoot := bytesutil.ToBytes32(cp.Root) 242 if err := s.cfg.StateGen.MigrateToCold(ctx, fRoot); err != nil { 243 return errors.Wrap(err, "could not migrate to cold") 244 } 245 246 return nil 247 } 248 249 // ancestor returns the block root of an ancestry block from the input block root. 250 // 251 // Spec pseudocode definition: 252 // def get_ancestor(store: Store, root: Root, slot: Slot) -> Root: 253 // block = store.blocks[root] 254 // if block.slot > slot: 255 // return get_ancestor(store, block.parent_root, slot) 256 // elif block.slot == slot: 257 // return root 258 // else: 259 // # root is older than queried slot, thus a skip slot. Return most recent root prior to slot 260 // return root 261 func (s *Service) ancestor(ctx context.Context, root []byte, slot types.Slot) ([]byte, error) { 262 ctx, span := trace.StartSpan(ctx, "blockChain.ancestor") 263 defer span.End() 264 265 r := bytesutil.ToBytes32(root) 266 // Get ancestor root from fork choice store instead of recursively looking up blocks in DB. 267 // This is most optimal outcome. 268 ar, err := s.ancestorByForkChoiceStore(ctx, r, slot) 269 if err != nil { 270 // Try getting ancestor root from DB when failed to retrieve from fork choice store. 271 // This is the second line of defense for retrieving ancestor root. 272 ar, err = s.ancestorByDB(ctx, r, slot) 273 if err != nil { 274 return nil, err 275 } 276 } 277 278 return ar, nil 279 } 280 281 // This retrieves an ancestor root using fork choice store. The look up is looping through the a flat array structure. 282 func (s *Service) ancestorByForkChoiceStore(ctx context.Context, r [32]byte, slot types.Slot) ([]byte, error) { 283 ctx, span := trace.StartSpan(ctx, "blockChain.ancestorByForkChoiceStore") 284 defer span.End() 285 286 if !s.cfg.ForkChoiceStore.HasParent(r) { 287 return nil, errors.New("could not find root in fork choice store") 288 } 289 return s.cfg.ForkChoiceStore.AncestorRoot(ctx, r, slot) 290 } 291 292 // This retrieves an ancestor root using DB. The look up is recursively looking up DB. Slower than `ancestorByForkChoiceStore`. 293 func (s *Service) ancestorByDB(ctx context.Context, r [32]byte, slot types.Slot) ([]byte, error) { 294 ctx, span := trace.StartSpan(ctx, "blockChain.ancestorByDB") 295 defer span.End() 296 297 // Stop recursive ancestry lookup if context is cancelled. 298 if ctx.Err() != nil { 299 return nil, ctx.Err() 300 } 301 302 signed, err := s.cfg.BeaconDB.Block(ctx, r) 303 if err != nil { 304 return nil, errors.Wrap(err, "could not get ancestor block") 305 } 306 307 if s.hasInitSyncBlock(r) { 308 signed = s.getInitSyncBlock(r) 309 } 310 311 if signed == nil || signed.IsNil() || signed.Block().IsNil() { 312 return nil, errors.New("nil block") 313 } 314 b := signed.Block() 315 if b.Slot() == slot || b.Slot() < slot { 316 return r[:], nil 317 } 318 319 return s.ancestorByDB(ctx, bytesutil.ToBytes32(b.ParentRoot()), slot) 320 } 321 322 // This updates justified check point in store, if the new justified is later than stored justified or 323 // the store's justified is not in chain with finalized check point. 324 // 325 // Spec definition: 326 // # Potentially update justified if different from store 327 // if store.justified_checkpoint != state.current_justified_checkpoint: 328 // # Update justified if new justified is later than store justified 329 // if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch: 330 // store.justified_checkpoint = state.current_justified_checkpoint 331 // return 332 // # Update justified if store justified is not in chain with finalized checkpoint 333 // finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch) 334 // ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot) 335 // if ancestor_at_finalized_slot != store.finalized_checkpoint.root: 336 // store.justified_checkpoint = state.current_justified_checkpoint 337 func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state iface.BeaconState) error { 338 // Update justified if it's different than the one cached in the store. 339 if !attestationutil.CheckPointIsEqual(s.justifiedCheckpt, state.CurrentJustifiedCheckpoint()) { 340 if state.CurrentJustifiedCheckpoint().Epoch > s.justifiedCheckpt.Epoch { 341 s.justifiedCheckpt = state.CurrentJustifiedCheckpoint() 342 return s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)) 343 } 344 345 // Update justified if store justified is not in chain with finalized check point. 346 finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch) 347 if err != nil { 348 return err 349 } 350 justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root)) 351 anc, err := s.ancestor(ctx, justifiedRoot[:], finalizedSlot) 352 if err != nil { 353 return err 354 } 355 if !bytes.Equal(anc, s.finalizedCheckpt.Root) { 356 s.justifiedCheckpt = state.CurrentJustifiedCheckpoint() 357 if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil { 358 return err 359 } 360 } 361 } 362 return nil 363 } 364 365 // This retrieves missing blocks from DB (ie. the blocks that couldn't be received over sync) and inserts them to fork choice store. 366 // This is useful for block tree visualizer and additional vote accounting. 367 func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfaces.BeaconBlock, 368 fCheckpoint, jCheckpoint *ethpb.Checkpoint) error { 369 pendingNodes := make([]interfaces.BeaconBlock, 0) 370 pendingRoots := make([][32]byte, 0) 371 372 parentRoot := bytesutil.ToBytes32(blk.ParentRoot()) 373 slot := blk.Slot() 374 // Fork choice only matters from last finalized slot. 375 fSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch) 376 if err != nil { 377 return err 378 } 379 higherThanFinalized := slot > fSlot 380 // As long as parent node is not in fork choice store, and parent node is in DB. 381 for !s.cfg.ForkChoiceStore.HasNode(parentRoot) && s.cfg.BeaconDB.HasBlock(ctx, parentRoot) && higherThanFinalized { 382 b, err := s.cfg.BeaconDB.Block(ctx, parentRoot) 383 if err != nil { 384 return err 385 } 386 387 pendingNodes = append(pendingNodes, b.Block()) 388 copiedRoot := parentRoot 389 pendingRoots = append(pendingRoots, copiedRoot) 390 parentRoot = bytesutil.ToBytes32(b.Block().ParentRoot()) 391 slot = b.Block().Slot() 392 higherThanFinalized = slot > fSlot 393 } 394 395 // Insert parent nodes to fork choice store in reverse order. 396 // Lower slots should be at the end of the list. 397 for i := len(pendingNodes) - 1; i >= 0; i-- { 398 b := pendingNodes[i] 399 r := pendingRoots[i] 400 if err := s.cfg.ForkChoiceStore.ProcessBlock(ctx, 401 b.Slot(), r, bytesutil.ToBytes32(b.ParentRoot()), bytesutil.ToBytes32(b.Body().Graffiti()), 402 jCheckpoint.Epoch, 403 fCheckpoint.Epoch); err != nil { 404 return errors.Wrap(err, "could not process block for proto array fork choice") 405 } 406 } 407 408 return nil 409 } 410 411 // inserts finalized deposits into our finalized deposit trie. 412 func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) error { 413 ctx, span := trace.StartSpan(ctx, "blockChain.insertFinalizedDeposits") 414 defer span.End() 415 416 // Update deposit cache. 417 finalizedState, err := s.cfg.StateGen.StateByRoot(ctx, fRoot) 418 if err != nil { 419 return errors.Wrap(err, "could not fetch finalized state") 420 } 421 // We update the cache up to the last deposit index in the finalized block's state. 422 // We can be confident that these deposits will be included in some block 423 // because the Eth1 follow distance makes such long-range reorgs extremely unlikely. 424 eth1DepositIndex := int64(finalizedState.Eth1Data().DepositCount - 1) 425 s.cfg.DepositCache.InsertFinalizedDeposits(ctx, eth1DepositIndex) 426 // Deposit proofs are only used during state transition and can be safely removed to save space. 427 if err = s.cfg.DepositCache.PruneProofs(ctx, eth1DepositIndex); err != nil { 428 return errors.Wrap(err, "could not prune deposit proofs") 429 } 430 return nil 431 } 432 433 // The deletes input attestations from the attestation pool, so proposers don't include them in a block for the future. 434 func (s *Service) deletePoolAtts(atts []*ethpb.Attestation) error { 435 for _, att := range atts { 436 if helpers.IsAggregated(att) { 437 if err := s.cfg.AttPool.DeleteAggregatedAttestation(att); err != nil { 438 return err 439 } 440 } else { 441 if err := s.cfg.AttPool.DeleteUnaggregatedAttestation(att); err != nil { 442 return err 443 } 444 } 445 } 446 447 return nil 448 } 449 450 // This ensures that the input root defaults to using genesis root instead of zero hashes. This is needed for handling 451 // fork choice justification routine. 452 func (s *Service) ensureRootNotZeros(root [32]byte) [32]byte { 453 if root == params.BeaconConfig().ZeroHash { 454 return s.genesisRoot 455 } 456 return root 457 }