mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else if stateDB == nil {
|
||||||
|
return errors.New("nil stateDB in UpdateM1")
|
||||||
} else {
|
} else {
|
||||||
candidates = state.GetCandidates(stateDB)
|
candidates = state.GetCandidates(stateDB)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -443,7 +442,11 @@ func (b *EthApiBackend) GetVotersRewards(masternodeAddr common.Address) map[comm
|
||||||
|
|
||||||
state, err := chain.StateAt(lastCheckpointBlock.Root())
|
state, err := chain.StateAt(lastCheckpointBlock.Root())
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,7 +506,11 @@ func (b *EthApiBackend) GetVotersCap(checkpoint *big.Int, masterAddr common.Addr
|
||||||
state, err := chain.StateAt(checkpointBlock.Root())
|
state, err := chain.StateAt(checkpointBlock.Root())
|
||||||
|
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,9 +540,12 @@ func (b *EthApiBackend) GetEpochDuration() *big.Int {
|
||||||
func (b *EthApiBackend) GetMasternodesCap(checkpoint uint64) map[common.Address]*big.Int {
|
func (b *EthApiBackend) GetMasternodesCap(checkpoint uint64) map[common.Address]*big.Int {
|
||||||
checkpointBlock := b.eth.blockchain.GetBlockByNumber(checkpoint)
|
checkpointBlock := b.eth.blockchain.GetBlockByNumber(checkpoint)
|
||||||
state, err := b.eth.blockchain.StateAt(checkpointBlock.Root())
|
state, err := b.eth.blockchain.StateAt(checkpointBlock.Root())
|
||||||
|
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,32 @@ type txTraceTask struct {
|
||||||
index int // Transaction offset in the block
|
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
|
// TraceChain returns the structured logs created during the execution of EVM
|
||||||
// between two blocks (excluding start) and returns them as a JSON object.
|
// 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) {
|
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
|
block *types.Block
|
||||||
)
|
)
|
||||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
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 {
|
} else if number, ok := blockNrOrHash.Number(); ok {
|
||||||
if number == rpc.PendingBlockNumber {
|
if number == rpc.PendingBlockNumber {
|
||||||
// We don't have access to the miner here. For tracing 'future' transactions,
|
// 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.
|
// of what the next actual block is likely to contain.
|
||||||
return nil, errors.New("tracing on top of pending is not supported")
|
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 {
|
} else {
|
||||||
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
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.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain)
|
||||||
eth.orderPool = core.NewOrderPool(eth.chainConfig, eth.blockchain)
|
eth.orderPool = core.NewOrderPool(eth.chainConfig, eth.blockchain)
|
||||||
eth.lendingPool = core.NewLendingPool(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()
|
curBlock := eth.blockchain.CurrentBlock()
|
||||||
|
if curBlock == nil {
|
||||||
|
log.Warn("not find current block when rollback")
|
||||||
|
}
|
||||||
prevBlock := eth.blockchain.GetBlockByHash(common.RollbackHash)
|
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) {
|
for ; curBlock != nil && curBlock.NumberU64() != prevBlock.NumberU64(); curBlock = eth.blockchain.GetBlock(curBlock.ParentHash(), curBlock.NumberU64()-1) {
|
||||||
eth.blockchain.Rollback([]common.Hash{curBlock.Hash()})
|
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)
|
log.Crit("Err Rollback", "err", err)
|
||||||
return nil, 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())
|
stateDB, err := bc.StateAt(bc.GetBlockByHash(block).Root())
|
||||||
candidateAddresses = state.GetCandidates(stateDB)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if stateDB == nil {
|
||||||
|
return nil, errors.New("nil stateDB in HookGetSignersFromContract")
|
||||||
|
}
|
||||||
|
|
||||||
|
candidateAddresses = state.GetCandidates(stateDB)
|
||||||
for _, address := range candidateAddresses {
|
for _, address := range candidateAddresses {
|
||||||
v, err := validator.GetCandidateCap(opts, address)
|
v, err := validator.GetCandidateCap(opts, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -897,6 +897,10 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd
|
||||||
result[fieldSuccess] = false
|
result[fieldSuccess] = false
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
if statedb == nil {
|
||||||
|
result[fieldSuccess] = false
|
||||||
|
return result, errors.New("nil statedb in GetCandidateStatus")
|
||||||
|
}
|
||||||
candidatesAddresses := state.GetCandidates(statedb)
|
candidatesAddresses := state.GetCandidates(statedb)
|
||||||
candidates = make([]utils.Masternode, 0, len(candidatesAddresses))
|
candidates = make([]utils.Masternode, 0, len(candidatesAddresses))
|
||||||
for _, address := range candidatesAddresses {
|
for _, address := range candidatesAddresses {
|
||||||
|
|
@ -1052,6 +1056,10 @@ func (s *PublicBlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.Epoch
|
||||||
result[fieldSuccess] = false
|
result[fieldSuccess] = false
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
if statedb == nil {
|
||||||
|
result[fieldSuccess] = false
|
||||||
|
return result, errors.New("nil statedb in GetCandidates")
|
||||||
|
}
|
||||||
candidatesAddresses := state.GetCandidates(statedb)
|
candidatesAddresses := state.GetCandidates(statedb)
|
||||||
candidates = make([]utils.Masternode, 0, len(candidatesAddresses))
|
candidates = make([]utils.Masternode, 0, len(candidatesAddresses))
|
||||||
for _, address := range 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 {
|
if statedb == nil || err != nil {
|
||||||
return nil, 0, false, 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 {
|
if err := overrides.Apply(statedb); err != nil {
|
||||||
return nil, 0, false, 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 {
|
if err != nil {
|
||||||
return nil, 0, false, 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())
|
author, err := b.GetEngine().Author(block.Header())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, false, 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 {
|
if err != nil {
|
||||||
return nil, 0, nil, err
|
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())
|
author, err := b.GetEngine().Author(block.Header())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
|
|
@ -3617,10 +3634,16 @@ func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return addrs, err
|
return addrs, err
|
||||||
}
|
}
|
||||||
|
if header == nil {
|
||||||
|
return addrs, errors.New("nil header in GetSignersFromBlocks")
|
||||||
|
}
|
||||||
blockData, err := b.BlockByNumber(nil, rpc.BlockNumber(i))
|
blockData, err := b.BlockByNumber(nil, rpc.BlockNumber(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return addrs, err
|
return addrs, err
|
||||||
}
|
}
|
||||||
|
if blockData == nil {
|
||||||
|
return addrs, errors.New("nil blockData in GetSignersFromBlocks")
|
||||||
|
}
|
||||||
signTxs := engine.CacheSigningTxs(header.Hash(), blockData.Transactions())
|
signTxs := engine.CacheSigningTxs(header.Hash(), blockData.Transactions())
|
||||||
for _, signtx := range signTxs {
|
for _, signtx := range signTxs {
|
||||||
blkHash := common.BytesToHash(signtx.Data()[len(signtx.Data())-32:])
|
blkHash := common.BytesToHash(signtx.Data()[len(signtx.Data())-32:])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue