Parallel process block from fetcher

This commit is contained in:
Nguyen Ba Tam 2018-12-04 10:20:31 +07:00
parent e4e7061482
commit 33ddb251ef
14 changed files with 429 additions and 93 deletions

View file

@ -58,7 +58,7 @@ type Engine interface {
// VerifyHeader checks whether a header conforms to the consensus rules of a // VerifyHeader checks whether a header conforms to the consensus rules of a
// given engine. Verifying the seal may be done optionally here, or explicitly // given engine. Verifying the seal may be done optionally here, or explicitly
// via the VerifySeal method. // via the VerifySeal method.
VerifyHeader(chain ChainReader, header *types.Header, seal bool) error VerifyHeader(chain ChainReader, header *types.Header, fullVerify bool) error
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
// concurrently. The method returns a quit channel to abort the operations and // concurrently. The method returns a quit channel to abort the operations and

View file

@ -261,20 +261,20 @@ func (c *Posv) Author(header *types.Header) (common.Address, error) {
} }
// VerifyHeader checks whether a header conforms to the consensus rules. // VerifyHeader checks whether a header conforms to the consensus rules.
func (c *Posv) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { func (c *Posv) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error {
return c.verifyHeaderWithCache(chain, header, nil) return c.verifyHeaderWithCache(chain, header, nil, fullVerify)
} }
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
// method returns a quit channel to abort the operations and a results channel to // method returns a quit channel to abort the operations and a results channel to
// retrieve the async verifications (the order is that of the input slice). // retrieve the async verifications (the order is that of the input slice).
func (c *Posv) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { func (c *Posv) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) {
abort := make(chan struct{}) abort := make(chan struct{})
results := make(chan error, len(headers)) results := make(chan error, len(headers))
go func() { go func() {
for i, header := range headers { for i, header := range headers {
err := c.verifyHeaderWithCache(chain, header, headers[:i]) err := c.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i])
select { select {
case <-abort: case <-abort:
@ -286,12 +286,12 @@ func (c *Posv) VerifyHeaders(chain consensus.ChainReader, headers []*types.Heade
return abort, results return abort, results
} }
func (c *Posv) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { func (c *Posv) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
_, check := c.verifiedHeaders.Get(header.Hash()) _, check := c.verifiedHeaders.Get(header.Hash())
if check { if check {
return nil return nil
} }
err := c.verifyHeader(chain, header, parents) err := c.verifyHeader(chain, header, parents, fullVerify)
if err == nil { if err == nil {
c.verifiedHeaders.Add(header.Hash(), true) c.verifiedHeaders.Add(header.Hash(), true)
} }
@ -302,15 +302,19 @@ func (c *Posv) verifyHeaderWithCache(chain consensus.ChainReader, header *types.
// caller may optionally pass in a batch of parents (ascending order) to avoid // caller may optionally pass in a batch of parents (ascending order) to avoid
// looking those up from the database. This is useful for concurrently verifying // looking those up from the database. This is useful for concurrently verifying
// a batch of new headers. // a batch of new headers.
func (c *Posv) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { func (c *Posv) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
if header.Number == nil { if header.Number == nil {
return errUnknownBlock return errUnknownBlock
} }
number := header.Number.Uint64() number := header.Number.Uint64()
if fullVerify {
// Don't waste time checking blocks from the future if header.Number.Uint64() > c.config.Epoch && len(header.Validator) == 0 {
if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 { return consensus.ErrNoValidatorSignature
return consensus.ErrFutureBlock }
// Don't waste time checking blocks from the future
if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
return consensus.ErrFutureBlock
}
} }
// Checkpoint blocks need to enforce zero beneficiary // Checkpoint blocks need to enforce zero beneficiary
checkpoint := (number % c.config.Epoch) == 0 checkpoint := (number % c.config.Epoch) == 0
@ -359,14 +363,14 @@ func (c *Posv) verifyHeader(chain consensus.ChainReader, header *types.Header, p
return err return err
} }
// All basic checks passed, verify cascading fields // All basic checks passed, verify cascading fields
return c.verifyCascadingFields(chain, header, parents) return c.verifyCascadingFields(chain, header, parents, fullVerify)
} }
// verifyCascadingFields verifies all the header fields that are not standalone, // verifyCascadingFields verifies all the header fields that are not standalone,
// rather depend on a batch of previous headers. The caller may optionally pass // rather depend on a batch of previous headers. The caller may optionally pass
// in a batch of parents (ascending order) to avoid looking those up from the // in a batch of parents (ascending order) to avoid looking those up from the
// database. This is useful for concurrently verifying a batch of new headers. // database. This is useful for concurrently verifying a batch of new headers.
func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
// The genesis block is the always valid dead-end // The genesis block is the always valid dead-end
number := header.Number.Uint64() number := header.Number.Uint64()
if number == 0 { if number == 0 {
@ -385,9 +389,6 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.
if parent.Time.Uint64()+c.config.Period > header.Time.Uint64() { if parent.Time.Uint64()+c.config.Period > header.Time.Uint64() {
return ErrInvalidTimestamp return ErrInvalidTimestamp
} }
if header.Number.Uint64() > c.config.Epoch && len(header.Validator) == 0 {
return consensus.ErrNoValidatorSignature
}
// Retrieve the snapshot needed to verify this header and cache it // Retrieve the snapshot needed to verify this header and cache it
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) snap, err := c.snapshot(chain, number-1, header.ParentHash, parents)
if err != nil { if err != nil {
@ -429,7 +430,7 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types.
} }
} }
// All basic checks passed, verify the seal and return // All basic checks passed, verify the seal and return
return c.verifySeal(chain, header, parents) return c.verifySeal(chain, header, parents, fullVerify)
} }
func (c *Posv) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*Snapshot, error) { func (c *Posv) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*Snapshot, error) {
@ -533,7 +534,7 @@ func (c *Posv) snapshot(chain consensus.ChainReader, number uint64, hash common.
// If we're at block zero, make a snapshot // If we're at block zero, make a snapshot
if number == 0 { if number == 0 {
genesis := chain.GetHeaderByNumber(0) genesis := chain.GetHeaderByNumber(0)
if err := c.VerifyHeader(chain, genesis, false); err != nil { if err := c.VerifyHeader(chain, genesis, true); err != nil {
return nil, err return nil, err
} }
signers := make([]common.Address, (len(genesis.Extra)-extraVanity-extraSeal)/common.AddressLength) signers := make([]common.Address, (len(genesis.Extra)-extraVanity-extraSeal)/common.AddressLength)
@ -598,7 +599,7 @@ func (c *Posv) VerifyUncles(chain consensus.ChainReader, block *types.Block) err
// VerifySeal implements consensus.Engine, checking whether the signature contained // VerifySeal implements consensus.Engine, checking whether the signature contained
// in the header satisfies the consensus protocol requirements. // in the header satisfies the consensus protocol requirements.
func (c *Posv) VerifySeal(chain consensus.ChainReader, header *types.Header) error { func (c *Posv) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
return c.verifySeal(chain, header, nil) return c.verifySeal(chain, header, nil, true)
} }
// verifySeal checks whether the signature contained in the header satisfies the // verifySeal checks whether the signature contained in the header satisfies the
@ -607,7 +608,7 @@ func (c *Posv) VerifySeal(chain consensus.ChainReader, header *types.Header) err
// from. // from.
// verifySeal also checks the pair of creator-validator set in the header satisfies // verifySeal also checks the pair of creator-validator set in the header satisfies
// the double validation. // the double validation.
func (c *Posv) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { func (c *Posv) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
// Verifying the genesis block is not supported // Verifying the genesis block is not supported
number := header.Number.Uint64() number := header.Number.Uint64()
if number == 0 { if number == 0 {
@ -663,7 +664,7 @@ func (c *Posv) verifySeal(chain consensus.ChainReader, header *types.Header, par
// header must contain validator info following double validation design // header must contain validator info following double validation design
// start checking from epoch 2nd. // start checking from epoch 2nd.
if header.Number.Uint64() > c.config.Epoch { if header.Number.Uint64() > c.config.Epoch && fullVerify {
validator, err := c.RecoverValidator(header) validator, err := c.RecoverValidator(header)
if err != nil { if err != nil {
return err return err

View file

@ -75,6 +75,13 @@ type CacheConfig struct {
TrieNodeLimit int // Memory limit (MB) at which to flush the current in-memory trie to disk TrieNodeLimit int // Memory limit (MB) at which to flush the current in-memory trie to disk
TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk
} }
type ResultProcessBlock struct {
logs []*types.Log
receipts []*types.Receipt
state *state.StateDB
proctime time.Duration
usedGas uint64
}
// BlockChain represents the canonical chain given a database with a genesis // BlockChain represents the canonical chain given a database with a genesis
// block. The Blockchain manages chain imports, reverts, chain reorganisations. // block. The Blockchain manages chain imports, reverts, chain reorganisations.
@ -115,14 +122,16 @@ type BlockChain struct {
currentBlock atomic.Value // Current head of the block chain currentBlock atomic.Value // Current head of the block chain
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!) currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
stateCache state.Database // State database to reuse between imports (contains state cache) stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies bodyCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
blockCache *lru.Cache // Cache for the most recent entire blocks blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing futureBlocks *lru.Cache // future blocks are blocks added for later processing
resultProcess *lru.Cache
quit chan struct{} // blockchain quit channel calculatingBlock *lru.Cache
running int32 // running must be called atomically downloadingBlock *lru.Cache
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically
// procInterrupt must be atomically called // procInterrupt must be atomically called
procInterrupt int32 // interrupt signaler for block processing procInterrupt int32 // interrupt signaler for block processing
wg sync.WaitGroup // chain processing wait group for shutting down wg sync.WaitGroup // chain processing wait group for shutting down
@ -152,21 +161,26 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
blockCache, _ := lru.New(blockCacheLimit) blockCache, _ := lru.New(blockCacheLimit)
futureBlocks, _ := lru.New(maxFutureBlocks) futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit) badBlocks, _ := lru.New(badBlockLimit)
resultProcess, _ := lru.New(blockCacheLimit)
preparingBlock, _ := lru.New(blockCacheLimit)
downloadingBlock, _ := lru.New(blockCacheLimit)
bc := &BlockChain{ bc := &BlockChain{
chainConfig: chainConfig, chainConfig: chainConfig,
cacheConfig: cacheConfig, cacheConfig: cacheConfig,
db: db, db: db,
triegc: prque.New(), triegc: prque.New(),
stateCache: state.NewDatabase(db), stateCache: state.NewDatabase(db),
quit: make(chan struct{}), quit: make(chan struct{}),
bodyCache: bodyCache, bodyCache: bodyCache,
bodyRLPCache: bodyRLPCache, bodyRLPCache: bodyRLPCache,
blockCache: blockCache, blockCache: blockCache,
futureBlocks: futureBlocks, futureBlocks: futureBlocks,
engine: engine, resultProcess: resultProcess,
vmConfig: vmConfig, calculatingBlock: preparingBlock,
badBlocks: badBlocks, downloadingBlock: downloadingBlock,
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,
} }
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
@ -1049,6 +1063,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
for i, block := range chain { for i, block := range chain {
headers[i] = block.Header() headers[i] = block.Header()
seals[i] = true seals[i] = true
bc.downloadingBlock.Add(block.Hash(), true)
} }
abort, results := bc.engine.VerifyHeaders(bc, headers, seals) abort, results := bc.engine.VerifyHeaders(bc, headers, seals)
defer close(abort) defer close(abort)
@ -1168,7 +1183,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
} }
switch status { switch status {
case CanonStatTy: case CanonStatTy:
log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()), log.Debug("Inserted new block from downloader", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()),
"txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(bstart))) "txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(bstart)))
coalescedLogs = append(coalescedLogs, logs...) coalescedLogs = append(coalescedLogs, logs...)
@ -1180,7 +1195,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
bc.gcproc += proctime bc.gcproc += proctime
case SideStatTy: case SideStatTy:
log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed", log.Debug("Inserted forked block from downloader", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed",
common.PrettyDuration(time.Since(bstart)), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles())) common.PrettyDuration(time.Since(bstart)), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()))
blockInsertTimer.UpdateSince(bstart) blockInsertTimer.UpdateSince(bstart)
@ -1189,7 +1204,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
stats.processed++ stats.processed++
stats.usedGas += usedGas stats.usedGas += usedGas
stats.report(chain, i, bc.stateCache.TrieDB().Size()) stats.report(chain, i, bc.stateCache.TrieDB().Size())
if bc.chainConfig.Posv != nil { if status == CanonStatTy && bc.chainConfig.Posv != nil {
// epoch block // epoch block
if (chain[i].NumberU64() % bc.chainConfig.Posv.Epoch) == 0 { if (chain[i].NumberU64() % bc.chainConfig.Posv.Epoch) == 0 {
CheckpointCh <- 1 CheckpointCh <- 1
@ -1206,11 +1221,212 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
} }
// Append a single chain head event if we've progressed the chain // Append a single chain head event if we've progressed the chain
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() { if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
log.Debug("New ChainHeadEvent ", "number", lastCanon.NumberU64(), "hash", lastCanon.Hash())
events = append(events, ChainHeadEvent{lastCanon}) events = append(events, ChainHeadEvent{lastCanon})
} }
return 0, events, coalescedLogs, nil return 0, events, coalescedLogs, nil
} }
func (bc *BlockChain) InsertBlock(block *types.Block) error {
events, logs, err := bc.insertBlock(block)
bc.PostChainEvents(events, logs)
return err
}
func (bc *BlockChain) PrepareBlock(block *types.Block) (err error) {
defer log.Debug("Done prepare block ", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.Header().Validator, "err", err)
if _, check := bc.resultProcess.Get(block.Hash()); check {
log.Debug("Stop prepare a block because the result cached", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.Header().Validator)
return nil
}
if _, check := bc.calculatingBlock.Get(block.Hash()); check {
log.Debug("Stop prepare a block because inserting", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.Header().Validator)
return nil
}
err = bc.engine.VerifyHeader(bc, block.Header(), false)
if err != nil {
return err
}
result, err := bc.getResultBlock(block, false)
if err == nil {
bc.resultProcess.Add(block.Hash(), result)
return nil
} else if err == ErrKnownBlock {
return nil
} else if err == ErrStopPreparingBlock {
log.Debug("Stop prepare a block because calculating", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.Header().Validator)
return nil
}
return err
}
func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*ResultProcessBlock, error) {
var calculatedBlock *CalculatedBlock
if verifiedM2 {
if result, check := bc.resultProcess.Get(block.HashNoValidator()); check {
log.Debug("Get result block from cache ", "number", block.NumberU64(), "hash", block.Hash(), "hash no validator", block.HashNoValidator())
return result.(*ResultProcessBlock), nil
}
log.Debug("Not found cache prepare block ", "number", block.NumberU64(), "hash", block.Hash(), "validator", block.HashNoValidator())
if calculatedBlock, _ := bc.calculatingBlock.Get(block.HashNoValidator()); calculatedBlock != nil {
calculatedBlock.(*CalculatedBlock).stop = true
}
}
calculatedBlock = &CalculatedBlock{block, false}
bc.calculatingBlock.Add(block.HashNoValidator(), calculatedBlock)
// Start the parallel header verifier
// If the chain is terminating, stop processing blocks
if atomic.LoadInt32(&bc.procInterrupt) == 1 {
log.Debug("Premature abort during blocks processing")
return nil, ErrBlacklistedHash
}
// If the header is a banned one, straight out abort
if BadHashes[block.Hash()] {
bc.reportBlock(block, nil, ErrBlacklistedHash)
return nil, ErrBlacklistedHash
}
// Wait for the block's verification to complete
bstart := time.Now()
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() {
return nil, ErrKnownBlock
}
case err == consensus.ErrPrunedAncestor:
// Block competing with the canonical chain, store in the db, but don't process
// until the competitor TD goes above the canonical TD
currentBlock := bc.CurrentBlock()
localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty())
if localTd.Cmp(externTd) > 0 {
return nil, err
}
// Competitor chain beat canonical, gather all blocks from the common ancestor
var winner []*types.Block
parent := bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
for !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]
}
log.Debug("Number block need calculated again", "number", block.NumberU64(), "hash", block.Hash().Hex(), "winners", len(winner))
// Import all the pruned blocks to make the state available
_, _, _, err := bc.insertChain(winner)
if err != nil {
return nil, err
}
case err != nil:
bc.reportBlock(block, nil, err)
return nil, err
}
// Create a new statedb using the parent block and report an
// error if it fails.
var parent = bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
state, err := state.New(parent.Root(), bc.stateCache)
if err != nil {
return nil, err
}
// Process block using the parent state as reference point.
receipts, logs, usedGas, err := bc.processor.ProcessBlockNoValidator(calculatedBlock, state, bc.vmConfig)
process := time.Since(bstart)
if err != nil {
if err != ErrStopPreparingBlock {
bc.reportBlock(block, receipts, err)
}
return nil, err
}
// Validate the state using the default validator
err = bc.Validator().ValidateState(block, parent, state, receipts, usedGas)
if err != nil {
bc.reportBlock(block, receipts, err)
return nil, err
}
proctime := time.Since(bstart)
log.Debug("Caculate new block", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()),
"txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(bstart)), "process", process)
return &ResultProcessBlock{receipts: receipts, logs: logs, state: state, proctime: proctime, usedGas: usedGas}, nil
}
// 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
// with deferred statements.
func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.Log, error) {
var (
stats = insertStats{startTime: mclock.Now()}
events = make([]interface{}, 0, 1)
coalescedLogs []*types.Log
)
if _, check := bc.downloadingBlock.Get(block.Hash()); check {
log.Debug("Stop fetcher a block because downloading", "number", block.NumberU64(), "hash", block.Hash())
return events, coalescedLogs, nil
}
result, err := bc.getResultBlock(block, true)
if err != nil {
return events, coalescedLogs, err
}
defer bc.resultProcess.Remove(block.HashNoValidator())
bc.wg.Add(1)
defer bc.wg.Done()
// Write the block to the chain and get the status.
bc.chainmu.Lock()
defer bc.chainmu.Unlock()
if bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
return events, coalescedLogs, nil
}
status, err := bc.WriteBlockWithState(block, result.receipts, result.state)
if err != nil {
return events, coalescedLogs, err
}
switch status {
case CanonStatTy:
log.Debug("Inserted new block from fetcher", "number", block.Number(), "hash", block.Hash(), "uncles", len(block.Uncles()),
"txs", len(block.Transactions()), "gas", block.GasUsed(), "elapsed", common.PrettyDuration(time.Since(block.ReceivedAt)))
coalescedLogs = append(coalescedLogs, result.logs...)
events = append(events, ChainEvent{block, block.Hash(), result.logs})
// Only count canonical blocks for GC processing time
bc.gcproc += result.proctime
case SideStatTy:
log.Debug("Inserted forked block from fetcher", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed",
common.PrettyDuration(time.Since(block.ReceivedAt)), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()))
blockInsertTimer.Update(result.proctime)
events = append(events, ChainSideEvent{block})
}
stats.processed++
stats.usedGas += result.usedGas
stats.report(types.Blocks{block}, 0, bc.stateCache.TrieDB().Size())
if status == CanonStatTy && bc.chainConfig.Posv != nil {
// epoch block
if (block.NumberU64() % bc.chainConfig.Posv.Epoch) == 0 {
CheckpointCh <- 1
}
// prepare set of masternodes for the next epoch
if (block.NumberU64() % bc.chainConfig.Posv.Epoch) == (bc.chainConfig.Posv.Epoch - bc.chainConfig.Posv.Gap) {
err := bc.UpdateM1()
if err != nil {
log.Error("Error when update masternodes set. Stopping node", "err", err)
os.Exit(1)
}
}
}
// Append a single chain head event if we've progressed the chain
if status == CanonStatTy && bc.CurrentBlock().Hash() == block.Hash() {
events = append(events, ChainHeadEvent{block})
log.Debug("New ChainHeadEvent from fetcher ", "number", block.NumberU64(), "hash", block.Hash())
}
return events, coalescedLogs, 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

View file

@ -36,4 +36,6 @@ var (
ErrNotPoSV = errors.New("Posv not found in config") ErrNotPoSV = errors.New("Posv not found in config")
ErrNotFoundM1 = errors.New("list M1 not found ") ErrNotFoundM1 = errors.New("list M1 not found ")
ErrStopPreparingBlock = errors.New("stop calculate a block not vrified M2")
) )

View file

@ -40,6 +40,10 @@ type StateProcessor struct {
bc *BlockChain // Canonical block chain bc *BlockChain // Canonical block chain
engine consensus.Engine // Consensus engine used for block rewards engine consensus.Engine // Consensus engine used for block rewards
} }
type CalculatedBlock struct {
block *types.Block
stop bool
}
// NewStateProcessor initialises a new StateProcessor. // NewStateProcessor initialises a new StateProcessor.
func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor {
@ -69,9 +73,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
InitSignerInTransactions(p.config, header, block.Transactions()) InitSignerInTransactions(p.config, header, block.Transactions())
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i) statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
@ -83,7 +85,44 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts)
return receipts, allLogs, *usedGas, nil
}
func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {
block := cBlock.block
var (
receipts types.Receipts
usedGas = new(uint64)
header = block.Header()
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit())
)
// Mutate the the block and state according to any hard-fork specs
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
}
if cBlock.stop {
return nil, nil, 0, ErrStopPreparingBlock
}
InitSignerInTransactions(p.config, header, block.Transactions())
if cBlock.stop {
return nil, nil, 0, ErrStopPreparingBlock
}
// Iterate over and process the individual transactions
receipts = make([]*types.Receipt, block.Transactions().Len())
for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
if err != nil {
return nil, nil, 0, err
}
if cBlock.stop {
return nil, nil, 0, ErrStopPreparingBlock
}
receipts[i] = receipt
}
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts)
return receipts, allLogs, *usedGas, nil return receipts, allLogs, *usedGas, nil
} }

