@ -199,10 +199,10 @@ type BlockChain struct {
// Readers don't need to take it, they can just read the database.
// Readers don't need to take it, they can just read the database.
chainmu * syncx . ClosableMutex
chainmu * syncx . ClosableMutex
currentBlock atomic . Value // Current head of the block chain
currentBlock atomic . Pointer [ types . Header ] // Current head of the chain
currentFastBlock atomic . Value // Current head of the fast-sync chain (may be above the block chain!)
currentSnapBlock atomic . Pointer [ types . Header ] // Current head of snap-sync
currentFinalized Block atomic . Value // Current finalized head
currentFinalBlock atomic . Pointer [ types . Header ] // Latest (consensus) finalized block
currentSafeBlock atomic . Value // Current safe head
currentSafeBlock atomic . Pointer [ types . Header ] // Latest (consensus) safe block
bodyCache * lru . Cache [ common . Hash , * types . Body ]
bodyCache * lru . Cache [ common . Hash , * types . Body ]
bodyRLPCache * lru . Cache [ common . Hash , rlp . RawValue ]
bodyRLPCache * lru . Cache [ common . Hash , rlp . RawValue ]
@ -289,11 +289,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
return nil , ErrNoGenesis
return nil , ErrNoGenesis
}
}
var nilBlock * types . Block
bc . currentBlock . Store ( nil )
bc . currentBlock . Store ( nilBlock )
bc . currentSnapBlock . Store ( nil )
bc . currentFastBlock . Store ( nilBlock )
bc . currentFinalBlock . Store ( nil )
bc . currentFinalizedBlock . Store ( nilBlock )
bc . currentSafeBlock . Store ( nil )
bc . currentSafeBlock . Store ( nilBlock )
// If Geth is initialized with an external ancient store, re-initialize the
// If Geth is initialized with an external ancient store, re-initialize the
// missing chain indexes and chain flags. This procedure can survive crash
// missing chain indexes and chain flags. This procedure can survive crash
@ -307,7 +306,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
}
// Make sure the state associated with the block is available
// Make sure the state associated with the block is available
head := bc . CurrentBlock ( )
head := bc . CurrentBlock ( )
if ! bc . HasState ( head . Root ( ) ) {
if ! bc . HasState ( head . Root ) {
// Head state is missing, before the state recovery, find out the
// Head state is missing, before the state recovery, find out the
// disk layer point of snapshot(if it's enabled). Make sure the
// disk layer point of snapshot(if it's enabled). Make sure the
// rewound point is lower than disk layer.
// rewound point is lower than disk layer.
@ -316,9 +315,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
diskRoot = rawdb . ReadSnapshotRoot ( bc . db )
diskRoot = rawdb . ReadSnapshotRoot ( bc . db )
}
}
if diskRoot != ( common . Hash { } ) {
if diskRoot != ( common . Hash { } ) {
log . Warn ( "Head state missing, repairing" , "number" , head . Number ( ) , "hash" , head . Hash ( ) , "snaproot" , diskRoot )
log . Warn ( "Head state missing, repairing" , "number" , head . Number , "hash" , head . Hash ( ) , "snaproot" , diskRoot )
snapDisk , err := bc . setHeadBeyondRoot ( head . NumberU 64( ) , 0 , diskRoot , true )
snapDisk , err := bc . setHeadBeyondRoot ( head . Number . Uint 64( ) , 0 , diskRoot , true )
if err != nil {
if err != nil {
return nil , err
return nil , err
}
}
@ -327,13 +326,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
rawdb . WriteSnapshotRecoveryNumber ( bc . db , snapDisk )
rawdb . WriteSnapshotRecoveryNumber ( bc . db , snapDisk )
}
}
} else {
} else {
log . Warn ( "Head state missing, repairing" , "number" , head . Number ( ) , "hash" , head . Hash ( ) )
log . Warn ( "Head state missing, repairing" , "number" , head . Number , "hash" , head . Hash ( ) )
if _ , err := bc . setHeadBeyondRoot ( head . NumberU 64( ) , 0 , common . Hash { } , true ) ; err != nil {
if _ , err := bc . setHeadBeyondRoot ( head . Number . Uint 64( ) , 0 , common . Hash { } , true ) ; err != nil {
return nil , err
return nil , err
}
}
}
}
}
}
// Ensure that a previous crash in SetHead doesn't leave extra ancients
// Ensure that a previous crash in SetHead doesn't leave extra ancients
if frozen , err := bc . db . Ancients ( ) ; err == nil && frozen > 0 {
if frozen , err := bc . db . Ancients ( ) ; err == nil && frozen > 0 {
var (
var (
@ -344,18 +342,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
// blockchain repair. If the head full block is even lower than the ancient
// blockchain repair. If the head full block is even lower than the ancient
// chain, truncate the ancient store.
// chain, truncate the ancient store.
fullBlock := bc . CurrentBlock ( )
fullBlock := bc . CurrentBlock ( )
if fullBlock != nil && fullBlock . Hash ( ) != bc . genesisBlock . Hash ( ) && fullBlock . NumberU 64( ) < frozen - 1 {
if fullBlock != nil && fullBlock . Hash ( ) != bc . genesisBlock . Hash ( ) && fullBlock . Number . Uint 64( ) < frozen - 1 {
needRewind = true
needRewind = true
low = fullBlock . NumberU 64( )
low = fullBlock . Number . Uint 64( )
}
}
// In fast sync, it may happen that ancient data has been written to the
// In fast sync, it may happen that ancient data has been written to the
// ancient store, but the LastFastBlock has not been updated, truncate the
// ancient store, but the LastFastBlock has not been updated, truncate the
// extra data here.
// extra data here.
fast Block := bc . CurrentFast Block ( )
snap Block := bc . CurrentSnap Block ( )
if fast Block != nil && fastBlock . NumberU 64( ) < frozen - 1 {
if snap Block != nil && snapBlock . Number . Uint 64( ) < frozen - 1 {
needRewind = true
needRewind = true
if fastBlock . NumberU 64( ) < low || low == 0 {
if snapBlock . Number . Uint 64( ) < low || low == 0 {
low = fastBlock . NumberU 64( )
low = snapBlock . Number . Uint 64( )
}
}
}
}
if needRewind {
if needRewind {
@ -395,8 +393,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
var recover bool
var recover bool
head := bc . CurrentBlock ( )
head := bc . CurrentBlock ( )
if layer := rawdb . ReadSnapshotRecoveryNumber ( bc . db ) ; layer != nil && * layer >= head . NumberU 64( ) {
if layer := rawdb . ReadSnapshotRecoveryNumber ( bc . db ) ; layer != nil && * layer >= head . Number . Uint 64( ) {
log . Warn ( "Enabling snapshot recovery" , "chainhead" , head . NumberU64 ( ) , "diskbase" , * layer )
log . Warn ( "Enabling snapshot recovery" , "chainhead" , head . Number , "diskbase" , * layer )
recover = true
recover = true
}
}
snapconfig := snapshot . Config {
snapconfig := snapshot . Config {
@ -405,7 +403,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
NoBuild : bc . cacheConfig . SnapshotNoBuild ,
NoBuild : bc . cacheConfig . SnapshotNoBuild ,
AsyncBuild : ! bc . cacheConfig . SnapshotWait ,
AsyncBuild : ! bc . cacheConfig . SnapshotWait ,
}
}
bc . snaps , _ = snapshot . New ( snapconfig , bc . db , bc . triedb , head . Root ( ) )
bc . snaps , _ = snapshot . New ( snapconfig , bc . db , bc . triedb , head . Root )
}
}
// Start future block processor.
// Start future block processor.
@ -469,32 +467,32 @@ func (bc *BlockChain) loadLastState() error {
return bc . Reset ( )
return bc . Reset ( )
}
}
// Make sure the entire head block is available
// Make sure the entire head block is available
current Block := bc . GetBlockByHash ( head )
head Block := bc . GetBlockByHash ( head )
if current Block == nil {
if head Block == nil {
// Corrupt or empty database, init from scratch
// Corrupt or empty database, init from scratch
log . Warn ( "Head block missing, resetting chain" , "hash" , head )
log . Warn ( "Head block missing, resetting chain" , "hash" , head )
return bc . Reset ( )
return bc . Reset ( )
}
}
// Everything seems to be fine, set as the head block
// Everything seems to be fine, set as the head block
bc . currentBlock . Store ( currentBlock )
bc . currentBlock . Store ( headBlock . Header ( ) )
headBlockGauge . Update ( int64 ( current Block. NumberU64 ( ) ) )
headBlockGauge . Update ( int64 ( head Block. NumberU64 ( ) ) )
// Restore the last known head header
// Restore the last known head header
currentHeader := current Block. Header ( )
headHeader := head Block. Header ( )
if head := rawdb . ReadHeadHeaderHash ( bc . db ) ; head != ( common . Hash { } ) {
if head := rawdb . ReadHeadHeaderHash ( bc . db ) ; head != ( common . Hash { } ) {
if header := bc . GetHeaderByHash ( head ) ; header != nil {
if header := bc . GetHeaderByHash ( head ) ; header != nil {
current Header = header
head Header = header
}
}
}
}
bc . hc . SetCurrentHeader ( current Header)
bc . hc . SetCurrentHeader ( head Header)
// Restore the last known head fast block
// Restore the last known head fast block
bc . currentFast Block . Store ( currentBlock )
bc . currentSnap Block . Store ( headBlock . Header ( ) )
headFastBlockGauge . Update ( int64 ( current Block. NumberU64 ( ) ) )
headFastBlockGauge . Update ( int64 ( head Block. NumberU64 ( ) ) )
if head := rawdb . ReadHeadFastBlockHash ( bc . db ) ; head != ( common . Hash { } ) {
if head := rawdb . ReadHeadFastBlockHash ( bc . db ) ; head != ( common . Hash { } ) {
if block := bc . GetBlockByHash ( head ) ; block != nil {
if block := bc . GetBlockByHash ( head ) ; block != nil {
bc . currentFast Block . Store ( block )
bc . currentSnap Block . Store ( block . Header ( ) )
headFastBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
headFastBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
}
}
}
}
@ -504,27 +502,31 @@ func (bc *BlockChain) loadLastState() error {
// known finalized block on startup
// known finalized block on startup
if head := rawdb . ReadFinalizedBlockHash ( bc . db ) ; head != ( common . Hash { } ) {
if head := rawdb . ReadFinalizedBlockHash ( bc . db ) ; head != ( common . Hash { } ) {
if block := bc . GetBlockByHash ( head ) ; block != nil {
if block := bc . GetBlockByHash ( head ) ; block != nil {
bc . currentFinalized Block . Store ( block )
bc . currentFinalBlock . Store ( block . Header ( ) )
headFinalizedBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
headFinalizedBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
bc . currentSafeBlock . Store ( block )
bc . currentSafeBlock . Store ( block . Header ( ) )
headSafeBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
headSafeBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
}
}
}
}
// Issue a status log for the user
// Issue a status log for the user
currentFastBlock := bc . CurrentFastBlock ( )
var (
currentFinalizedBlock := bc . CurrentFinalizedBlock ( )
currentSnapBlock = bc . CurrentSnapBlock ( )
currentFinalBlock = bc . CurrentFinalBlock ( )
headerTd := bc . GetTd ( currentHeader . Hash ( ) , currentHeader . Number . Uint64 ( ) )
blockTd := bc . GetTd ( currentBlock . Hash ( ) , currentBlock . NumberU64 ( ) )
fastTd := bc . GetTd ( currentFastBlock . Hash ( ) , currentFastBlock . NumberU64 ( ) )
log . Info ( "Loaded most recent local header" , "number" , currentHeader . Number , "hash" , currentHeader . Hash ( ) , "td" , headerTd , "age" , common . PrettyAge ( time . Unix ( int64 ( currentHeader . Time ) , 0 ) ) )
log . Info ( "Loaded most recent local full block" , "number" , currentBlock . Number ( ) , "hash" , currentBlock . Hash ( ) , "td" , blockTd , "age" , common . PrettyAge ( time . Unix ( int64 ( currentBlock . Time ( ) ) , 0 ) ) )
log . Info ( "Loaded most recent local fast block" , "number" , currentFastBlock . Number ( ) , "hash" , currentFastBlock . Hash ( ) , "td" , fastTd , "age" , common . PrettyAge ( time . Unix ( int64 ( currentFastBlock . Time ( ) ) , 0 ) ) )
if currentFinalizedBlock != nil {
headerTd = bc . GetTd ( headHeader . Hash ( ) , headHeader . Number . Uint64 ( ) )
finalTd := bc . GetTd ( currentFinalizedBlock . Hash ( ) , currentFinalizedBlock . NumberU64 ( ) )
blockTd = bc . GetTd ( headBlock . Hash ( ) , headBlock . NumberU64 ( ) )
log . Info ( "Loaded most recent local finalized block" , "number" , currentFinalizedBlock . Number ( ) , "hash" , currentFinalizedBlock . Hash ( ) , "td" , finalTd , "age" , common . PrettyAge ( time . Unix ( int64 ( currentFinalizedBlock . Time ( ) ) , 0 ) ) )
)
if headHeader . Hash ( ) != headBlock . Hash ( ) {
log . Info ( "Loaded most recent local header" , "number" , headHeader . Number , "hash" , headHeader . Hash ( ) , "td" , headerTd , "age" , common . PrettyAge ( time . Unix ( int64 ( headHeader . Time ) , 0 ) ) )
}
log . Info ( "Loaded most recent local block" , "number" , headBlock . Number ( ) , "hash" , headBlock . Hash ( ) , "td" , blockTd , "age" , common . PrettyAge ( time . Unix ( int64 ( headBlock . Time ( ) ) , 0 ) ) )
if headBlock . Hash ( ) != currentSnapBlock . Hash ( ) {
fastTd := bc . GetTd ( currentSnapBlock . Hash ( ) , currentSnapBlock . Number . Uint64 ( ) )
log . Info ( "Loaded most recent local snap block" , "number" , currentSnapBlock . Number , "hash" , currentSnapBlock . Hash ( ) , "td" , fastTd , "age" , common . PrettyAge ( time . Unix ( int64 ( currentSnapBlock . Time ) , 0 ) ) )
}
if currentFinalBlock != nil {
finalTd := bc . GetTd ( currentFinalBlock . Hash ( ) , currentFinalBlock . Number . Uint64 ( ) )
log . Info ( "Loaded most recent local finalized block" , "number" , currentFinalBlock . Number , "hash" , currentFinalBlock . Hash ( ) , "td" , finalTd , "age" , common . PrettyAge ( time . Unix ( int64 ( currentFinalBlock . Time ) , 0 ) ) )
}
}
if pivot := rawdb . ReadLastPivotNumber ( bc . db ) ; pivot != nil {
if pivot := rawdb . ReadLastPivotNumber ( bc . db ) ; pivot != nil {
log . Info ( "Loaded last fast-sync pivot marker" , "number" , * pivot )
log . Info ( "Loaded last fast-sync pivot marker" , "number" , * pivot )
@ -540,7 +542,16 @@ func (bc *BlockChain) SetHead(head uint64) error {
return err
return err
}
}
// Send chain head event to update the transaction pool
// Send chain head event to update the transaction pool
bc . chainHeadFeed . Send ( ChainHeadEvent { Block : bc . CurrentBlock ( ) } )
header := bc . CurrentBlock ( )
block := bc . GetBlock ( header . Hash ( ) , header . Number . Uint64 ( ) )
if block == nil {
// This should never happen. In practice, previsouly currentBlock
// contained the entire block whereas now only a "marker", so there
// is an ever so slight chance for a race we should handle.
log . Error ( "Current block not found in database" , "block" , header . Number , "hash" , header . Hash ( ) )
return fmt . Errorf ( "current block missing: #%d [%x..]" , header . Number , header . Hash ( ) . Bytes ( ) [ : 4 ] )
}
bc . chainHeadFeed . Send ( ChainHeadEvent { Block : block } )
return nil
return nil
}
}
@ -553,16 +564,25 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error {
return err
return err
}
}
// Send chain head event to update the transaction pool
// Send chain head event to update the transaction pool
bc . chainHeadFeed . Send ( ChainHeadEvent { Block : bc . CurrentBlock ( ) } )
header := bc . CurrentBlock ( )
block := bc . GetBlock ( header . Hash ( ) , header . Number . Uint64 ( ) )
if block == nil {
// This should never happen. In practice, previsouly currentBlock
// contained the entire block whereas now only a "marker", so there
// is an ever so slight chance for a race we should handle.
log . Error ( "Current block not found in database" , "block" , header . Number , "hash" , header . Hash ( ) )
return fmt . Errorf ( "current block missing: #%d [%x..]" , header . Number , header . Hash ( ) . Bytes ( ) [ : 4 ] )
}
bc . chainHeadFeed . Send ( ChainHeadEvent { Block : block } )
return nil
return nil
}
}
// SetFinalized sets the finalized block.
// SetFinalized sets the finalized block.
func ( bc * BlockChain ) SetFinalized ( block * types . Block ) {
func ( bc * BlockChain ) SetFinalized ( header * types . Header ) {
bc . currentFinalizedBlock . Store ( block )
bc . currentFinalBlock . Store ( header )
if block != nil {
if header != nil {
rawdb . WriteFinalizedBlockHash ( bc . db , block . Hash ( ) )
rawdb . WriteFinalizedBlockHash ( bc . db , header . Hash ( ) )
headFinalizedBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
headFinalizedBlockGauge . Update ( int64 ( header . Number . Uint 64( ) ) )
} else {
} else {
rawdb . WriteFinalizedBlockHash ( bc . db , common . Hash { } )
rawdb . WriteFinalizedBlockHash ( bc . db , common . Hash { } )
headFinalizedBlockGauge . Update ( 0 )
headFinalizedBlockGauge . Update ( 0 )
@ -570,10 +590,10 @@ func (bc *BlockChain) SetFinalized(block *types.Block) {
}
}
// SetSafe sets the safe block.
// SetSafe sets the safe block.
func ( bc * BlockChain ) SetSafe ( block * types . Block ) {
func ( bc * BlockChain ) SetSafe ( header * types . Header ) {
bc . currentSafeBlock . Store ( block )
bc . currentSafeBlock . Store ( header )
if block != nil {
if header != nil {
headSafeBlockGauge . Update ( int64 ( block . NumberU 64( ) ) )
headSafeBlockGauge . Update ( int64 ( header . Number . Uint 64( ) ) )
} else {
} else {
headSafeBlockGauge . Update ( 0 )
headSafeBlockGauge . Update ( 0 )
}
}
@ -609,7 +629,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// Rewind the blockchain, ensuring we don't end up with a stateless head
// Rewind the blockchain, ensuring we don't end up with a stateless head
// block. Note, depth equality is permitted to allow using SetHead as a
// block. Note, depth equality is permitted to allow using SetHead as a
// chain reparation mechanism without deleting any data!
// chain reparation mechanism without deleting any data!
if currentBlock := bc . CurrentBlock ( ) ; currentBlock != nil && header . Number . Uint64 ( ) <= currentBlock . NumberU 64( ) {
if currentBlock := bc . CurrentBlock ( ) ; currentBlock != nil && header . Number . Uint64 ( ) <= currentBlock . Number . Uint 64( ) {
newHeadBlock := bc . GetBlock ( header . Hash ( ) , header . Number . Uint64 ( ) )
newHeadBlock := bc . GetBlock ( header . Hash ( ) , header . Number . Uint64 ( ) )
if newHeadBlock == nil {
if newHeadBlock == nil {
log . Error ( "Gap in the chain, rewinding to genesis" , "number" , header . Number , "hash" , header . Hash ( ) )
log . Error ( "Gap in the chain, rewinding to genesis" , "number" , header . Number , "hash" , header . Hash ( ) )
@ -667,27 +687,27 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// In theory we should update all in-memory markers in the
// In theory we should update all in-memory markers in the
// last step, however the direction of SetHead is from high
// last step, however the direction of SetHead is from high
// to low, so it's safe to update in-memory markers directly.
// to low, so it's safe to update in-memory markers directly.
bc . currentBlock . Store ( newHeadBlock )
bc . currentBlock . Store ( newHeadBlock . Header ( ) )
headBlockGauge . Update ( int64 ( newHeadBlock . NumberU64 ( ) ) )
headBlockGauge . Update ( int64 ( newHeadBlock . NumberU64 ( ) ) )
}
}
// Rewind the fast block in a simpleton way to the target head
// Rewind the fast block in a simpleton way to the target head
if currentFast Block := bc . CurrentFast Block ( ) ; currentFast Block != nil && header . Number . Uint64 ( ) < currentFastBlock . NumberU 64 ( ) {
if currentSnap Block := bc . CurrentSnap Block ( ) ; currentSnap Block != nil && header . Number . Uint64 ( ) < currentSnapBlock . Number . Uint 64 ( ) {
newHeadFast Block := bc . GetBlock ( header . Hash ( ) , header . Number . Uint64 ( ) )
newHeadSnap Block := bc . GetBlock ( header . Hash ( ) , header . Number . Uint64 ( ) )
// If either blocks reached nil, reset to the genesis state
// If either blocks reached nil, reset to the genesis state
if newHeadFast Block == nil {
if newHeadSnap Block == nil {
newHeadFast Block = bc . genesisBlock
newHeadSnap Block = bc . genesisBlock
}
}
rawdb . WriteHeadFastBlockHash ( db , newHeadFast Block . Hash ( ) )
rawdb . WriteHeadFastBlockHash ( db , newHeadSnap Block . Hash ( ) )
// Degrade the chain markers if they are explicitly reverted.
// Degrade the chain markers if they are explicitly reverted.
// In theory we should update all in-memory markers in the
// In theory we should update all in-memory markers in the
// last step, however the direction of SetHead is from high
// last step, however the direction of SetHead is from high
// to low, so it's safe the update in-memory markers directly.
// to low, so it's safe the update in-memory markers directly.
bc . currentFast Block . Store ( newHeadFastBlock )
bc . currentSnap Block . Store ( newHeadSnapBlock . Header ( ) )
headFastBlockGauge . Update ( int64 ( newHeadFast Block . NumberU64 ( ) ) )
headFastBlockGauge . Update ( int64 ( newHeadSnap Block . NumberU64 ( ) ) )
}
}
var (
var (
headHeader = bc . CurrentBlock ( ) . Header ( )
headHeader = bc . CurrentBlock ( )
headNumber = headHeader . Number . Uint64 ( )
headNumber = headHeader . Number . Uint64 ( )
)
)
// If setHead underflown the freezer threshold and the block processing
// If setHead underflown the freezer threshold and the block processing
@ -723,7 +743,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// If SetHead was only called as a chain reparation method, try to skip
// If SetHead was only called as a chain reparation method, try to skip
// touching the header chain altogether, unless the freezer is broken
// touching the header chain altogether, unless the freezer is broken
if repair {
if repair {
if target , force := updateFn ( bc . db , bc . CurrentBlock ( ) . Header ( ) ) ; force {
if target , force := updateFn ( bc . db , bc . CurrentBlock ( ) ) ; force {
bc . hc . SetHead ( target . Number . Uint64 ( ) , updateFn , delFn )
bc . hc . SetHead ( target . Number . Uint64 ( ) , updateFn , delFn )
}
}
} else {
} else {
@ -746,15 +766,14 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
bc . futureBlocks . Purge ( )
bc . futureBlocks . Purge ( )
// Clear safe block, finalized block if needed
// Clear safe block, finalized block if needed
if safe := bc . CurrentSafeBlock ( ) ; safe != nil && head < safe . NumberU 64( ) {
if safe := bc . CurrentSafeBlock ( ) ; safe != nil && head < safe . Number . Uint 64( ) {
log . Warn ( "SetHead invalidated safe block" )
log . Warn ( "SetHead invalidated safe block" )
bc . SetSafe ( nil )
bc . SetSafe ( nil )
}
}
if finalized := bc . CurrentFinalized Block ( ) ; finalized != nil && head < finalized . NumberU 64( ) {
if finalized := bc . CurrentFinalBlock ( ) ; finalized != nil && head < finalized . Number . Uint 64( ) {
log . Error ( "SetHead invalidated finalized block" )
log . Error ( "SetHead invalidated finalized block" )
bc . SetFinalized ( nil )
bc . SetFinalized ( nil )
}
}
return rootNumber , bc . loadLastState ( )
return rootNumber , bc . loadLastState ( )
}
}
@ -774,7 +793,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
if ! bc . chainmu . TryLock ( ) {
if ! bc . chainmu . TryLock ( ) {
return errChainStopped
return errChainStopped
}
}
bc . currentBlock . Store ( block )
bc . currentBlock . Store ( block . Header ( ) )
headBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
headBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
bc . chainmu . Unlock ( )
bc . chainmu . Unlock ( )
@ -815,18 +834,18 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
// Last update all in-memory chain markers
// Last update all in-memory chain markers
bc . genesisBlock = genesis
bc . genesisBlock = genesis
bc . currentBlock . Store ( bc . genesisBlock )
bc . currentBlock . Store ( bc . genesisBlock . Header ( ) )
headBlockGauge . Update ( int64 ( bc . genesisBlock . NumberU64 ( ) ) )
headBlockGauge . Update ( int64 ( bc . genesisBlock . NumberU64 ( ) ) )
bc . hc . SetGenesis ( bc . genesisBlock . Header ( ) )
bc . hc . SetGenesis ( bc . genesisBlock . Header ( ) )
bc . hc . SetCurrentHeader ( bc . genesisBlock . Header ( ) )
bc . hc . SetCurrentHeader ( bc . genesisBlock . Header ( ) )
bc . currentFast Block . Store ( bc . genesisBlock )
bc . currentSnap Block . Store ( bc . genesisBlock . Header ( ) )
headFastBlockGauge . Update ( int64 ( bc . genesisBlock . NumberU64 ( ) ) )
headFastBlockGauge . Update ( int64 ( bc . genesisBlock . NumberU64 ( ) ) )
return nil
return nil
}
}
// Export writes the active chain to the given writer.
// Export writes the active chain to the given writer.
func ( bc * BlockChain ) Export ( w io . Writer ) error {
func ( bc * BlockChain ) Export ( w io . Writer ) error {
return bc . ExportN ( w , uint64 ( 0 ) , bc . CurrentBlock ( ) . NumberU 64( ) )
return bc . ExportN ( w , uint64 ( 0 ) , bc . CurrentBlock ( ) . Number . Uint 64( ) )
}
}
// ExportN writes a subset of the active chain to the given writer.
// ExportN writes a subset of the active chain to the given writer.
@ -883,10 +902,10 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) {
// Update all in-memory chain markers in the last step
// Update all in-memory chain markers in the last step
bc . hc . SetCurrentHeader ( block . Header ( ) )
bc . hc . SetCurrentHeader ( block . Header ( ) )
bc . currentFast Block . Store ( block )
bc . currentSnap Block . Store ( block . Header ( ) )
headFastBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
headFastBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
bc . currentBlock . Store ( block )
bc . currentBlock . Store ( block . Header ( ) )
headBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
headBlockGauge . Update ( int64 ( block . NumberU64 ( ) ) )
}
}
@ -927,7 +946,7 @@ func (bc *BlockChain) Stop() {
var snapBase common . Hash
var snapBase common . Hash
if bc . snaps != nil {
if bc . snaps != nil {
var err error
var err error
if snapBase , err = bc . snaps . Journal ( bc . CurrentBlock ( ) . Root ( ) ) ; err != nil {
if snapBase , err = bc . snaps . Journal ( bc . CurrentBlock ( ) . Root ) ; err != nil {
log . Error ( "Failed to journal state snapshot" , "err" , err )
log . Error ( "Failed to journal state snapshot" , "err" , err )
}
}
}
}
@ -941,7 +960,7 @@ func (bc *BlockChain) Stop() {
triedb := bc . triedb
triedb := bc . triedb
for _ , offset := range [ ] uint64 { 0 , 1 , TriesInMemory - 1 } {
for _ , offset := range [ ] uint64 { 0 , 1 , TriesInMemory - 1 } {
if number := bc . CurrentBlock ( ) . NumberU 64( ) ; number > offset {
if number := bc . CurrentBlock ( ) . Number . Uint 64( ) ; number > offset {
recent := bc . GetBlockByNumber ( number - offset )
recent := bc . GetBlockByNumber ( number - offset )
log . Info ( "Writing cached state to disk" , "block" , recent . Number ( ) , "hash" , recent . Hash ( ) , "root" , recent . Root ( ) )
log . Info ( "Writing cached state to disk" , "block" , recent . Number ( ) , "hash" , recent . Hash ( ) , "root" , recent . Root ( ) )
@ -1059,7 +1078,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
// Rewind may have occurred, skip in that case.
// Rewind may have occurred, skip in that case.
if bc . CurrentHeader ( ) . Number . Cmp ( head . Number ( ) ) >= 0 {
if bc . CurrentHeader ( ) . Number . Cmp ( head . Number ( ) ) >= 0 {
reorg , err := bc . forker . ReorgNeeded ( bc . CurrentFastBlock ( ) . Header ( ) , head . Header ( ) )
reorg , err := bc . forker . ReorgNeeded ( bc . CurrentSnapBlock ( ) , head . Header ( ) )
if err != nil {
if err != nil {
log . Warn ( "Reorg failed" , "err" , err )
log . Warn ( "Reorg failed" , "err" , err )
return false
return false
@ -1067,13 +1086,12 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
return false
return false
}
}
rawdb . WriteHeadFastBlockHash ( bc . db , head . Hash ( ) )
rawdb . WriteHeadFastBlockHash ( bc . db , head . Hash ( ) )
bc . currentFast Block . Store ( head )
bc . currentSnap Block . Store ( head . Header ( ) )
headFastBlockGauge . Update ( int64 ( head . NumberU64 ( ) ) )
headFastBlockGauge . Update ( int64 ( head . NumberU64 ( ) ) )
return true
return true
}
}
return false
return false
}
}
// writeAncient writes blockchain and corresponding receipt chain into ancient store.
// writeAncient writes blockchain and corresponding receipt chain into ancient store.
//
//
// this function only accepts canonical chain data. All side chain will be reverted
// this function only accepts canonical chain data. All side chain will be reverted
@ -1135,8 +1153,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
if batch . ValueSize ( ) > ethdb . IdealBatchSize || i == len ( blockChain ) - 1 {
if batch . ValueSize ( ) > ethdb . IdealBatchSize || i == len ( blockChain ) - 1 {
size += int64 ( batch . ValueSize ( ) )
size += int64 ( batch . ValueSize ( ) )
if err = batch . Write ( ) ; err != nil {
if err = batch . Write ( ) ; err != nil {
fast Block := bc . CurrentFastBlock ( ) . NumberU 64 ( )
snap Block := bc . CurrentSnapBlock ( ) . Number . Uint 64 ( )
if err := bc . db . TruncateHead ( fast Block + 1 ) ; err != nil {
if err := bc . db . TruncateHead ( snap Block + 1 ) ; err != nil {
log . Error ( "Can't truncate ancient store after failed insert" , "err" , err )
log . Error ( "Can't truncate ancient store after failed insert" , "err" , err )
}
}
return 0 , err
return 0 , err
@ -1150,11 +1168,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
return 0 , err
return 0 , err
}
}
// Update the current fast block because all block data is now present in DB.
// Update the current fast block because all block data is now present in DB.
previousFast Block := bc . CurrentFastBlock ( ) . NumberU 64 ( )
previousSnap Block := bc . CurrentSnapBlock ( ) . Number . Uint 64 ( )
if ! updateHead ( blockChain [ len ( blockChain ) - 1 ] ) {
if ! updateHead ( blockChain [ len ( blockChain ) - 1 ] ) {
// We end up here if the header chain has reorg'ed, and the blocks/receipts
// We end up here if the header chain has reorg'ed, and the blocks/receipts
// don't match the canonical chain.
// don't match the canonical chain.
if err := bc . db . TruncateHead ( previousFast Block + 1 ) ; err != nil {
if err := bc . db . TruncateHead ( previousSnap Block + 1 ) ; err != nil {
log . Error ( "Can't truncate ancient store after failed insert" , "err" , err )
log . Error ( "Can't truncate ancient store after failed insert" , "err" , err )
}
}
return 0 , errSideChainReceipts
return 0 , errSideChainReceipts
@ -1414,7 +1432,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
return NonStatTy , err
return NonStatTy , err
}
}
currentBlock := bc . CurrentBlock ( )
currentBlock := bc . CurrentBlock ( )
reorg , err := bc . forker . ReorgNeeded ( currentBlock . Header ( ) , block . Header ( ) )
reorg , err := bc . forker . ReorgNeeded ( currentBlock , block . Header ( ) )
if err != nil {
if err != nil {
return NonStatTy , err
return NonStatTy , err
}
}
@ -1562,7 +1580,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
current = bc . CurrentBlock ( )
current = bc . CurrentBlock ( )
)
)
for block != nil && bc . skipBlock ( err , it ) {
for block != nil && bc . skipBlock ( err , it ) {
reorg , err = bc . forker . ReorgNeeded ( current . Header ( ) , block . Header ( ) )
reorg , err = bc . forker . ReorgNeeded ( current , block . Header ( ) )
if err != nil {
if err != nil {
return it . index , err
return it . index , err
}
}
@ -1572,7 +1590,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
// In eth2 the forker always returns true for reorg decision (blindly trusting
// In eth2 the forker always returns true for reorg decision (blindly trusting
// the external consensus engine), but in order to prevent the unnecessary
// the external consensus engine), but in order to prevent the unnecessary
// reorgs when importing known blocks, the special case is handled here.
// reorgs when importing known blocks, the special case is handled here.
if block . NumberU64 ( ) > current . NumberU 64( ) || bc . GetCanonicalHash ( block . NumberU64 ( ) ) != block . Hash ( ) {
if block . NumberU64 ( ) > current . Number . Uint 64( ) || bc . GetCanonicalHash ( block . NumberU64 ( ) ) != block . Hash ( ) {
break
break
}
}
}
}
@ -1872,7 +1890,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
err := consensus . ErrPrunedAncestor
err := consensus . ErrPrunedAncestor
for ; block != nil && errors . Is ( err , consensus . ErrPrunedAncestor ) ; block , err = it . next ( ) {
for ; block != nil && errors . Is ( err , consensus . ErrPrunedAncestor ) ; block , err = it . next ( ) {
// Check the canonical state root for that number
// Check the canonical state root for that number
if number := block . NumberU64 ( ) ; current . NumberU 64( ) >= number {
if number := block . NumberU64 ( ) ; current . Number . Uint 64( ) >= number {
canonical := bc . GetBlockByNumber ( number )
canonical := bc . GetBlockByNumber ( number )
if canonical != nil && canonical . Hash ( ) == block . Hash ( ) {
if canonical != nil && canonical . Hash ( ) == block . Hash ( ) {
// Not a sidechain block, this is a re-import of a canon block which has it's state pruned
// Not a sidechain block, this is a re-import of a canon block which has it's state pruned
@ -1922,12 +1940,12 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
//
//
// If the externTd was larger than our local TD, we now need to reimport the previous
// If the externTd was larger than our local TD, we now need to reimport the previous
// blocks to regenerate the required state
// blocks to regenerate the required state
reorg , err := bc . forker . ReorgNeeded ( current . Header ( ) , lastBlock . Header ( ) )
reorg , err := bc . forker . ReorgNeeded ( current , lastBlock . Header ( ) )
if err != nil {
if err != nil {
return it . index , err
return it . index , err
}
}
if ! reorg {
if ! reorg {
localTd := bc . GetTd ( current . Hash ( ) , current . NumberU 64( ) )
localTd := bc . GetTd ( current . Hash ( ) , current . Number . Uint 64( ) )
log . Info ( "Sidechain written to disk" , "start" , it . first ( ) . NumberU64 ( ) , "end" , it . previous ( ) . Number , "sidetd" , externTd , "localtd" , localTd )
log . Info ( "Sidechain written to disk" , "start" , it . first ( ) . NumberU64 ( ) , "end" , it . previous ( ) . Number , "sidetd" , externTd , "localtd" , localTd )
return it . index , err
return it . index , err
}
}
@ -2051,7 +2069,7 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
// potential missing transactions and post an event about them.
// potential missing transactions and post an event about them.
// Note the new head block won't be processed here, callers need to handle it
// Note the new head block won't be processed here, callers need to handle it
// externally.
// externally.
func ( bc * BlockChain ) reorg ( oldBlock , newBlock * types . Block ) error {
func ( bc * BlockChain ) reorg ( oldHead * types . Header , newHead * types . Block ) error {
var (
var (
newChain types . Blocks
newChain types . Blocks
oldChain types . Blocks
oldChain types . Blocks
@ -2060,6 +2078,12 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
deletedTxs [ ] common . Hash
deletedTxs [ ] common . Hash
addedTxs [ ] common . Hash
addedTxs [ ] common . Hash
)
)
oldBlock := bc . GetBlock ( oldHead . Hash ( ) , oldHead . Number . Uint64 ( ) )
if oldBlock == nil {
return errors . New ( "current head block missing" )
}
newBlock := newHead
// Reduce the longer chain to the same number as the shorter one
// Reduce the longer chain to the same number as the shorter one
if oldBlock . NumberU64 ( ) > newBlock . NumberU64 ( ) {
if oldBlock . NumberU64 ( ) > newBlock . NumberU64 ( ) {
// Old chain is longer, gather all transactions and logs as deleted ones
// Old chain is longer, gather all transactions and logs as deleted ones
@ -2076,10 +2100,10 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
}
}
}
}
if oldBlock == nil {
if oldBlock == nil {
return fmt . Errorf ( "invalid old chain" )
return errors . New ( "invalid old chain" )
}
}
if newBlock == nil {
if newBlock == nil {
return fmt . Errorf ( "invalid new chain" )
return errors . New ( "invalid new chain" )
}
}
// Both sides of the reorg are at the same number, reduce both until the common
// Both sides of the reorg are at the same number, reduce both until the common
// ancestor is found
// ancestor is found