|
|
@ -108,7 +108,6 @@ type BlockChain struct { |
|
|
|
scope event.SubscriptionScope |
|
|
|
scope event.SubscriptionScope |
|
|
|
genesisBlock *types.Block |
|
|
|
genesisBlock *types.Block |
|
|
|
|
|
|
|
|
|
|
|
mu sync.RWMutex // global mutex for locking chain operations
|
|
|
|
|
|
|
|
chainmu sync.RWMutex // blockchain insertion lock
|
|
|
|
chainmu sync.RWMutex // blockchain insertion lock
|
|
|
|
procmu sync.RWMutex // block processor lock
|
|
|
|
procmu sync.RWMutex // block processor lock
|
|
|
|
|
|
|
|
|
|
|
@ -281,8 +280,8 @@ func (bc *BlockChain) loadLastState() error { |
|
|
|
func (bc *BlockChain) SetHead(head uint64) error { |
|
|
|
func (bc *BlockChain) SetHead(head uint64) error { |
|
|
|
log.Warn("Rewinding blockchain", "target", head) |
|
|
|
log.Warn("Rewinding blockchain", "target", head) |
|
|
|
|
|
|
|
|
|
|
|
bc.mu.Lock() |
|
|
|
bc.chainmu.Lock() |
|
|
|
defer bc.mu.Unlock() |
|
|
|
defer bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
// Rewind the header chain, deleting all block bodies until then
|
|
|
|
// Rewind the header chain, deleting all block bodies until then
|
|
|
|
delFn := func(db rawdb.DatabaseDeleter, hash common.Hash, num uint64) { |
|
|
|
delFn := func(db rawdb.DatabaseDeleter, hash common.Hash, num uint64) { |
|
|
@ -340,9 +339,9 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error { |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
// If all checks out, manually set the head block
|
|
|
|
// If all checks out, manually set the head block
|
|
|
|
bc.mu.Lock() |
|
|
|
bc.chainmu.Lock() |
|
|
|
bc.currentBlock.Store(block) |
|
|
|
bc.currentBlock.Store(block) |
|
|
|
bc.mu.Unlock() |
|
|
|
bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
log.Info("Committed new head block", "number", block.Number(), "hash", hash) |
|
|
|
log.Info("Committed new head block", "number", block.Number(), "hash", hash) |
|
|
|
return nil |
|
|
|
return nil |
|
|
@ -420,8 +419,8 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error { |
|
|
|
if err := bc.SetHead(0); err != nil { |
|
|
|
if err := bc.SetHead(0); err != nil { |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
bc.mu.Lock() |
|
|
|
bc.chainmu.Lock() |
|
|
|
defer bc.mu.Unlock() |
|
|
|
defer bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
// Prepare the genesis block and reinitialise the chain
|
|
|
|
// Prepare the genesis block and reinitialise the chain
|
|
|
|
if err := bc.hc.WriteTd(genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { |
|
|
|
if err := bc.hc.WriteTd(genesis.Hash(), genesis.NumberU64(), genesis.Difficulty()); err != nil { |
|
|
@ -468,8 +467,8 @@ func (bc *BlockChain) Export(w io.Writer) error { |
|
|
|
|
|
|
|
|
|
|
|
// ExportN writes a subset of the active chain to the given writer.
|
|
|
|
// ExportN writes a subset of the active chain to the given writer.
|
|
|
|
func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { |
|
|
|
func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { |
|
|
|
bc.mu.RLock() |
|
|
|
bc.chainmu.RLock() |
|
|
|
defer bc.mu.RUnlock() |
|
|
|
defer bc.chainmu.RUnlock() |
|
|
|
|
|
|
|
|
|
|
|
if first > last { |
|
|
|
if first > last { |
|
|
|
return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last) |
|
|
|
return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last) |
|
|
@ -490,7 +489,6 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { |
|
|
|
reported = time.Now() |
|
|
|
reported = time.Now() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -756,8 +754,8 @@ const ( |
|
|
|
// Rollback is designed to remove a chain of links from the database that aren't
|
|
|
|
// Rollback is designed to remove a chain of links from the database that aren't
|
|
|
|
// certain enough to be valid.
|
|
|
|
// certain enough to be valid.
|
|
|
|
func (bc *BlockChain) Rollback(chain []common.Hash) { |
|
|
|
func (bc *BlockChain) Rollback(chain []common.Hash) { |
|
|
|
bc.mu.Lock() |
|
|
|
bc.chainmu.Lock() |
|
|
|
defer bc.mu.Unlock() |
|
|
|
defer bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
for i := len(chain) - 1; i >= 0; i-- { |
|
|
|
for i := len(chain) - 1; i >= 0; i-- { |
|
|
|
hash := chain[i] |
|
|
|
hash := chain[i] |
|
|
@ -881,7 +879,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Update the head fast sync block if better
|
|
|
|
// Update the head fast sync block if better
|
|
|
|
bc.mu.Lock() |
|
|
|
bc.chainmu.Lock() |
|
|
|
head := blockChain[len(blockChain)-1] |
|
|
|
head := blockChain[len(blockChain)-1] |
|
|
|
if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case
|
|
|
|
if td := bc.GetTd(head.Hash(), head.NumberU64()); td != nil { // Rewind may have occurred, skip in that case
|
|
|
|
currentFastBlock := bc.CurrentFastBlock() |
|
|
|
currentFastBlock := bc.CurrentFastBlock() |
|
|
@ -890,7 +888,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ |
|
|
|
bc.currentFastBlock.Store(head) |
|
|
|
bc.currentFastBlock.Store(head) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
bc.mu.Unlock() |
|
|
|
bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
context := []interface{}{ |
|
|
|
context := []interface{}{ |
|
|
|
"count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), |
|
|
|
"count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), |
|
|
@ -924,6 +922,15 @@ func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (e |
|
|
|
|
|
|
|
|
|
|
|
// WriteBlockWithState writes the block and all associated state to the database.
|
|
|
|
// WriteBlockWithState writes the block and all associated state to the database.
|
|
|
|
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) { |
|
|
|
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) { |
|
|
|
|
|
|
|
bc.chainmu.Lock() |
|
|
|
|
|
|
|
defer bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return bc.writeBlockWithState(block, receipts, state) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// writeBlockWithState writes the block and all associated state to the database,
|
|
|
|
|
|
|
|
// but is expects the chain mutex to be held.
|
|
|
|
|
|
|
|
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (status WriteStatus, err error) { |
|
|
|
bc.wg.Add(1) |
|
|
|
bc.wg.Add(1) |
|
|
|
defer bc.wg.Done() |
|
|
|
defer bc.wg.Done() |
|
|
|
|
|
|
|
|
|
|
@ -933,9 +940,6 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. |
|
|
|
return NonStatTy, consensus.ErrUnknownAncestor |
|
|
|
return NonStatTy, consensus.ErrUnknownAncestor |
|
|
|
} |
|
|
|
} |
|
|
|
// Make sure no inconsistent state is leaked during insertion
|
|
|
|
// Make sure no inconsistent state is leaked during insertion
|
|
|
|
bc.mu.Lock() |
|
|
|
|
|
|
|
defer bc.mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
currentBlock := bc.CurrentBlock() |
|
|
|
currentBlock := bc.CurrentBlock() |
|
|
|
localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) |
|
|
|
localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) |
|
|
|
externTd := new(big.Int).Add(block.Difficulty(), ptd) |
|
|
|
externTd := new(big.Int).Add(block.Difficulty(), ptd) |
|
|
@ -1212,7 +1216,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, [] |
|
|
|
proctime := time.Since(start) |
|
|
|
proctime := time.Since(start) |
|
|
|
|
|
|
|
|
|
|
|
// Write the block to the chain and get the status.
|
|
|
|
// Write the block to the chain and get the status.
|
|
|
|
status, err := bc.WriteBlockWithState(block, receipts, state) |
|
|
|
status, err := bc.writeBlockWithState(block, receipts, state) |
|
|
|
t3 := time.Now() |
|
|
|
t3 := time.Now() |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return it.index, events, coalescedLogs, err |
|
|
|
return it.index, events, coalescedLogs, err |
|
|
@ -1281,7 +1285,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, [] |
|
|
|
func (bc *BlockChain) insertSidechain(it *insertIterator) (int, []interface{}, []*types.Log, error) { |
|
|
|
func (bc *BlockChain) insertSidechain(it *insertIterator) (int, []interface{}, []*types.Log, error) { |
|
|
|
var ( |
|
|
|
var ( |
|
|
|
externTd *big.Int |
|
|
|
externTd *big.Int |
|
|
|
current = bc.CurrentBlock().NumberU64() |
|
|
|
current = bc.CurrentBlock() |
|
|
|
) |
|
|
|
) |
|
|
|
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
|
|
|
// The first sidechain block error is already verified to be ErrPrunedAncestor.
|
|
|
|
// Since we don't import them here, we expect ErrUnknownAncestor for the remaining
|
|
|
|
// Since we don't import them here, we expect ErrUnknownAncestor for the remaining
|
|
|
@ -1290,7 +1294,7 @@ func (bc *BlockChain) insertSidechain(it *insertIterator) (int, []interface{}, [ |
|
|
|
block, err := it.current(), consensus.ErrPrunedAncestor |
|
|
|
block, err := it.current(), consensus.ErrPrunedAncestor |
|
|
|
for ; block != nil && (err == consensus.ErrPrunedAncestor); block, err = it.next() { |
|
|
|
for ; block != nil && (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 >= number { |
|
|
|
if number := block.NumberU64(); current.NumberU64() >= number { |
|
|
|
if canonical := bc.GetBlockByNumber(number); canonical != nil && canonical.Root() == block.Root() { |
|
|
|
if canonical := bc.GetBlockByNumber(number); canonical != nil && canonical.Root() == block.Root() { |
|
|
|
// This is most likely a shadow-state attack. When a fork is imported into the
|
|
|
|
// This is most likely a shadow-state attack. When a fork is imported into the
|
|
|
|
// database, and it eventually reaches a block height which is not pruned, we
|
|
|
|
// database, and it eventually reaches a block height which is not pruned, we
|
|
|
@ -1329,7 +1333,7 @@ func (bc *BlockChain) insertSidechain(it *insertIterator) (int, []interface{}, [ |
|
|
|
//
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
localTd := bc.GetTd(bc.CurrentBlock().Hash(), current) |
|
|
|
localTd := bc.GetTd(current.Hash(), current.NumberU64()) |
|
|
|
if localTd.Cmp(externTd) > 0 { |
|
|
|
if localTd.Cmp(externTd) > 0 { |
|
|
|
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().NumberU64(), "sidetd", externTd, "localtd", localTd) |
|
|
|
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().NumberU64(), "sidetd", externTd, "localtd", localTd) |
|
|
|
return it.index, nil, nil, err |
|
|
|
return it.index, nil, nil, err |
|
|
@ -1597,36 +1601,12 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i |
|
|
|
defer bc.wg.Done() |
|
|
|
defer bc.wg.Done() |
|
|
|
|
|
|
|
|
|
|
|
whFunc := func(header *types.Header) error { |
|
|
|
whFunc := func(header *types.Header) error { |
|
|
|
bc.mu.Lock() |
|
|
|
|
|
|
|
defer bc.mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_, err := bc.hc.WriteHeader(header) |
|
|
|
_, err := bc.hc.WriteHeader(header) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return bc.hc.InsertHeaderChain(chain, whFunc, start) |
|
|
|
return bc.hc.InsertHeaderChain(chain, whFunc, start) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// writeHeader writes a header into the local chain, given that its parent is
|
|
|
|
|
|
|
|
// already known. If the total difficulty of the newly inserted header becomes
|
|
|
|
|
|
|
|
// greater than the current known TD, the canonical chain is re-routed.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Note: This method is not concurrent-safe with inserting blocks simultaneously
|
|
|
|
|
|
|
|
// into the chain, as side effects caused by reorganisations cannot be emulated
|
|
|
|
|
|
|
|
// without the real blocks. Hence, writing headers directly should only be done
|
|
|
|
|
|
|
|
// in two scenarios: pure-header mode of operation (light clients), or properly
|
|
|
|
|
|
|
|
// separated header/block phases (non-archive clients).
|
|
|
|
|
|
|
|
func (bc *BlockChain) writeHeader(header *types.Header) error { |
|
|
|
|
|
|
|
bc.wg.Add(1) |
|
|
|
|
|
|
|
defer bc.wg.Done() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bc.mu.Lock() |
|
|
|
|
|
|
|
defer bc.mu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_, err := bc.hc.WriteHeader(header) |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CurrentHeader retrieves the current head header of the canonical chain. The
|
|
|
|
// CurrentHeader retrieves the current head header of the canonical chain. The
|
|
|
|
// header is retrieved from the HeaderChain's internal cache.
|
|
|
|
// header is retrieved from the HeaderChain's internal cache.
|
|
|
|
func (bc *BlockChain) CurrentHeader() *types.Header { |
|
|
|
func (bc *BlockChain) CurrentHeader() *types.Header { |
|
|
@ -1675,8 +1655,8 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com |
|
|
|
//
|
|
|
|
//
|
|
|
|
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
|
|
|
|
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
|
|
|
|
func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { |
|
|
|
func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { |
|
|
|
bc.chainmu.Lock() |
|
|
|
bc.chainmu.RLock() |
|
|
|
defer bc.chainmu.Unlock() |
|
|
|
defer bc.chainmu.RUnlock() |
|
|
|
|
|
|
|
|
|
|
|
return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical) |
|
|
|
return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical) |
|
|
|
} |
|
|
|
} |
|
|
|