fix error double validation : m2 not validate body before verify block

This commit is contained in:
MestryOmkar 2018-11-12 12:39:52 +05:30
parent 05ea5f10f7
commit 5111364215
2 changed files with 37 additions and 16 deletions

View file

@ -24,6 +24,7 @@ import (
"runtime" "runtime"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time"
"bytes" "bytes"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
@ -188,6 +189,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if eth.chainConfig.XDPoS != nil { if eth.chainConfig.XDPoS != nil {
c := eth.engine.(*XDPoS.XDPoS) c := eth.engine.(*XDPoS.XDPoS)
signHook := func(block *types.Block) error { 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 { 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) 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 // Hook prepares validators M2 for the current epoch
c.HookValidator = func(header *types.Header, signers []common.Address) error { c.HookValidator = func(header *types.Header, signers []common.Address) error {
start := time.Now()
number := header.Number.Int64() number := header.Number.Int64()
if number > 0 && number%common.EpocBlockRandomize == 0 { if number > 0 && number%common.EpocBlockRandomize == 0 {
validators, err := GetValidators(eth.blockchain, signers) validators, err := GetValidators(eth.blockchain, signers)
@ -232,6 +242,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
} }
header.Validators = validators header.Validators = validators
} }
log.Debug("Time Calculated HookValidator ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
return nil return nil
} }
@ -243,6 +254,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
} }
prevEpoc := blockNumberEpoc - chain.Config().XDPoS.Epoch prevEpoc := blockNumberEpoc - chain.Config().XDPoS.Epoch
if prevEpoc >= 0 { if prevEpoc >= 0 {
start := time.Now()
prevHeader := chain.GetHeaderByNumber(prevEpoc) prevHeader := chain.GetHeaderByNumber(prevEpoc)
penSigners := c.GetMasternodes(chain, prevHeader) penSigners := c.GetMasternodes(chain, prevHeader)
if len(penSigners) > 0 { 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 penSigners, nil
} }
return []common.Address{}, nil return []common.Address{}, nil
@ -288,13 +301,14 @@ 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{}) {
// 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.
chainReward := new(big.Int).Mul(new(big.Int).SetUint64(chain.Config().XDPoS.Reward), new(big.Int).SetUint64(params.Ether)) 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) chainReward = rewardInflation(chainReward, number, common.BlocksPerYear)
totalSigner := new(uint64) totalSigner := new(uint64)
signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner) signers, err := contracts.GetRewardForCheckpoint(chain, addr, number, rCheckpoint, client, totalSigner)
if err != nil { 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 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 { c.HookVerifyMNs = func(header *types.Header, signers []common.Address) error {
number := header.Number.Int64() number := header.Number.Int64()
if number > 0 && number%common.EpocBlockRandomize == 0 { if number > 0 && number%common.EpocBlockRandomize == 0 {
start := time.Now()
validators, err := GetValidators(eth.blockchain, signers) validators, err := GetValidators(eth.blockchain, signers)
log.Debug("Time Calculated HookVerifyMNs ", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
if err != nil { if err != nil {
return err return err
} }
@ -497,8 +513,8 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) {
self.miner.SetEtherbase(etherbase) self.miner.SetEtherbase(etherbase)
} }
// ValidateMiner checks if node's address is in set of validators // ValidateMasternode checks if node's address is in set of masternodes
func (s *Ethereum) ValidateStaker() (bool, error) { func (s *Ethereum) ValidateMasternode() (bool, error) {
eb, err := s.Etherbase() eb, err := s.Etherbase()
if err != nil { if err != nil {
return false, err return false, err
@ -508,14 +524,14 @@ func (s *Ethereum) ValidateStaker() (bool, error) {
c := s.engine.(*XDPoS.XDPoS) c := s.engine.(*XDPoS.XDPoS)
snap, err := c.GetSnapshot(s.blockchain, s.blockchain.CurrentHeader()) snap, err := c.GetSnapshot(s.blockchain, s.blockchain.CurrentHeader())
if err != nil { 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 { if _, authorized := snap.Signers[eb]; !authorized {
//This miner doesn't belong to set of validators //This miner doesn't belong to set of validators
return false, nil return false, nil
} }
} else { } 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 return true, nil
} }

View file

@ -19,6 +19,7 @@ package fetcher
import ( import (
"errors" "errors"
"github.com/hashicorp/golang-lru"
"math/rand" "math/rand"
"time" "time"
@ -62,7 +63,7 @@ type blockBroadcasterFn func(block *types.Block, propagate bool)
type chainHeightFn func() uint64 type chainHeightFn func() uint64
// chainInsertFn is a callback type to insert a batch of blocks into the local chain. // 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. // peerDropFn is a callback type for dropping a peer detected as malicious.
type peerDropFn func(id string) type peerDropFn func(id string)
@ -128,7 +129,7 @@ type Fetcher struct {
queue *prque.Prque // Queue containing the import operations (block number sorted) queue *prque.Prque // Queue containing the import operations (block number sorted)
queues map[string]int // Per peer block counts to prevent memory exhaustion 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) queued map[common.Hash]*inject // Set of already queued blocks (to dedup imports)
knowns *lru.ARCCache
// Callbacks // Callbacks
getBlock blockRetrievalFn // Retrieves a block from the local chain getBlock blockRetrievalFn // Retrieves a block from the local chain
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
@ -148,6 +149,7 @@ type Fetcher struct {
// 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, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher {
knownBlocks, _ := lru.NewARC(blockLimit)
return &Fetcher{ return &Fetcher{
notify: make(chan *announce), notify: make(chan *announce),
inject: make(chan *inject), inject: make(chan *inject),
@ -164,6 +166,7 @@ func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBloc
queue: prque.New(), queue: prque.New(),
queues: make(map[string]int), queues: make(map[string]int),
queued: make(map[common.Hash]*inject), queued: make(map[common.Hash]*inject),
knowns: knownBlocks,
getBlock: getBlock, getBlock: getBlock,
verifyHeader: verifyHeader, verifyHeader: verifyHeader,
broadcastBlock: broadcastBlock, broadcastBlock: broadcastBlock,
@ -441,7 +444,7 @@ func (f *Fetcher) loop() {
headerFilterInMeter.Mark(int64(len(task.headers))) headerFilterInMeter.Mark(int64(len(task.headers)))
// Split the batch of headers into unknown ones (to return to the caller), // 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{} unknown, incomplete, complete := []*types.Header{}, []*announce{}, []*types.Block{}
for _, header := range task.headers { for _, header := range task.headers {
hash := header.Hash() hash := header.Hash()
@ -601,7 +604,10 @@ func (f *Fetcher) rescheduleComplete(complete *time.Timer) {
// has not yet been seen. // has not yet been seen.
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) {
log.Debug("Discarded propagated block, knowns block", "peer", peer, "number", block.Number(), "hash", hash, "limit", blockLimit)
return
}
// Ensure the peer isn't DOSing us // Ensure the peer isn't DOSing us
count := f.queues[peer] + 1 count := f.queues[peer] + 1
if count > blockLimit { if count > blockLimit {
@ -625,6 +631,7 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
} }
f.queues[peer] = count f.queues[peer] = count
f.queued[hash] = op f.queued[hash] = op
f.knowns.Add(hash, true)
f.queue.Push(op, -float32(block.NumberU64())) f.queue.Push(op, -float32(block.NumberU64()))
if f.queueChangeHook != nil { if f.queueChangeHook != nil {
f.queueChangeHook(op.block.Hash(), true) 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()) log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash())
return return
} }
again: again:
// 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 := f.verifyHeader(block.Header()); err {
case nil: case nil:
@ -660,7 +667,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
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) 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 goto again
case consensus.ErrMissingValidatorSignature: case consensus.ErrMissingValidatorSignature:
newBlock := block newBlock := block
@ -674,8 +681,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
go f.broadcastBlock(block, true) go f.broadcastBlock(block, true)
return return
} }
f.Enqueue(peer, newBlock) block = newBlock
return
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)
@ -695,11 +701,10 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
return return
} }
} }
// 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)
go f.broadcastBlock(block, false) go f.broadcastBlock(block, false)
}() }()
} }