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"
"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
}

View file

@ -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)
}()
}