diff --git a/consensus/XDPoS/api.go b/consensus/XDPoS/api.go index 59232fae8ce7..b68214d564ae 100644 --- a/consensus/XDPoS/api.go +++ b/consensus/XDPoS/api.go @@ -189,12 +189,19 @@ func (api *API) GetMasternodesByNumber(number *rpc.BlockNumber) MasternodesStatu if number == nil || *number == rpc.LatestBlockNumber { header = api.chain.CurrentHeader() } else if *number == rpc.CommittedBlockNumber { - hash := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo().Hash - header = api.chain.GetHeaderByHash(hash) + if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil { + header = api.chain.GetHeaderByHash(info.Hash) + } } else { header = api.chain.GetHeaderByNumber(uint64(number.Int64())) } + if header == nil { + return MasternodesStatus{ + Error: fmt.Errorf("can not get header by number: %v", number), + } + } + round, err := api.XDPoS.EngineV2.GetRoundNumber(header) if err != nil { return MasternodesStatus{ @@ -306,14 +313,19 @@ func (api *API) GetV2BlockByHeader(header *types.Header, uncle bool) *V2BlockInf func (api *API) GetV2BlockByNumber(number *rpc.BlockNumber) *V2BlockInfo { header := api.getHeaderFromApiBlockNum(number) if header == nil { - return &V2BlockInfo{ - Number: big.NewInt(number.Int64()), - Error: "can not find block from this number", + if number == nil { + return &V2BlockInfo{ + Error: "can not find block from nil number", + } + } else { + return &V2BlockInfo{ + Number: big.NewInt(number.Int64()), + Error: "can not find block from this number", + } } } - uncle := false - return api.GetV2BlockByHeader(header, uncle) + return api.GetV2BlockByHeader(header, false) } // Confirm V2 Block Committed Status @@ -328,11 +340,14 @@ func (api *API) GetV2BlockByHash(blockHash common.Hash) *V2BlockInfo { // confirm this is on the main chain chainHeader := api.chain.GetHeaderByNumber(header.Number.Uint64()) - uncle := false - if header.Hash() != chainHeader.Hash() { - uncle = true + if chainHeader == nil { + return &V2BlockInfo{ + Number: header.Number, + Error: "can not find chain header from this number", + } } + uncle := header.Hash() != chainHeader.Hash() return api.GetV2BlockByHeader(header, uncle) } @@ -361,8 +376,9 @@ func (api *API) getHeaderFromApiBlockNum(number *rpc.BlockNumber) *types.Header if number == nil || *number == rpc.LatestBlockNumber { header = api.chain.CurrentHeader() } else if *number == rpc.CommittedBlockNumber { - hash := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo().Hash - header = api.chain.GetHeaderByHash(hash) + if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil { + header = api.chain.GetHeaderByHash(info.Hash) + } } else { header = api.chain.GetHeaderByNumber(uint64(number.Int64())) } diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index 3a62b58f6e7e..d408a23bd815 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -874,6 +874,10 @@ func (x *XDPoS_v2) commitBlocks(blockChainReader consensus.ChainReader, proposed } // Find the last two parent block and check their rounds are the continuous parentBlock := blockChainReader.GetHeaderByHash(proposedBlockHeader.ParentHash) + if parentBlock == nil { + log.Error("[commitBlocks] Fail to get header by parent hash", "hash", proposedBlockHeader.ParentHash) + return false, fmt.Errorf("commitBlocks fail to get header by parent hash: %v", proposedBlockHeader.ParentHash) + } _, round, _, err := x.getExtraFields(parentBlock) if err != nil { @@ -887,6 +891,10 @@ func (x *XDPoS_v2) commitBlocks(blockChainReader consensus.ChainReader, proposed // If parent round is continuous, we check grandparent grandParentBlock := blockChainReader.GetHeaderByHash(parentBlock.ParentHash) + if grandParentBlock == nil { + log.Error("[commitBlocks] Fail to get header by grandparent hash", "hash", parentBlock.ParentHash) + return false, fmt.Errorf("commitBlocks fail to get header by grandparent hash: %v", parentBlock.ParentHash) + } _, round, _, err = x.getExtraFields(grandParentBlock) if err != nil { log.Error("Fail to execute second DecodeBytesExtraFields for committing block", "parentBlockHash", parentBlock.Hash()) diff --git a/consensus/XDPoS/engines/engine_v2/snapshot.go b/consensus/XDPoS/engines/engine_v2/snapshot.go index f0ce71a2d434..84aeaf5f5e16 100644 --- a/consensus/XDPoS/engines/engine_v2/snapshot.go +++ b/consensus/XDPoS/engines/engine_v2/snapshot.go @@ -2,6 +2,7 @@ package engine_v2 import ( "encoding/json" + "fmt" "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/consensus" @@ -84,7 +85,12 @@ func (x *XDPoS_v2) getSnapshot(chain consensus.ChainReader, number uint64, isGap } } - gapBlockHash := chain.GetHeaderByNumber(gapBlockNum).Hash() + gapHeader := chain.GetHeaderByNumber(gapBlockNum) + if gapHeader == nil { + log.Error("[getSnapshot] Fail to get header", "number", gapBlockNum) + return nil, fmt.Errorf("getSnapshot fail to get header by number: %v", gapBlockNum) + } + gapBlockHash := gapHeader.Hash() log.Debug("get snapshot from gap block", "number", gapBlockNum, "hash", gapBlockHash.Hex()) // If an in-memory SnapshotV2 was found, use that diff --git a/consensus/XDPoS/engines/engine_v2/utils.go b/consensus/XDPoS/engines/engine_v2/utils.go index 176bb442fde2..64de39fccd14 100644 --- a/consensus/XDPoS/engines/engine_v2/utils.go +++ b/consensus/XDPoS/engines/engine_v2/utils.go @@ -96,6 +96,9 @@ func (x *XDPoS_v2) signSignature(signingHash common.Hash) (types.Signature, erro signer, signFn := x.signer, x.signFn x.signLock.RUnlock() + if signFn == nil { + return nil, errors.New("signFn is nil") + } signedHash, err := signFn(accounts.Account{Address: signer}, signingHash.Bytes()) if err != nil { return nil, fmt.Errorf("error %v while signing hash", err) @@ -182,6 +185,9 @@ func (x *XDPoS_v2) CalculateMissingRounds(chain consensus.ChainReader, header *t nextHeader := header for nextHeader.Number.Cmp(switchInfo.EpochSwitchBlockInfo.Number) > 0 { parentHeader := chain.GetHeaderByHash(nextHeader.ParentHash) + if parentHeader == nil { + return nil, fmt.Errorf("fail to get header by hash %v: ", nextHeader.ParentHash) + } parentRound, err := x.GetRoundNumber(parentHeader) if err != nil { return nil, err @@ -299,6 +305,9 @@ func (x *XDPoS_v2) binarySearchBlockByEpochNumber(chain consensus.ChainReader, t func (x *XDPoS_v2) GetBlockByEpochNumber(chain consensus.ChainReader, targetEpochNum uint64) (*types.BlockInfo, error) { currentHeader := chain.CurrentHeader() + if currentHeader == nil { + return nil, errors.New("current header is nil") + } epochSwitchInfo, err := x.getEpochSwitchInfo(chain, currentHeader, currentHeader.Hash()) if err != nil { return nil, err @@ -332,6 +341,9 @@ func (x *XDPoS_v2) GetBlockByEpochNumber(chain consensus.ChainReader, targetEpoc closeEpochNum := uint64(2) if closeEpochNum >= epochNum-targetEpochNum { estBlockHeader := chain.GetHeaderByNumber(estBlockNum.Uint64()) + if estBlockHeader == nil { + return nil, fmt.Errorf("fail to get est block header by number: %v", estBlockNum) + } epochSwitchInfos, err := x.GetEpochSwitchInfoBetween(chain, estBlockHeader, currentHeader) if err != nil { return nil, err diff --git a/consensus/XDPoS/engines/engine_v2/verifyHeader.go b/consensus/XDPoS/engines/engine_v2/verifyHeader.go index 199f1997e153..c64a280d332c 100644 --- a/consensus/XDPoS/engines/engine_v2/verifyHeader.go +++ b/consensus/XDPoS/engines/engine_v2/verifyHeader.go @@ -79,6 +79,10 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade log.Warn("[verifyHeader] decode extra field error", "err", err) return utils.ErrInvalidV2Extra } + if quorumCert == nil { + log.Warn("[verifyHeader] quorumCert is nil") + return utils.ErrInvalidQuorumCert + } minePeriod := uint64(x.config.V2.Config(uint64(round)).MinePeriod) if parent.Number.Uint64() >= x.config.V2.SwitchBlock.Uint64() && parent.Time+minePeriod > header.Time { diff --git a/consensus/XDPoS/utils/errors.go b/consensus/XDPoS/utils/errors.go index eec246b54b7b..da11a6871838 100644 --- a/consensus/XDPoS/utils/errors.go +++ b/consensus/XDPoS/utils/errors.go @@ -88,6 +88,7 @@ var ( ErrEmptyEpochSwitchValidators = errors.New("empty validators list on epoch switch block") ErrInvalidV2Extra = errors.New("invalid v2 extra in the block") + ErrInvalidQuorumCert = errors.New("invalid quorum cert") ErrInvalidQC = errors.New("invalid QC content") ErrInvalidQCSignatures = errors.New("invalid QC Signatures") ErrInvalidTC = errors.New("invalid TC content") diff --git a/core/blockchain.go b/core/blockchain.go index 3747a087a7a1..7e6ba427a18f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -743,7 +743,11 @@ func (bc *BlockChain) repair(head **types.Block) error { log.Info("Rewound blockchain to past state", "number", (*head).Number(), "hash", (*head).Hash()) } // Otherwise rewind one block and recheck state availability there - (*head) = bc.GetBlock((*head).ParentHash(), (*head).NumberU64()-1) + block := bc.GetBlock((*head).ParentHash(), (*head).NumberU64()-1) + if block == nil { + panic(fmt.Sprintf("repair fail to get block at number: %v, hash: %v", (*head).NumberU64()-1, (*head).ParentHash())) + } + (*head) = block } } @@ -1018,10 +1022,16 @@ func (bc *BlockChain) GetBlocksHashCache(number uint64) []common.Hash { func (bc *BlockChain) AreTwoBlockSamePath(bh1 common.Hash, bh2 common.Hash) bool { bl1 := bc.GetBlockByHash(bh1) bl2 := bc.GetBlockByHash(bh2) - toBlockLevel := bl2.Number().Uint64() + if bl1 == nil || bl2 == nil { + return false + } + toBlockLevel := bl2.Number().Uint64() for bl1.Number().Uint64() > toBlockLevel { bl1 = bc.GetBlockByHash(bl1.ParentHash()) + if bl1 == nil { + return false + } } return (bl1.Hash() == bl2.Hash()) @@ -2141,6 +2151,9 @@ func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*Resu var winner []*types.Block parent := bc.GetBlock(block.ParentHash(), block.NumberU64()-1) + if parent == nil { + return nil, fmt.Errorf("fail to get parent block at number: %v, hash: %v", block.NumberU64()-1, block.ParentHash()) + } for !bc.HasFullState(parent) { winner = append(winner, parent) parent = bc.GetBlock(parent.ParentHash(), parent.NumberU64()-1) diff --git a/eth/hooks/engine_v2_hooks.go b/eth/hooks/engine_v2_hooks.go index 5a1c2f68fb8f..54d17d47cf2b 100644 --- a/eth/hooks/engine_v2_hooks.go +++ b/eth/hooks/engine_v2_hooks.go @@ -2,6 +2,7 @@ package hooks import ( "errors" + "fmt" "math/big" "time" @@ -72,6 +73,10 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf for i := uint64(1); ; i++ { parentHeader := chain.GetHeader(parentHash, parentNumber) + if parentHeader == nil { + log.Error("[HookPenalty] fail to get parent header") + return []common.Address{}, fmt.Errorf("hook penalty fail to get parent header at number: %v, hash: %v", parentNumber, parentHash) + } isEpochSwitch, _, err := adaptor.EngineV2.IsEpochSwitch(parentHeader) if err != nil { log.Error("[HookPenalty] isEpochSwitch", "err", err) @@ -149,8 +154,10 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf signingTxs, ok := adaptor.GetCachedSigningTxs(bhash) if !ok { block := chain.GetBlock(bhash, blockNumber) - txs := block.Transactions() - signingTxs = adaptor.CacheSigningTxs(bhash, txs) + if block != nil { + txs := block.Transactions() + signingTxs = adaptor.CacheSigningTxs(bhash, txs) + } } // Check signer signed? for _, tx := range signingTxs { @@ -221,8 +228,10 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf signingTxs, ok := adaptor.GetCachedSigningTxs(bhash) if !ok { block := chain.GetBlock(bhash, blockNumber) - txs := block.Transactions() - signingTxs = adaptor.CacheSigningTxs(bhash, txs) + if block != nil { + txs := block.Transactions() + signingTxs = adaptor.CacheSigningTxs(bhash, txs) + } } // Check signer signed? for _, tx := range signingTxs { @@ -404,7 +413,12 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type h := header for i := number - 1; ; i-- { - h = chain.GetHeader(h.ParentHash, i) + parentHash := h.ParentHash + h = chain.GetHeader(parentHash, i) + if h == nil { + log.Error("[GetSigningTxCount] fail to get header", "number", i, "hash", parentHash) + return nil, fmt.Errorf("fail to get header in GetSigningTxCount at number: %v, hash: %v", i, parentHash) + } isEpochSwitch, _, err := c.IsEpochSwitch(h) if err != nil { return nil, err @@ -464,8 +478,10 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type if !ok { log.Debug("Failed get from cached", "hash", h.Hash().String(), "number", i) block := chain.GetBlock(h.Hash(), i) - txs := block.Transactions() - signingTxs = c.CacheSigningTxs(h.Hash(), txs) + if block != nil { + txs := block.Transactions() + signingTxs = c.CacheSigningTxs(h.Hash(), txs) + } } for _, tx := range signingTxs { blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:])