diff --git a/eth/backend.go b/eth/backend.go index 2e9168ce35..cb9b82be9d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -24,6 +24,7 @@ import ( "runtime" "sync" "sync/atomic" + "time" "bytes" "github.com/ethereum/go-ethereum/accounts" @@ -188,6 +189,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { if eth.chainConfig.XDPoS != nil { c := eth.engine.(*XDPoS.XDPoS) signHook := func(block *types.Block) error { + ok, err := eth.ValidateMasternode() + if err != nil { + return fmt.Errorf("Can't verify masternode permission: %v", err) + } + if !ok { + // silently return as this node doesn't have masternode permission to sign block + return nil + } if err := contracts.CreateTransactionSign(chainConfig, eth.txPool, eth.accountManager, block, chainDb); err != nil { return fmt.Errorf("Fail to create tx sign for importing block: %v", err) } @@ -224,6 +233,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Hook prepares validators M2 for the current epoch c.HookValidator = func(header *types.Header, signers []common.Address) error { + start := time.Now() number := header.Number.Int64() if number > 0 && number%common.EpocBlockRandomize == 0 { validators, err := GetValidators(eth.blockchain, signers) @@ -232,6 +242,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } header.Validators = validators } + log.Debug("Time Calculated HookValidator ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) return nil } @@ -243,6 +254,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } prevEpoc := blockNumberEpoc - chain.Config().XDPoS.Epoch if prevEpoc >= 0 { + start := time.Now() prevHeader := chain.GetHeaderByNumber(prevEpoc) penSigners := c.GetMasternodes(chain, prevHeader) if len(penSigners) > 0 { @@ -271,6 +283,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } } + log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) return penSigners, nil } return []common.Address{}, nil @@ -288,13 +301,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { if foudationWalletAddr == (common.Address{}) { log.Error("Foundation Wallet Address is empty", "error", foudationWalletAddr) } + start := time.Now() if number > 0 && number-rCheckpoint > 0 && foudationWalletAddr != (common.Address{}) { // Get signers in blockSigner smartcontract. addr := common.HexToAddress(common.BlockSigners) // Get reward inflation. chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().XDPoS.Reward), new(big.Int).SetUint64(params.Ether)) chainReward = rewardInflation(chainReward, number, common.BlocksPerYear) - + totalSigner := new(uint64) signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) if err != nil { @@ -321,7 +335,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } } - + log.Debug("Time Calculated HookReward ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) return nil } @@ -329,7 +343,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { c.HookVerifyMNs = func(header *types.Header, signers []common.Address) error { number := header.Number.Int64() if number > 0 && number%common.EpocBlockRandomize == 0 { + start := time.Now() validators, err := GetValidators(eth.blockchain, signers) + log.Debug("Time Calculated HookVerifyMNs ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) if err != nil { return err } @@ -497,8 +513,8 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) { self.miner.SetEtherbase(etherbase) } -// ValidateMiner checks if node's address is in set of validators -func (s *Ethereum) ValidateStaker() (bool, error) { +// ValidateMasternode checks if node's address is in set of masternodes +func (s *Ethereum) ValidateMasternode() (bool, error) { eb, err := s.Etherbase() if err != nil { return false, err @@ -508,14 +524,14 @@ func (s *Ethereum) ValidateStaker() (bool, error) { c := s.engine.(*XDPoS.XDPoS) snap, err := c.GetSnapshot(s.blockchain, s.blockchain.CurrentHeader()) if err != nil { - return false, fmt.Errorf("Can't verify miner: %v", err) + return false, fmt.Errorf("Can't verify masternode permission: %v", err) } if _, authorized := snap.Signers[eb]; !authorized { //This miner doesn't belong to set of validators return false, nil } } else { - return false, fmt.Errorf("Only verify miners in XDPoS protocol") + return false, fmt.Errorf("Only verify masternode permission in XDPoS protocol") } return true, nil } diff --git a/eth/fetcher/fetcher.go b/eth/fetcher/fetcher.go index 6055847efa..5756ae3592 100644 --- a/eth/fetcher/fetcher.go +++ b/eth/fetcher/fetcher.go @@ -19,6 +19,7 @@ package fetcher import ( "errors" + "github.com/hashicorp/golang-lru" "math/rand" "time" @@ -62,7 +63,7 @@ type blockBroadcasterFn func(block *types.Block, propagate bool) type chainHeightFn func() uint64 // chainInsertFn is a callback type to insert a batch of blocks into the local chain. -type chainInsertFn func(types.Blocks) (int, error) +type chainInsertFn func(blocks types.Blocks) (int, error) // peerDropFn is a callback type for dropping a peer detected as malicious. type peerDropFn func(id string) @@ -128,7 +129,7 @@ type Fetcher struct { queue *prque.Prque // Queue containing the import operations (block number sorted) queues map[string]int // Per peer block counts to prevent memory exhaustion queued map[common.Hash]*inject // Set of already queued blocks (to dedup imports) - + knowns *lru.ARCCache // Callbacks getBlock blockRetrievalFn // Retrieves a block from the local chain verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work @@ -148,6 +149,7 @@ type Fetcher struct { // 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 { + knownBlocks, _ := lru.NewARC(blockLimit) return &Fetcher{ notify: make(chan *announce), inject: make(chan *inject), @@ -164,6 +166,7 @@ func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBloc queue: prque.New(), queues: make(map[string]int), queued: make(map[common.Hash]*inject), + knowns: knownBlocks, getBlock: getBlock, verifyHeader: verifyHeader, broadcastBlock: broadcastBlock, @@ -441,7 +444,7 @@ func (f *Fetcher) loop() { headerFilterInMeter.Mark(int64(len(task.headers))) // Split the batch of headers into unknown ones (to return to the caller), - // known incomplete ones (requiring body retrievals) and completed blocks. + // knowns incomplete ones (requiring body retrievals) and completed blocks. unknown, incomplete, complete := []*types.Header{}, []*announce{}, []*types.Block{} for _, header := range task.headers { hash := header.Hash() @@ -601,7 +604,10 @@ func (f *Fetcher) rescheduleComplete(complete *time.Timer) { // has not yet been seen. func (f *Fetcher) enqueue(peer string, block *types.Block) { hash := block.Hash() - + if f.knowns.Contains(hash) { + log.Debug("Discarded propagated block, knowns block", "peer", peer, "number", block.Number(), "hash", hash, "limit", blockLimit) + return + } // Ensure the peer isn't DOSing us count := f.queues[peer] + 1 if count > blockLimit { @@ -625,6 +631,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) { } f.queues[peer] = count f.queued[hash] = op + f.knowns.Add(hash, true) f.queue.Push(op, -float32(block.NumberU64())) if f.queueChangeHook != nil { f.queueChangeHook(op.block.Hash(), true) @@ -650,7 +657,7 @@ 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()) return } - again: + again: // Quickly validate the header and propagate the block if it passes switch err := f.verifyHeader(block.Header()); err { case nil: @@ -660,7 +667,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) { case consensus.ErrFutureBlock: delay := time.Unix(block.Time().Int64(), 0).Sub(time.Now()) // nolint: gosimple time.Sleep(delay) - log.Info("Receive futrue block", "number", block.NumberU64(), "hash", block.Hash().Hex(), "delay", delay) + log.Info("Receive future block", "number", block.NumberU64(), "hash", block.Hash().Hex(), "delay", delay) goto again case consensus.ErrMissingValidatorSignature: newBlock := block @@ -674,8 +681,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) { go f.broadcastBlock(block, true) return } - f.Enqueue(peer, newBlock) - return + block = newBlock default: // Something went very wrong, drop the peer log.Debug("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) @@ -695,11 +701,10 @@ func (f *Fetcher) insert(peer string, block *types.Block) { return } } - // If import succeeded, broadcast the block propAnnounceOutTimer.UpdateSince(block.ReceivedAt) + go f.broadcastBlock(block, true) go f.broadcastBlock(block, false) - }() }