|
|
@ -1194,7 +1194,18 @@ func (bc *BlockChainImpl) Rollback(chain []common.Hash) error { |
|
|
|
|
|
|
|
|
|
|
|
var lastWrite uint64 |
|
|
|
var lastWrite uint64 |
|
|
|
|
|
|
|
|
|
|
|
func (bc *BlockChainImpl) writeBlockWithState( |
|
|
|
func (bc *BlockChainImpl) WriteBlockWithoutState(block *types.Block) (err error) { |
|
|
|
|
|
|
|
bc.chainmu.Lock() |
|
|
|
|
|
|
|
defer bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if err := rawdb.WriteBlock(bc.db, block); err != nil { |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (bc *BlockChainImpl) WriteBlockWithState( |
|
|
|
block *types.Block, receipts []*types.Receipt, |
|
|
|
block *types.Block, receipts []*types.Receipt, |
|
|
|
cxReceipts []*types.CXReceipt, |
|
|
|
cxReceipts []*types.CXReceipt, |
|
|
|
stakeMsgs []staking.StakeMsg, |
|
|
|
stakeMsgs []staking.StakeMsg, |
|
|
@ -1348,7 +1359,7 @@ func (bc *BlockChainImpl) GetMaxGarbageCollectedBlockNumber() int64 { |
|
|
|
return bc.maxGarbCollectedBlkNum |
|
|
|
return bc.maxGarbCollectedBlkNum |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (bc *BlockChainImpl) InsertChain(chain types.Blocks, verifyHeaders bool) (int, error) { |
|
|
|
func (bc *BlockChainImpl) InsertChain(chain types.Blocks, verifyHeaders bool, blockExecution bool) (int, error) { |
|
|
|
// if in tikv mode, writer node need preempt master or come be a follower
|
|
|
|
// if in tikv mode, writer node need preempt master or come be a follower
|
|
|
|
if bc.isInitTiKV() && !bc.tikvPreemptMaster(bc.rangeBlock(chain)) { |
|
|
|
if bc.isInitTiKV() && !bc.tikvPreemptMaster(bc.rangeBlock(chain)) { |
|
|
|
return len(chain), nil |
|
|
|
return len(chain), nil |
|
|
@ -1392,10 +1403,17 @@ func (bc *BlockChainImpl) LeaderRotationMeta() LeaderRotationMeta { |
|
|
|
return bc.leaderRotationMeta.Clone() |
|
|
|
return bc.leaderRotationMeta.Clone() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (bc *BlockChainImpl) insertChain(chain types.Blocks, verifyHeaders bool, blockExecution bool) (int, []interface{}, []*types.Log, error) { |
|
|
|
|
|
|
|
if blockExecution { |
|
|
|
|
|
|
|
return bc.insertChainWithBlockExecution(chain, verifyHeaders) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return bc.insertChainWithoutBlockExecution(chain, verifyHeaders) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// insertChain will execute the actual chain insertion and event aggregation. The
|
|
|
|
// insertChain will execute the actual chain insertion and event aggregation. The
|
|
|
|
// only reason this method exists as a separate one is to make locking cleaner
|
|
|
|
// only reason this method exists as a separate one is to make locking cleaner
|
|
|
|
// with deferred statements.
|
|
|
|
// with deferred statements.
|
|
|
|
func (bc *BlockChainImpl) insertChain(chain types.Blocks, verifyHeaders bool) (int, []interface{}, []*types.Log, error) { |
|
|
|
func (bc *BlockChainImpl) insertChainWithBlockExecution(chain types.Blocks, verifyHeaders bool) (int, []interface{}, []*types.Log, error) { |
|
|
|
// Sanity check that we have something meaningful to import
|
|
|
|
// Sanity check that we have something meaningful to import
|
|
|
|
if len(chain) == 0 { |
|
|
|
if len(chain) == 0 { |
|
|
|
return 0, nil, nil, ErrEmptyChain |
|
|
|
return 0, nil, nil, ErrEmptyChain |
|
|
@ -1506,7 +1524,9 @@ func (bc *BlockChainImpl) insertChain(chain types.Blocks, verifyHeaders bool) (i |
|
|
|
// Prune in case non-empty winner chain
|
|
|
|
// Prune in case non-empty winner chain
|
|
|
|
if len(winner) > 0 { |
|
|
|
if len(winner) > 0 { |
|
|
|
// Import all the pruned blocks to make the state available
|
|
|
|
// Import all the pruned blocks to make the state available
|
|
|
|
_, evs, logs, err := bc.insertChain(winner, true /* verifyHeaders */) |
|
|
|
bc.chainmu.Unlock() |
|
|
|
|
|
|
|
_, evs, logs, err := bc.insertChainWithBlockExecution(winner, true /* verifyHeaders */) |
|
|
|
|
|
|
|
bc.chainmu.Lock() |
|
|
|
events, coalescedLogs = evs, logs |
|
|
|
events, coalescedLogs = evs, logs |
|
|
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
@ -1639,6 +1659,125 @@ func (bc *BlockChainImpl) insertChain(chain types.Blocks, verifyHeaders bool) (i |
|
|
|
return 0, events, coalescedLogs, nil |
|
|
|
return 0, events, coalescedLogs, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//receiptChain []types.Receipts,
|
|
|
|
|
|
|
|
func (bc *BlockChainImpl) insertChainWithoutBlockExecution(chain types.Blocks, verifyHeaders bool) (int, []interface{}, []*types.Log, error) { |
|
|
|
|
|
|
|
// Sanity check that we have something meaningful to import
|
|
|
|
|
|
|
|
if len(chain) == 0 { |
|
|
|
|
|
|
|
return 0, nil, nil, nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Do a sanity check that the provided chain is actually ordered and linked
|
|
|
|
|
|
|
|
for i := 1; i < len(chain); i++ { |
|
|
|
|
|
|
|
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() { |
|
|
|
|
|
|
|
// Chain broke ancestry, log a message (programming error) and skip insertion
|
|
|
|
|
|
|
|
utils.Logger().Error(). |
|
|
|
|
|
|
|
Str("number", chain[i].Number().String()). |
|
|
|
|
|
|
|
Str("hash", chain[i].Hash().Hex()). |
|
|
|
|
|
|
|
Str("parent", chain[i].ParentHash().Hex()). |
|
|
|
|
|
|
|
Str("prevnumber", chain[i-1].Number().String()). |
|
|
|
|
|
|
|
Str("prevhash", chain[i-1].Hash().Hex()). |
|
|
|
|
|
|
|
Msg("insertChain: non contiguous block insert") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0, nil, nil, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].NumberU64(), |
|
|
|
|
|
|
|
chain[i-1].Hash().Bytes()[:4], i, chain[i].NumberU64(), chain[i].Hash().Bytes()[:4], chain[i].ParentHash().Bytes()[:4]) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bc.chainmu.Lock() |
|
|
|
|
|
|
|
defer bc.chainmu.Unlock() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var verifyHeadersResults <-chan error |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If the block header chain has not been verified, conduct header verification here.
|
|
|
|
|
|
|
|
if verifyHeaders { |
|
|
|
|
|
|
|
headers := make([]*block.Header, len(chain)) |
|
|
|
|
|
|
|
seals := make([]bool, len(chain)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i, block := range chain { |
|
|
|
|
|
|
|
headers[i] = block.Header() |
|
|
|
|
|
|
|
seals[i] = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Note that VerifyHeaders verifies headers in the chain in parallel
|
|
|
|
|
|
|
|
abort, results := bc.Engine().VerifyHeaders(bc, headers, seals) |
|
|
|
|
|
|
|
verifyHeadersResults = results |
|
|
|
|
|
|
|
defer close(abort) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start a parallel signature recovery (signer will fluke on fork transition, minimal perf loss)
|
|
|
|
|
|
|
|
//senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Iterate over the blocks and insert when the verifier permits
|
|
|
|
|
|
|
|
for i, block := range chain { |
|
|
|
|
|
|
|
// If the chain is terminating, stop processing blocks
|
|
|
|
|
|
|
|
if atomic.LoadInt32(&bc.procInterrupt) == 1 { |
|
|
|
|
|
|
|
utils.Logger().Debug().Msg("Premature abort during blocks processing") |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var err error |
|
|
|
|
|
|
|
if verifyHeaders { |
|
|
|
|
|
|
|
err = <-verifyHeadersResults |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if err == nil { |
|
|
|
|
|
|
|
err = bc.Validator().ValidateBody(block) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
switch { |
|
|
|
|
|
|
|
case err == ErrKnownBlock: |
|
|
|
|
|
|
|
// Block and state both already known. However if the current block is below
|
|
|
|
|
|
|
|
// this number we did a rollback and we should reimport it nonetheless.
|
|
|
|
|
|
|
|
if bc.CurrentBlock().NumberU64() >= block.NumberU64() { |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case err == consensus_engine.ErrFutureBlock: |
|
|
|
|
|
|
|
// Allow up to MaxFuture second in the future blocks. If this limit is exceeded
|
|
|
|
|
|
|
|
// the chain is discarded and processed at a later time if given.
|
|
|
|
|
|
|
|
max := big.NewInt(time.Now().Unix() + maxTimeFutureBlocks) |
|
|
|
|
|
|
|
if block.Time().Cmp(max) > 0 { |
|
|
|
|
|
|
|
return i, nil, nil, fmt.Errorf("future block: %v > %v", block.Time(), max) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
bc.futureBlocks.Add(block.Hash(), block) |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case err == consensus_engine.ErrUnknownAncestor && bc.futureBlocks.Contains(block.ParentHash()): |
|
|
|
|
|
|
|
bc.futureBlocks.Add(block.Hash(), block) |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case err == consensus_engine.ErrPrunedAncestor: |
|
|
|
|
|
|
|
var winner []*types.Block |
|
|
|
|
|
|
|
parent := bc.GetBlock(block.ParentHash(), block.NumberU64()-1) |
|
|
|
|
|
|
|
for parent != nil && !bc.HasState(parent.Root()) { |
|
|
|
|
|
|
|
winner = append(winner, parent) |
|
|
|
|
|
|
|
parent = bc.GetBlock(parent.ParentHash(), parent.NumberU64()-1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for j := 0; j < len(winner)/2; j++ { |
|
|
|
|
|
|
|
winner[j], winner[len(winner)-1-j] = winner[len(winner)-1-j], winner[j] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Prune in case non-empty winner chain
|
|
|
|
|
|
|
|
if len(winner) > 0 { |
|
|
|
|
|
|
|
// Import all the pruned blocks to make the state available
|
|
|
|
|
|
|
|
bc.chainmu.Unlock() |
|
|
|
|
|
|
|
_, _, _, err := bc.insertChainWithoutBlockExecution(winner, true /* verifyHeaders */) |
|
|
|
|
|
|
|
bc.chainmu.Lock() |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return i, nil, nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case err != nil: |
|
|
|
|
|
|
|
bc.reportBlock(block, nil, err) |
|
|
|
|
|
|
|
return i, nil, nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a new statedb using the parent block and report an
|
|
|
|
|
|
|
|
// error if it fails.
|
|
|
|
|
|
|
|
if err = bc.WriteBlockWithoutState(block); err != nil { |
|
|
|
|
|
|
|
return i, nil, nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0, nil, nil, nil |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// insertStats tracks and reports on block insertion.
|
|
|
|
// insertStats tracks and reports on block insertion.
|
|
|
|
type insertStats struct { |
|
|
|
type insertStats struct { |
|
|
|
queued, processed, ignored int |
|
|
|
queued, processed, ignored int |
|
|
|