diff options
author | gary rong <garyrong0905@gmail.com> | 2019-05-08 19:30:36 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2019-05-08 19:30:36 +0800 |
commit | c113723fdb9d9fa4c8ac57777f9aecfe97391453 (patch) | |
tree | ded32d7ac594ed6ca8ec4fe71a25cddc54546f2f /core/blockchain.go | |
parent | 78477e4118d7ab57b7f56847153251439f24e884 (diff) | |
download | go-tangerine-c113723fdb9d9fa4c8ac57777f9aecfe97391453.tar go-tangerine-c113723fdb9d9fa4c8ac57777f9aecfe97391453.tar.gz go-tangerine-c113723fdb9d9fa4c8ac57777f9aecfe97391453.tar.bz2 go-tangerine-c113723fdb9d9fa4c8ac57777f9aecfe97391453.tar.lz go-tangerine-c113723fdb9d9fa4c8ac57777f9aecfe97391453.tar.xz go-tangerine-c113723fdb9d9fa4c8ac57777f9aecfe97391453.tar.zst go-tangerine-c113723fdb9d9fa4c8ac57777f9aecfe97391453.zip |
core: handle importing known blocks more gracefully (#19417)
* core: import known blocks if they can be inserted as canonical blocks
* core: insert knowns blocks
* core: remove useless
* core: doesn't process head block in reorg function
Diffstat (limited to 'core/blockchain.go')
-rw-r--r-- | core/blockchain.go | 72 |
1 files changed, 58 insertions, 14 deletions
diff --git a/core/blockchain.go b/core/blockchain.go index 9fa5b09f9..8cbef7173 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -883,10 +883,10 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ var lastWrite uint64 -// WriteBlockWithoutState writes only the block and its metadata to the database, +// writeBlockWithoutState writes only the block and its metadata to the database, // but does not write any state. This is used to construct competing side forks // up to the point where they exceed the canonical total difficulty. -func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (err error) { +func (bc *BlockChain) writeBlockWithoutState(block *types.Block, td *big.Int) (err error) { bc.wg.Add(1) defer bc.wg.Done() @@ -898,6 +898,26 @@ func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (e return nil } +// writeKnownBlock updates the head block flag with a known block +// and introduces chain reorg if necessary. +func (bc *BlockChain) writeKnownBlock(block *types.Block) error { + bc.wg.Add(1) + defer bc.wg.Done() + + current := bc.CurrentBlock() + if block.ParentHash() != current.Hash() { + if err := bc.reorg(current, block); err != nil { + return err + } + } + // Write the positional metadata for transaction/receipt lookups. + // Preimages here is empty, ignore it. + rawdb.WriteTxLookupEntries(bc.db, block) + + bc.insert(block) + return nil +} + // 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) { bc.chainmu.Lock() @@ -1139,18 +1159,42 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, [] // 2. The block is stored as a sidechain, and is lying about it's stateroot, and passes a stateroot // from the canonical chain, which has not been verified. // Skip all known blocks that are behind us - current := bc.CurrentBlock().NumberU64() - for block != nil && err == ErrKnownBlock && current >= block.NumberU64() { + var ( + current = bc.CurrentBlock() + localTd = bc.GetTd(current.Hash(), current.NumberU64()) + externTd = bc.GetTd(block.ParentHash(), block.NumberU64()-1) // The first block can't be nil + ) + for block != nil && err == ErrKnownBlock { + externTd = new(big.Int).Add(externTd, block.Difficulty()) + if localTd.Cmp(externTd) < 0 { + break + } stats.ignored++ block, err = it.next() } + // The remaining blocks are still known blocks, the only scenario here is: + // During the fast sync, the pivot point is already submitted but rollback + // happens. Then node resets the head full block to a lower height via `rollback` + // and leaves a few known blocks in the database. + // + // When node runs a fast sync again, it can re-import a batch of known blocks via + // `insertChain` while a part of them have higher total difficulty than current + // head full block(new pivot point). + for block != nil && err == ErrKnownBlock { + if err := bc.writeKnownBlock(block); err != nil { + return it.index, nil, nil, err + } + lastCanon = block + + block, err = it.next() + } // Falls through to the block import } switch { // First block is pruned, insert as sidechain and reorg only if TD grows enough case err == consensus.ErrPrunedAncestor: - return bc.insertSidechain(block, it) + return bc.insertSideChain(block, it) // First block is future, shove it (and all children) to the future queue (unknown ancestor) case err == consensus.ErrFutureBlock || (err == consensus.ErrUnknownAncestor && bc.futureBlocks.Contains(it.first().ParentHash())): @@ -1313,13 +1357,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, [] return it.index, events, coalescedLogs, err } -// insertSidechain is called when an import batch hits upon a pruned ancestor +// insertSideChain is called when an import batch hits upon a pruned ancestor // error, which happens when a sidechain with a sufficiently old fork-block is // found. // // The method writes all (header-and-body-valid) blocks to disk, then tries to // switch over to the new chain if the TD exceeded the current chain. -func (bc *BlockChain) insertSidechain(block *types.Block, it *insertIterator) (int, []interface{}, []*types.Log, error) { +func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (int, []interface{}, []*types.Log, error) { var ( externTd *big.Int current = bc.CurrentBlock() @@ -1360,7 +1404,7 @@ func (bc *BlockChain) insertSidechain(block *types.Block, it *insertIterator) (i if !bc.HasBlock(block.Hash(), block.NumberU64()) { start := time.Now() - if err := bc.WriteBlockWithoutState(block, externTd); err != nil { + if err := bc.writeBlockWithoutState(block, externTd); err != nil { return it.index, nil, nil, err } log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(), @@ -1524,15 +1568,15 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } else { log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "newnum", newBlock.Number(), "newhash", newBlock.Hash()) } - // Insert the new chain, taking care of the proper incremental order - for i := len(newChain) - 1; i >= 0; i-- { + // Insert the new chain(except the head block(reverse order)), + // taking care of the proper incremental order. + for i := len(newChain) - 1; i >= 1; i-- { // Insert the block in the canonical way, re-writing history bc.insert(newChain[i]) - // Collect reborn logs due to chain reorg (except head block (reverse order)) - if i != 0 { - collectLogs(newChain[i].Hash(), false) - } + // Collect reborn logs due to chain reorg + collectLogs(newChain[i].Hash(), false) + // Write lookup entries for hash based transaction/receipt searches rawdb.WriteTxLookupEntries(bc.db, newChain[i]) addedTxs = append(addedTxs, newChain[i].Transactions()...) |