mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
Parallel process block from fetcher
This commit is contained in:
parent
e4e7061482
commit
33ddb251ef
14 changed files with 429 additions and 93 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue