mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
Fix some panic cuased by nil block, statedb, header (#578)
* fix panic during rollback * eth/hooks: check nil stateDB to fix issue #271 * internal/ethapi: fix eth_call crash * all: check nil statedb * eth: check nil block for tracer api * internal/ethapi: check nil header and block
This commit is contained in:
parent
e9e94e640d
commit
4976b7cbb3
6 changed files with 80 additions and 11 deletions
|
|
@ -2584,6 +2584,8 @@ func (bc *BlockChain) UpdateM1() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if stateDB == nil {
|
||||
return errors.New("nil stateDB in UpdateM1")
|
||||
} else {
|
||||
candidates = state.GetCandidates(stateDB)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -443,7 +442,11 @@ func (b *EthApiBackend) GetVotersRewards(masternodeAddr common.Address) map[comm
|
|||
|
||||
state, err := chain.StateAt(lastCheckpointBlock.Root())
|
||||
if err != nil {
|
||||
fmt.Println("ERROR Trying to getting state at", lastCheckpointNumber, " Error ", err)
|
||||
log.Error("fail to get state in GetVotersRewards", "lastCheckpointNumber", lastCheckpointNumber, "err", err)
|
||||
return nil
|
||||
}
|
||||
if state == nil {
|
||||
log.Error("fail to get state in GetVotersRewards", "lastCheckpointNumber", lastCheckpointNumber)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +506,11 @@ func (b *EthApiBackend) GetVotersCap(checkpoint *big.Int, masterAddr common.Addr
|
|||
state, err := chain.StateAt(checkpointBlock.Root())
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("ERROR Trying to getting state at", checkpoint, " Error ", err)
|
||||
log.Error("fail to get state in GetVotersCap", "checkpoint", checkpoint, "err", err)
|
||||
return nil
|
||||
}
|
||||
if state != nil {
|
||||
log.Error("fail to get state in GetVotersCap", "checkpoint", checkpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -533,9 +540,12 @@ func (b *EthApiBackend) GetEpochDuration() *big.Int {
|
|||
func (b *EthApiBackend) GetMasternodesCap(checkpoint uint64) map[common.Address]*big.Int {
|
||||
checkpointBlock := b.eth.blockchain.GetBlockByNumber(checkpoint)
|
||||
state, err := b.eth.blockchain.StateAt(checkpointBlock.Root())
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("ERROR Trying to getting state at", checkpoint, " Error ", err)
|
||||
log.Error("fail to get state in GetMasternodesCap", "checkpoint", checkpoint, "err", err)
|
||||
return nil
|
||||
}
|
||||
if state == nil {
|
||||
log.Error("fail to get state in GetMasternodesCap", "checkpoint", checkpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,32 @@ type txTraceTask struct {
|
|||
index int // Transaction offset in the block
|
||||
}
|
||||
|
||||
// blockByNumber is the wrapper of the chain access function offered by the backend.
|
||||
// It will return an error if the block is not found.
|
||||
func (api *PrivateDebugAPI) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
|
||||
block, err := api.eth.ApiBackend.BlockByNumber(ctx, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block #%d not found", number)
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// blockByHash is the wrapper of the chain access function offered by the backend.
|
||||
// It will return an error if the block is not found.
|
||||
func (api *PrivateDebugAPI) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||
block, err := api.eth.ApiBackend.BlockByHash(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block %s not found", hash.Hex())
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// TraceChain returns the structured logs created during the execution of EVM
|
||||
// between two blocks (excluding start) and returns them as a JSON object.
|
||||
func (api *PrivateDebugAPI) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) {
|
||||
|
|
@ -640,7 +666,7 @@ func (api *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.CallArgs,
|
|||
block *types.Block
|
||||
)
|
||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||
block, err = api.eth.ApiBackend.BlockByHash(ctx, hash)
|
||||
block, err = api.blockByHash(ctx, hash)
|
||||
} else if number, ok := blockNrOrHash.Number(); ok {
|
||||
if number == rpc.PendingBlockNumber {
|
||||
// We don't have access to the miner here. For tracing 'future' transactions,
|
||||
|
|
@ -650,7 +676,7 @@ func (api *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.CallArgs,
|
|||
// of what the next actual block is likely to contain.
|
||||
return nil, errors.New("tracing on top of pending is not supported")
|
||||
}
|
||||
block, err = api.eth.ApiBackend.BlockByNumber(ctx, number)
|
||||
block, err = api.blockByNumber(ctx, number)
|
||||
} else {
|
||||
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,11 +192,14 @@ func New(ctx *node.ServiceContext, config *ethconfig.Config, XDCXServ *XDCx.XDCX
|
|||
eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain)
|
||||
eth.orderPool = core.NewOrderPool(eth.chainConfig, eth.blockchain)
|
||||
eth.lendingPool = core.NewLendingPool(eth.chainConfig, eth.blockchain)
|
||||
if common.RollbackHash != common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") {
|
||||
if common.RollbackHash != (common.Hash{}) {
|
||||
curBlock := eth.blockchain.CurrentBlock()
|
||||
if curBlock == nil {
|
||||
log.Warn("not find current block when rollback")
|
||||
}
|
||||
prevBlock := eth.blockchain.GetBlockByHash(common.RollbackHash)
|
||||
|
||||
if curBlock.NumberU64() > prevBlock.NumberU64() {
|
||||
if curBlock != nil && prevBlock != nil && 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()})
|
||||
}
|
||||
|
|
@ -208,6 +211,8 @@ func New(ctx *node.ServiceContext, config *ethconfig.Config, XDCXServ *XDCx.XDCX
|
|||
log.Crit("Err Rollback", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
log.Error("skip SetHead because target block is nil when rollback")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,11 +228,14 @@ func AttachConsensusV1Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
|||
)
|
||||
|
||||
stateDB, err := bc.StateAt(bc.GetBlockByHash(block).Root())
|
||||
candidateAddresses = state.GetCandidates(stateDB)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stateDB == nil {
|
||||
return nil, errors.New("nil stateDB in HookGetSignersFromContract")
|
||||
}
|
||||
|
||||
candidateAddresses = state.GetCandidates(stateDB)
|
||||
for _, address := range candidateAddresses {
|
||||
v, err := validator.GetCandidateCap(opts, address)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -897,6 +897,10 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd
|
|||
result[fieldSuccess] = false
|
||||
return result, err
|
||||
}
|
||||
if statedb == nil {
|
||||
result[fieldSuccess] = false
|
||||
return result, errors.New("nil statedb in GetCandidateStatus")
|
||||
}
|
||||
candidatesAddresses := state.GetCandidates(statedb)
|
||||
candidates = make([]utils.Masternode, 0, len(candidatesAddresses))
|
||||
for _, address := range candidatesAddresses {
|
||||
|
|
@ -1052,6 +1056,10 @@ func (s *PublicBlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.Epoch
|
|||
result[fieldSuccess] = false
|
||||
return result, err
|
||||
}
|
||||
if statedb == nil {
|
||||
result[fieldSuccess] = false
|
||||
return result, errors.New("nil statedb in GetCandidates")
|
||||
}
|
||||
candidatesAddresses := state.GetCandidates(statedb)
|
||||
candidates = make([]utils.Masternode, 0, len(candidatesAddresses))
|
||||
for _, address := range candidatesAddresses {
|
||||
|
|
@ -1305,6 +1313,9 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
|
|||
if statedb == nil || err != nil {
|
||||
return nil, 0, false, err, nil
|
||||
}
|
||||
if header == nil {
|
||||
return nil, 0, false, errors.New("nil header in DoCall"), nil
|
||||
}
|
||||
if err := overrides.Apply(statedb); err != nil {
|
||||
return nil, 0, false, err, nil
|
||||
}
|
||||
|
|
@ -1327,6 +1338,9 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
|
|||
if err != nil {
|
||||
return nil, 0, false, err, nil
|
||||
}
|
||||
if block == nil {
|
||||
return nil, 0, false, fmt.Errorf("nil block in DoCall: number=%d, hash=%s", header.Number.Uint64(), header.Hash().Hex()), nil
|
||||
}
|
||||
author, err := b.GetEngine().Author(block.Header())
|
||||
if err != nil {
|
||||
return nil, 0, false, err, nil
|
||||
|
|
@ -1948,6 +1962,9 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
|||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
if block == nil {
|
||||
return nil, 0, nil, fmt.Errorf("nil block in AccessList: number=%d, hash=%s", header.Number.Uint64(), header.Hash().Hex())
|
||||
}
|
||||
author, err := b.GetEngine().Author(block.Header())
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
|
|
@ -3617,10 +3634,16 @@ func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash,
|
|||
if err != nil {
|
||||
return addrs, err
|
||||
}
|
||||
if header == nil {
|
||||
return addrs, errors.New("nil header in GetSignersFromBlocks")
|
||||
}
|
||||
blockData, err := b.BlockByNumber(nil, rpc.BlockNumber(i))
|
||||
if err != nil {
|
||||
return addrs, err
|
||||
}
|
||||
if blockData == nil {
|
||||
return addrs, errors.New("nil blockData in GetSignersFromBlocks")
|
||||
}
|
||||
signTxs := engine.CacheSigningTxs(header.Hash(), blockData.Transactions())
|
||||
for _, signtx := range signTxs {
|
||||
blkHash := common.BytesToHash(signtx.Data()[len(signtx.Data())-32:])
|
||||
|
|
|
|||
Loading…
Reference in a new issue