SetHead rewinds the local chain to a new head. In the case of headers, everything above the new head will be deleted and the new one set. In the case of blocks though, the head may be further rewound if block bodies are missing (non-archive nodes after a fast sync).
(head uint64)
| 392 | // though, the head may be further rewound if block bodies are missing (non-archive |
| 393 | // nodes after a fast sync). |
| 394 | func (bc *BlockChain) SetHead(head uint64) error { |
| 395 | log.Warn("Rewinding blockchain", "target", head) |
| 396 | |
| 397 | bc.mu.Lock() |
| 398 | defer bc.mu.Unlock() |
| 399 | |
| 400 | // Rewind the header chain, deleting all block bodies until then |
| 401 | delFn := func(db rawdb.DatabaseDeleter, hash common.Hash, num uint64) { |
| 402 | rawdb.DeleteBody(db, hash, num) |
| 403 | } |
| 404 | bc.hc.SetHead(head, delFn) |
| 405 | currentHeader := bc.hc.CurrentHeader() |
| 406 | |
| 407 | // Clear out any stale content from the caches |
| 408 | bc.bodyCache.Purge() |
| 409 | bc.bodyRLPCache.Purge() |
| 410 | bc.blockCache.Purge() |
| 411 | bc.futureBlocks.Purge() |
| 412 | |
| 413 | // Rewind the block chain, ensuring we don't end up with a stateless head block |
| 414 | if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number.Uint64() < currentBlock.NumberU64() { |
| 415 | bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())) |
| 416 | } |
| 417 | if currentBlock := bc.CurrentBlock(); currentBlock != nil { |
| 418 | if _, err := state.New(currentBlock.StateRoot(), bc.stateCache); err != nil { |
| 419 | // Rewound state missing, rolled back to before pivot, reset to genesis |
| 420 | bc.currentBlock.Store(bc.genesisBlock) |
| 421 | } |
| 422 | if _, err := state.New(GetPrivateStateRoot(bc.db, currentBlock.StateRoot()), bc.privateStateCache); err != nil { |
| 423 | // Rewound state missing, rolled back to before pivot, reset to genesis |
| 424 | bc.currentBlock.Store(bc.genesisBlock) |
| 425 | } |
| 426 | } |
| 427 | // Rewind the fast block in a simpleton way to the target head |
| 428 | if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && currentHeader.Number.Uint64() < currentFastBlock.NumberU64() { |
| 429 | bc.currentFastBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64())) |
| 430 | } |
| 431 | // If either blocks reached nil, reset to the genesis state |
| 432 | if currentBlock := bc.CurrentBlock(); currentBlock == nil { |
| 433 | bc.currentBlock.Store(bc.genesisBlock) |
| 434 | } |
| 435 | if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock == nil { |
| 436 | bc.currentFastBlock.Store(bc.genesisBlock) |
| 437 | } |
| 438 | currentBlock := bc.CurrentBlock() |
| 439 | currentFastBlock := bc.CurrentFastBlock() |
| 440 | |
| 441 | rawdb.WriteHeadBlockHash(bc.db, currentBlock.Hash()) |
| 442 | rawdb.WriteHeadFastBlockHash(bc.db, currentFastBlock.Hash()) |
| 443 | |
| 444 | return bc.loadLastState() |
| 445 | } |
| 446 | |
| 447 | // FastSyncCommitHead sets the current head block to the one defined by the hash |
| 448 | // irrelevant what the chain contents were prior. |
no test coverage detected