Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some panic cuased by nil block, statedb, header #578

Merged
merged 6 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2578,6 +2578,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)
}
Expand Down
20 changes: 15 additions & 5 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"math/big"
"os"
"path/filepath"
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down
30 changes: 28 additions & 2 deletions eth/api_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -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")
}
Expand Down
9 changes: 7 additions & 2 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()})
}
Expand All @@ -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")
}
}

Expand Down
7 changes: 5 additions & 2 deletions eth/hooks/engine_v1_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
gzliudan marked this conversation as resolved.
Show resolved Hide resolved
}
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 {
Expand Down
23 changes: 23 additions & 0 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
Expand All @@ -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
Expand Down Expand Up @@ -1944,6 +1958,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
Expand Down Expand Up @@ -3613,10 +3630,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:])
Expand Down