View file

@ -652,6 +652,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
} }
// If the transaction pool is full, discard underpriced transactions // If the transaction pool is full, discard underpriced transactions
if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue { if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
log.Debug("Add transaction to pool full", "hash", hash, "nonce", tx.Nonce())
// If the new transaction is underpriced, don't accept it // If the new transaction is underpriced, don't accept it
if pool.priced.Underpriced(tx, pool.locals) { if pool.priced.Underpriced(tx, pool.locals) {
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice()) log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
@ -879,9 +880,6 @@ func (pool *TxPool) addTx(tx *types.Transaction, local bool) error {
// addTxs attempts to queue a batch of transactions if they are valid. // addTxs attempts to queue a batch of transactions if they are valid.
func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error { func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error {
for _, tx := range txs {
types.CacheSigner(pool.signer, tx)
}
pool.mu.Lock() pool.mu.Lock()
defer pool.mu.Unlock() defer pool.mu.Unlock()

View file

@ -43,4 +43,5 @@ type Validator interface {
// failed. // failed.
type Processor interface { type Processor interface {
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
ProcessBlockNoValidator(block *CalculatedBlock, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
} }

View file

@ -125,6 +125,30 @@ func (h *Header) HashNoNonce() common.Hash {
}) })
} }
// HashNoNonce returns the hash which is used as input for the proof-of-work search.
func (h *Header) HashNoValidator() common.Hash {
return rlpHash([]interface{}{
h.ParentHash,
h.UncleHash,
h.Coinbase,
h.Root,
h.TxHash,
h.ReceiptHash,
h.Bloom,
h.Difficulty,
h.Number,
h.GasLimit,
h.GasUsed,
h.Time,
h.Extra,
h.MixDigest,
h.Nonce,
h.Validators,
[]byte{},
h.Penalties,
})
}
// Size returns the approximate memory used by all internal contents. It is used // Size returns the approximate memory used by all internal contents. It is used
// to approximate and limit the memory consumption of various caches. // to approximate and limit the memory consumption of various caches.
func (h *Header) Size() common.StorageSize { func (h *Header) Size() common.StorageSize {
@ -337,6 +361,9 @@ func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles} }
func (b *Block) HashNoNonce() common.Hash { func (b *Block) HashNoNonce() common.Hash {
return b.header.HashNoNonce() return b.header.HashNoNonce()
} }
func (b *Block) HashNoValidator() common.Hash {
return b.header.HashNoValidator()
}
// Size returns the true RLP encoded storage size of the block, either by encoding // Size returns the true RLP encoded storage size of the block, either by encoding
// and returning it, or returning a previsouly cached value. // and returning it, or returning a previsouly cached value.

View file

@ -203,29 +203,28 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return nil return nil
} }
appendM2HeaderHook := func(block *types.Block) (*types.Block, error) { appendM2HeaderHook := func(block *types.Block) (*types.Block, bool, error) {
eb, err := eth.Etherbase() eb, err := eth.Etherbase()
if err != nil { if err != nil {
log.Error("Cannot get etherbase for append m2 header", "err", err) log.Error("Cannot get etherbase for append m2 header", "err", err)
return block, fmt.Errorf("etherbase missing: %v", err) return block, false, fmt.Errorf("etherbase missing: %v", err)
} }
m1, err := c.RecoverSigner(block.Header()) m1, err := c.RecoverSigner(block.Header())
if err != nil { if err != nil {
return block, fmt.Errorf("can't get block creator: %v", err) return block, false, fmt.Errorf("can't get block creator: %v", err)
} }
m2, err := c.GetValidator(m1, eth.blockchain, block.Header()) m2, err := c.GetValidator(m1, eth.blockchain, block.Header())
if err != nil { if err != nil {
return block, fmt.Errorf("can't get block validator: %v", err) return block, false, fmt.Errorf("can't get block validator: %v", err)
} }
if m2 == eb { if m2 == eb {
wallet, _ := eth.accountManager.Find(accounts.Account{Address: eb}) wallet, _ := eth.accountManager.Find(accounts.Account{Address: eb})
header := block.Header() header := block.Header()
sighash, _ := wallet.SignHash(accounts.Account{Address: eb}, posv.SigHash(header).Bytes()) sighash, _ := wallet.SignHash(accounts.Account{Address: eb}, posv.SigHash(header).Bytes())
header.Validator = sighash header.Validator = sighash
block = types.NewBlockWithHeader(header).WithBody(block.Transactions(), block.Uncles()) return types.NewBlockWithHeader(header).WithBody(block.Transactions(), block.Uncles()), true, nil
} }
return block, false, nil
return block, nil
} }
eth.protocolManager.fetcher.SetSignHook(signHook) eth.protocolManager.fetcher.SetSignHook(signHook)
@ -301,8 +300,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if foudationWalletAddr == (common.Address{}) { if foudationWalletAddr == (common.Address{}) {
log.Error("Foundation Wallet Address is empty", "error", foudationWalletAddr) log.Error("Foundation Wallet Address is empty", "error", foudationWalletAddr)
} }
start := time.Now()
if number > 0 && number-rCheckpoint > 0 && foudationWalletAddr != (common.Address{}) { if number > 0 && number-rCheckpoint > 0 && foudationWalletAddr != (common.Address{}) {
start := time.Now()
// Get signers in blockSigner smartcontract. // Get signers in blockSigner smartcontract.
addr := common.HexToAddress(common.BlockSigners) addr := common.HexToAddress(common.BlockSigners)
// Get reward inflation. // Get reward inflation.
@ -334,8 +333,8 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
} }
} }
} }
log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
} }
log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
return nil return nil
} }

