From 6adee64867beb5a4ae05dcbe9dfd249c94ab649e Mon Sep 17 00:00:00 2001 From: parmarrushabh Date: Wed, 27 Feb 2019 14:58:16 +0530 Subject: [PATCH] handle SignHash error --- eth/backend.go | 318 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 234 insertions(+), 84 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index ca44202c5b..df9c20870d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -18,12 +18,13 @@ package eth import ( - "encoding/json" "errors" "fmt" - "io/ioutil" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/rlp" "math/big" - "path/filepath" "runtime" "sync" "sync/atomic" @@ -32,19 +33,16 @@ import ( "bytes" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/XDPoS" "github.com/ethereum/go-ethereum/contracts" - "github.com/ethereum/go-ethereum/contracts/validator/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" - "github.com/ethereum/go-ethereum/core/state" + //"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -54,7 +52,6 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" ) @@ -173,6 +170,25 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) + if common.RollbackHash != common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") { + curBlock := eth.blockchain.CurrentBlock() + prevBlock := eth.blockchain.GetBlockByHash(common.RollbackHash) + + if curBlock.NumberU64() > prevBlock.NumberU64() { + for ; curBlock != nil && curBlock.NumberU64() != prevBlock.NumberU64(); curBlock = eth.blockchain.GetBlock(curBlock.ParentHash(), curBlock.NumberU64()-1) { + eth.blockchain.Rollback([]common.Hash{curBlock.Hash()}) + } + } + + if prevBlock != nil { + err := eth.blockchain.SetHead(prevBlock.NumberU64()) + if err != nil { + log.Crit("Err Rollback", "err", err) + return nil, err + } + } + } + if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil { return nil, err } @@ -192,16 +208,19 @@ 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() + eb, err := eth.Etherbase() if err != nil { - return fmt.Errorf("Can't verify masternode permission: %v", err) + log.Error("Cannot get etherbase for append m2 header", "err", err) + return fmt.Errorf("etherbase missing: %v", err) } + ok := eth.txPool.IsSigner != nil && eth.txPool.IsSigner(eb) 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) + if block.NumberU64()%common.MergeSignRange == 0 || !eth.chainConfig.IsTIP2019(block.Number()) { + 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 nil } @@ -221,9 +240,15 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return block, false, fmt.Errorf("can't get block validator: %v", err) } if m2 == eb { - wallet, _ := eth.accountManager.Find(accounts.Account{Address: eb}) + wallet, err := eth.accountManager.Find(accounts.Account{Address: eb}) + if err != nil { + return block, false, err + } header := block.Header() - sighash, _ := wallet.SignHash(accounts.Account{Address: eb}, XDPoS.SigHash(header).Bytes()) + sighash, err := wallet.SignHash(accounts.Account{Address: eb}, XDPoS.SigHash(header).Bytes()) + if err != nil { + return block, false, err + } header.Validator = sighash return types.NewBlockWithHeader(header).WithBody(block.Transactions(), block.Uncles()), true, nil } @@ -247,9 +272,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Hook scans for bad masternodes and decide to penalty them c.HookPenalty = func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) { - client, err := eth.blockchain.GetClient() - if err != nil { - return nil, err + canonicalState, err := eth.blockchain.State() + if canonicalState == nil || err != nil { + log.Crit("Can't get state at head of canonical chain", "head number", eth.blockchain.CurrentHeader().Number.Uint64(), "err", err) } prevEpoc := blockNumberEpoc - chain.Config().XDPoS.Epoch if prevEpoc >= 0 { @@ -257,28 +282,31 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { prevHeader := chain.GetHeaderByNumber(prevEpoc) penSigners := c.GetMasternodes(chain, prevHeader) if len(penSigners) > 0 { - blockSignerAddr := common.HexToAddress(common.BlockSigners) // Loop for each block to check missing sign. for i := prevEpoc; i < blockNumberEpoc; i++ { - blockHeader := chain.GetHeaderByNumber(i) - if len(penSigners) > 0 { - signedMasternodes, err := contracts.GetSignersFromContract(blockSignerAddr, client, blockHeader.Hash()) - if err != nil { - return nil, err - } - if len(signedMasternodes) > 0 { - // Check signer signed? - for _, signed := range signedMasternodes { - for j, addr := range penSigners { - if signed == addr { - // Remove it from dupSigners. - penSigners = append(penSigners[:j], penSigners[j+1:]...) + if i%common.MergeSignRange == 0 || !chainConfig.IsTIP2019(big.NewInt(int64(i))) { + bheader := chain.GetHeaderByNumber(i) + bhash := bheader.Hash() + block := chain.GetBlock(bhash, i) + if len(penSigners) > 0 { + signedMasternodes, err := contracts.GetSignersFromContract(canonicalState, block) + if err != nil { + return nil, err + } + if len(signedMasternodes) > 0 { + // Check signer signed? + for _, signed := range signedMasternodes { + for j, addr := range penSigners { + if signed == addr { + // Remove it from dupSigners. + penSigners = append(penSigners[:j], penSigners[j+1:]...) + } } } } + } else { + break } - } else { - break } } } @@ -288,54 +316,159 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return []common.Address{}, nil } + // Hook scans for bad masternodes and decide to penalty them + c.HookPenaltyTIPSigning = func(chain consensus.ChainReader, header *types.Header, candidates []common.Address) ([]common.Address, error) { + prevEpoc := header.Number.Uint64() - chain.Config().XDPoS.Epoch + combackEpoch := uint64(0) + comebackLength := uint64((common.LimitPenaltyEpoch + 1) * chain.Config().XDPoS.Epoch) + if header.Number.Uint64() > comebackLength { + combackEpoch = header.Number.Uint64() - comebackLength + } + if prevEpoc >= 0 { + start := time.Now() + + listBlockHash := make([]common.Hash, chain.Config().XDPoS.Epoch) + + // get list block hash & stats total created block + statMiners := make(map[common.Address]int) + listBlockHash[0] = header.ParentHash + parentnumber := header.Number.Uint64() - 1 + parentHash := header.ParentHash + for i := uint64(1); i < chain.Config().XDPoS.Epoch; i++ { + parentHeader := chain.GetHeader(parentHash, parentnumber) + miner, _ := c.RecoverSigner(parentHeader) + value, exist := statMiners[miner] + if exist { + value = value + 1 + } else { + value = 1 + } + statMiners[miner] = value + parentHash = parentHeader.ParentHash + parentnumber-- + listBlockHash[i] = parentHash + } + + // add list not miner to penalties + prevHeader := chain.GetHeaderByNumber(prevEpoc) + preMasternodes := c.GetMasternodes(chain, prevHeader) + penalties := []common.Address{} + for miner, total := range statMiners { + if total < common.MinimunMinerBlockPerEpoch { + log.Debug("Find a node not enough requirement create block", "addr", miner.Hex(), "total", total) + penalties = append(penalties, miner) + } + } + for _, addr := range preMasternodes { + if _, exist := statMiners[addr]; !exist { + log.Debug("Find a node don't create block", "addr", addr.Hex()) + penalties = append(penalties, addr) + } + } + + // get list check penalties signing block & list master nodes wil comeback + penComebacks := []common.Address{} + if combackEpoch > 0 { + combackHeader := chain.GetHeaderByNumber(combackEpoch) + penalties := common.ExtractAddressFromBytes(combackHeader.Penalties) + for _, penaltie := range penalties { + for _, addr := range candidates { + if penaltie == addr { + penComebacks = append(penComebacks, penaltie) + } + } + } + } + + // Loop for each block to check missing sign. with comeback nodes + mapBlockHash := map[common.Hash]bool{} + for i := common.RangeReturnSigner - 1; i >= 0; i-- { + if len(penComebacks) > 0 { + blockNumber := header.Number.Uint64() - uint64(i) - 1 + bhash := listBlockHash[i] + if blockNumber%common.MergeSignRange == 0 { + mapBlockHash[bhash] = true + } + signData, ok := c.BlockSigners.Get(bhash) + if !ok { + block := chain.GetBlock(bhash, blockNumber) + txs := block.Transactions() + signData = c.CacheSigner(bhash, txs) + } + txs := signData.([]*types.Transaction) + // Check signer signed? + for _, tx := range txs { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + if mapBlockHash[blkHash] { + for j, addr := range penComebacks { + if from == addr { + // Remove it from dupSigners. + penComebacks = append(penComebacks[:j], penComebacks[j+1:]...) + break + } + } + } + } + } else { + break + } + } + + log.Debug("Time Calculated HookPenaltyTIPSigning ", "block", header.Number, "hash", header.Hash().Hex(), "pen comeback nodes", len(penComebacks), "not enough miner", len(penalties), "time", common.PrettyDuration(time.Since(start))) + penalties = append(penalties, penComebacks...) + return penComebacks, nil + + } + return []common.Address{}, nil + } + // Hook calculates reward for masternodes - c.HookReward = func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) { - client, err := eth.blockchain.GetClient() - if err != nil { - log.Error("Fail to connect IPC client for blockSigner", "error", err) - return err, nil + c.HookReward = func(chain consensus.ChainReader, stateBlock *state.StateDB, header *types.Header) (error, map[string]interface{}) { + parentHeader := eth.blockchain.GetHeader(header.ParentHash, header.Number.Uint64()-1) + canonicalState, err := eth.blockchain.StateAt(parentHeader.Root) + if canonicalState == nil || err != nil { + log.Crit("Can't get state at head of canonical chain", "head number", header.Number.Uint64(), "err", err) } number := header.Number.Uint64() rCheckpoint := chain.Config().XDPoS.RewardCheckpoint - foudationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr - if foudationWalletAddr == (common.Address{}) { - log.Error("Foundation Wallet Address is empty", "error", foudationWalletAddr) + foundationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr + if foundationWalletAddr == (common.Address{}) { + log.Error("Foundation Wallet Address is empty", "error", foundationWalletAddr) + return err, nil } rewards := make(map[string]interface{}) - if number > 0 && number-rCheckpoint > 0 && foudationWalletAddr != (common.Address{}) { + if number > 0 && number-rCheckpoint > 0 && foundationWalletAddr != (common.Address{}) { start := time.Now() // 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) + signers, err := contracts.GetRewardForCheckpoint(c, chain, header, rCheckpoint, totalSigner) + + log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start))) if err != nil { - log.Error("Fail to get signers for reward checkpoint", "error", err) - return err, nil + log.Crit("Fail to get signers for reward checkpoint", "error", err) } rewards["signers"] = signers rewardSigners, err := contracts.CalculateRewardForSigner(chainReward, signers, *totalSigner) if err != nil { - log.Error("Fail to calculate reward for signers", "error", err) - return err, nil - } - // Get validator. - validator, err := contract.NewXDCValidator(common.HexToAddress(common.MasternodeVotingSMC), client) - if err != nil { - log.Error("Fail get instance of XDC Validator", "error", err) - return err, nil + log.Crit("Fail to calculate reward for signers", "error", err) } // Add reward for coin holders. voterResults := make(map[common.Address]interface{}) if len(signers) > 0 { for signer, calcReward := range rewardSigners { - err, rewards := contracts.CalculateRewardForHolders(foudationWalletAddr, validator, state, signer, calcReward) + err, rewards := contracts.CalculateRewardForHolders(foundationWalletAddr, canonicalState, signer, calcReward, number) if err != nil { - log.Error("Fail to calculate reward for holders.", "error", err) - return err, nil + log.Crit("Fail to calculate reward for holders.", "error", err) + } + if len(rewards) > 0 { + for holder, reward := range rewards { + stateBlock.AddBalance(holder, reward) + } } voterResults[signer] = rewards } @@ -362,11 +495,20 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } return nil } - eth.txPool.IsMasterNode = func(address common.Address) bool { + + eth.txPool.IsSigner = func(address common.Address) bool { currentHeader := eth.blockchain.CurrentHeader() - snap, err := c.GetSnapshot(eth.blockchain, currentHeader) + header := currentHeader + // Sometimes, the latest block hasn't been inserted to chain yet + // getSnapshot from parent block if it exists + parentHeader := eth.blockchain.GetHeader(currentHeader.ParentHash, currentHeader.Number.Uint64()-1) + if parentHeader != nil { + // not genesis block + header = parentHeader + } + snap, err := c.GetSnapshot(eth.blockchain, header) if err != nil { - log.Error("Can't get snapshot with current header ", "number", currentHeader.Number, "hash", currentHeader.Hash().Hex(), "err", err) + log.Error("Can't get snapshot with at ", "number", header.Number, "hash", header.Hash().Hex(), "err", err) return false } if _, ok := snap.Signers[address]; ok { @@ -374,27 +516,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } return false } - eth.blockchain.HookWriteRewards = func(header *types.Header) { - if len(config.StoreRewardFolder) > 0 { - rewards := c.GetRewards(header.Hash()) - if rewards == nil { - rewards = c.GetRewards(header.HashNoValidator()) - if rewards != nil { - c.InsertRewards(header.Hash(), rewards) - } - } - if rewards == nil { - return - } - data, err := json.Marshal(rewards) - if err == nil { - err = ioutil.WriteFile(filepath.Join(config.StoreRewardFolder, header.Number.String()+"."+header.Hash().Hex()), data, 0644) - } - if err != nil { - log.Error("Error when save reward info ", "number", header.Number, "hash", header.Hash().Hex(), "err", err) - } - } - } } return eth, nil } @@ -430,10 +551,11 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chainConfig *params.ChainConfig, db ethdb.Database) consensus.Engine { - // If XinFin-DPoS is requested, set it up + // If Xinfin-XDPoS voting is requested, set it up if chainConfig.XDPoS != nil { return XDPoS.New(chainConfig.XDPoS, db) } + // Otherwise assume proof-of-work switch { case config.PowMode == ethash.ModeFake: @@ -575,6 +697,28 @@ func (s *Ethereum) ValidateMasternode() (bool, error) { return true, nil } +// ValidateMasternodeTestNet checks if node's address is in set of masternodes in Testnet +func (s *Ethereum) ValidateMasternodeTestnet() (bool, error) { + eb, err := s.Etherbase() + if err != nil { + return false, err + } + if s.chainConfig.XDPoS == nil { + return false, fmt.Errorf("Only verify masternode permission in XDPoS protocol") + } + masternodes := []common.Address{ + common.HexToAddress("0xfFC679Dcdf444D2eEb0491A998E7902B411CcF20"), + common.HexToAddress("0xd76fd76F7101811726DCE9E43C2617706a4c45c8"), + common.HexToAddress("0x8A97753311aeAFACfd76a68Cf2e2a9808d3e65E8"), + } + for _, m := range masternodes { + if m == eb { + return true, nil + } + } + return false, nil +} + func (s *Ethereum) StartStaking(local bool) error { eb, err := s.Etherbase() if err != nil { @@ -600,7 +744,9 @@ func (s *Ethereum) StartStaking(local bool) error { return nil } -func (s *Ethereum) StopStaking() { s.miner.Stop() } +func (s *Ethereum) StopStaking() { + s.miner.Stop() +} func (s *Ethereum) IsStaking() bool { return s.miner.Mining() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } @@ -715,3 +861,7 @@ func rewardInflation(chainReward *big.Int, number uint64, blockPerYear uint64) * return chainReward } + +func (s *Ethereum) GetPeer() int { + return len(s.protocolManager.peers.peers) +} \ No newline at end of file