View file

@ -62,8 +62,10 @@ type blockBroadcasterFn func(block *types.Block, propagate bool)
// chainHeightFn is a callback type to retrieve the current chain height. // chainHeightFn is a callback type to retrieve the current chain height.
type chainHeightFn func() uint64 type chainHeightFn func() uint64
// chainInsertFn is a callback type to insert a batch of blocks into the local chain. // blockInsertFn is a callback type to insert a batch of blocks into the local chain.
type chainInsertFn func(blocks types.Blocks) (int, error) type blockInsertFn func(block *types.Block) error
type blockPrepareFn func(block *types.Block) error
// peerDropFn is a callback type for dropping a peer detected as malicious. // peerDropFn is a callback type for dropping a peer detected as malicious.
type peerDropFn func(id string) type peerDropFn func(id string)
@ -135,8 +137,9 @@ type Fetcher struct {
verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work
broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers
chainHeight chainHeightFn // Retrieves the current chain's height chainHeight chainHeightFn // Retrieves the current chain's height
insertChain chainInsertFn // Injects a batch of blocks into the chain insertBlock blockInsertFn // Injects a batch of blocks into the chain
dropPeer peerDropFn // Drops a peer for misbehaving prepareBlock blockPrepareFn
dropPeer peerDropFn // Drops a peer for misbehaving
// Testing hooks // Testing hooks
announceChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a hash from the announce list announceChangeHook func(common.Hash, bool) // Method to call upon adding or deleting a hash from the announce list
@ -144,11 +147,11 @@ type Fetcher struct {
fetchingHook func([]common.Hash) // Method to call upon starting a block (eth/61) or header (eth/62) fetch fetchingHook func([]common.Hash) // Method to call upon starting a block (eth/61) or header (eth/62) fetch
completingHook func([]common.Hash) // Method to call upon starting a block body fetch (eth/62) completingHook func([]common.Hash) // Method to call upon starting a block body fetch (eth/62)
signHook func(*types.Block) error signHook func(*types.Block) error
appendM2HeaderHook func(*types.Block) (*types.Block, error) appendM2HeaderHook func(*types.Block) (*types.Block, bool, error)
} }
// New creates a block fetcher to retrieve blocks based on hash announcements. // New creates a block fetcher to retrieve blocks based on hash announcements.
func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher { func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertBlock blockInsertFn, prepareBlock blockPrepareFn, dropPeer peerDropFn) *Fetcher {
knownBlocks, _ := lru.NewARC(blockLimit) knownBlocks, _ := lru.NewARC(blockLimit)
return &Fetcher{ return &Fetcher{
notify: make(chan *announce), notify: make(chan *announce),
@ -171,7 +174,8 @@ func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBloc
verifyHeader: verifyHeader, verifyHeader: verifyHeader,
broadcastBlock: broadcastBlock, broadcastBlock: broadcastBlock,
chainHeight: chainHeight, chainHeight: chainHeight,
insertChain: insertChain, insertBlock: insertBlock,
prepareBlock: prepareBlock,
dropPeer: dropPeer, dropPeer: dropPeer,
} }
} }
@ -605,7 +609,7 @@ func (f *Fetcher) rescheduleComplete(complete *time.Timer) {
func (f *Fetcher) enqueue(peer string, block *types.Block) { func (f *Fetcher) enqueue(peer string, block *types.Block) {
hash := block.Hash() hash := block.Hash()
if f.knowns.Contains(hash) { if f.knowns.Contains(hash) {
log.Debug("Discarded propagated block, known block", "peer", peer, "number", block.Number(), "hash", hash, "limit", blockLimit) log.Trace("Discarded propagated block, known block", "peer", peer, "number", block.Number(), "hash", hash, "limit", blockLimit)
return return
} }
// Ensure the peer isn't DOSing us // Ensure the peer isn't DOSing us
@ -657,40 +661,56 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash()) log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash())
return return
} }
fastBroadCast := true
again: again:
err := f.verifyHeader(block.Header())
// Quickly validate the header and propagate the block if it passes // Quickly validate the header and propagate the block if it passes
switch err := f.verifyHeader(block.Header()); err { switch err {
case nil: case nil:
// All ok, quickly propagate to our peers // All ok, quickly propagate to our peers
propBroadcastOutTimer.UpdateSince(block.ReceivedAt) propBroadcastOutTimer.UpdateSince(block.ReceivedAt)
go f.broadcastBlock(block, true) if fastBroadCast {
go f.broadcastBlock(block, true)
}
case consensus.ErrFutureBlock: case consensus.ErrFutureBlock:
delay := time.Unix(block.Time().Int64(), 0).Sub(time.Now()) // nolint: gosimple delay := time.Unix(block.Time().Int64(), 0).Sub(time.Now()) // nolint: gosimple
time.Sleep(delay)
log.Info("Receive future block", "number", block.NumberU64(), "hash", block.Hash().Hex(), "delay", delay) log.Info("Receive future block", "number", block.NumberU64(), "hash", block.Hash().Hex(), "delay", delay)
time.Sleep(delay)
goto again goto again
case consensus.ErrNoValidatorSignature: case consensus.ErrNoValidatorSignature:
newBlock := block newBlock := block
var errM2 error
isM2 := false
if f.appendM2HeaderHook != nil { if f.appendM2HeaderHook != nil {
if newBlock, err = f.appendM2HeaderHook(block); err != nil { if newBlock, isM2, errM2 = f.appendM2HeaderHook(block); errM2 != nil {
log.Error("Append m2 to block header fail", "err", err) log.Error("Append m2 to block header fail", "err", errM2)
return return
} }
} }
if newBlock.Hash() == block.Hash() { if !isM2 {
go f.broadcastBlock(block, true) go f.broadcastBlock(block, true)
if err := f.prepareBlock(block); err != nil {
log.Debug("Propagated block prepare failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
return
}
return
}
log.Debug("Append M2 to header block", "numer", block.NumberU64(), "hahs", block.Hash())
if err := f.prepareBlock(block); err != nil {
log.Debug("Propagated block prepare failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
return return
} }
block = newBlock block = newBlock
fastBroadCast = false
goto again
default: default:
// Something went very wrong, drop the peer // Something went very wrong, drop the peer
log.Debug("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) log.Debug("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
f.dropPeer(peer) f.dropPeer(peer)
return return
} }
// Run the actual import and log any issues // Run the actual import and log any issues
if _, err := f.insertChain(types.Blocks{block}); err != nil { if err := f.insertBlock(block); err != nil {
log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
return return
} }
@ -703,8 +723,9 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
} }
// If import succeeded, broadcast the block // If import succeeded, broadcast the block
propAnnounceOutTimer.UpdateSince(block.ReceivedAt) propAnnounceOutTimer.UpdateSince(block.ReceivedAt)
go f.broadcastBlock(block, true) if !fastBroadCast {
//go f.broadcastBlock(block, false) go f.broadcastBlock(block, true)
}
}() }()
} }
@ -768,6 +789,6 @@ func (f *Fetcher) SetSignHook(signHook func(*types.Block) error) {
} }
// Bind append m2 to block header hook when imported into chain. // Bind append m2 to block header hook when imported into chain.
func (f *Fetcher) SetAppendM2HeaderHook(appendM2HeaderHook func(*types.Block) (*types.Block, error)) { func (f *Fetcher) SetAppendM2HeaderHook(appendM2HeaderHook func(*types.Block) (*types.Block, bool, error)) {
f.appendM2HeaderHook = appendM2HeaderHook f.appendM2HeaderHook = appendM2HeaderHook
} }

View file

@ -92,7 +92,7 @@ func newTester() *fetcherTester {
blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis},
drops: make(map[string]bool), drops: make(map[string]bool),
} }
tester.fetcher = New(tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertChain, tester.dropPeer) tester.fetcher = New(tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertBlock, tester.prepareBlock, tester.dropPeer)
tester.fetcher.Start() tester.fetcher.Start()
return tester return tester
@ -123,7 +123,7 @@ func (f *fetcherTester) chainHeight() uint64 {
return f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() return f.blocks[f.hashes[len(f.hashes)-1]].NumberU64()
} }
// insertChain injects a new blocks into the simulated chain. // insertBlock injects a new blocks into the simulated chain.
func (f *fetcherTester) insertChain(blocks types.Blocks) (int, error) { func (f *fetcherTester) insertChain(blocks types.Blocks) (int, error) {
f.lock.Lock() f.lock.Lock()
defer f.lock.Unlock() defer f.lock.Unlock()
@ -144,6 +144,31 @@ func (f *fetcherTester) insertChain(blocks types.Blocks) (int, error) {
return 0, nil return 0, nil
} }
// insertBlock injects a new blocks into the simulated chain.
func (f *fetcherTester) insertBlock(block *types.Block) error {
f.lock.Lock()
defer f.lock.Unlock()
// Make sure the parent in known
if _, ok := f.blocks[block.ParentHash()]; !ok {
return errors.New("unknown parent")
}
// Discard any new blocks if the same height already exists
if block.NumberU64() <= f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() {
return nil
}
// Otherwise build our current chain
f.hashes = append(f.hashes, block.Hash())
f.blocks[block.Hash()] = block
return nil
}
// insertBlock injects a new blocks into the simulated chain.
func (f *fetcherTester) prepareBlock(block *types.Block) error {
return nil
}
// dropPeer is an emulator for the peer removal, simply accumulating the various // dropPeer is an emulator for the peer removal, simply accumulating the various
// peers dropped by the fetcher. // peers dropped by the fetcher.
func (f *fetcherTester) dropPeer(peer string) { func (f *fetcherTester) dropPeer(peer string) {
@ -512,9 +537,9 @@ func testImportDeduplication(t *testing.T, protocol int) {
bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0) bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
counter := uint32(0) counter := uint32(0)
tester.fetcher.insertChain = func(blocks types.Blocks) (int, error) { tester.fetcher.insertBlock = func(block *types.Block) error {
atomic.AddUint32(&counter, uint32(len(blocks))) atomic.AddUint32(&counter, uint32(1))
return tester.insertChain(blocks) return tester.insertBlock(block)
} }
// Instrument the fetching and imported events // Instrument the fetching and imported events
fetching := make(chan []common.Hash) fetching := make(chan []common.Hash)

View file

@ -170,16 +170,26 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
heighter := func() uint64 { heighter := func() uint64 {
return blockchain.CurrentBlock().NumberU64() return blockchain.CurrentBlock().NumberU64()
} }
inserter := func(blocks types.Blocks) (int, error) { inserter := func(block *types.Block) error {
// If fast sync is running, deny importing weird blocks // If fast sync is running, deny importing weird blocks
if atomic.LoadUint32(&manager.fastSync) == 1 { if atomic.LoadUint32(&manager.fastSync) == 1 {
log.Warn("Discarded bad propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) log.Warn("Discarded bad propagated block", "number", block.Number(), "hash", block.Hash())
return 0, nil return nil
} }
atomic.StoreUint32(&manager.acceptTxs, 1) // Mark initial sync done on any fetcher import atomic.StoreUint32(&manager.acceptTxs, 1) // Mark initial sync done on any fetcher import
return manager.blockchain.InsertChain(blocks) return manager.blockchain.InsertBlock(block)
} }
manager.fetcher = fetcher.New(blockchain.GetBlockByHash, validator, manager.BroadcastBlock, heighter, inserter, manager.removePeer)
prepare := func(block *types.Block) error {
// If fast sync is running, deny importing weird blocks
if atomic.LoadUint32(&manager.fastSync) == 1 {
log.Warn("Discarded bad propagated block", "number", block.Number(), "hash", block.Hash())
return nil
}
atomic.StoreUint32(&manager.acceptTxs, 1) // Mark initial sync done on any fetcher import
return manager.blockchain.PrepareBlock(block)
}
manager.fetcher = fetcher.New(blockchain.GetBlockByHash, validator, manager.BroadcastBlock, heighter, inserter, prepare, manager.removePeer)
return manager, nil return manager, nil
} }

View file

@ -170,7 +170,6 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
currentBlock := pm.blockchain.CurrentBlock() currentBlock := pm.blockchain.CurrentBlock()
td := pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()) td := pm.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
pHead, pTd := peer.Head() pHead, pTd := peer.Head()
log.Debug("ProtocolManager synchronise ", "p", peer, "pTd", pTd, "currentTd", td)
if pTd.Cmp(td) <= 0 { if pTd.Cmp(td) <= 0 {
return return
} }

View file

@ -310,7 +310,6 @@ func (self *worker) update() {
self.commitNewWork() self.commitNewWork()
} }
} }
// System stopped
case <-self.chainHeadSub.Err(): case <-self.chainHeadSub.Err():
return return
case <-self.chainSideSub.Err(): case <-self.chainSideSub.Err():
@ -545,7 +544,6 @@ func (self *worker) commitNewWork() {
} }
} }
} }
tstamp := tstart.Unix() tstamp := tstart.Unix()
if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 { if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 {
tstamp = parent.Time().Int64() + 1 tstamp = parent.Time().Int64() + 1