consensus/XDPoS, eth: fix potential rpc.BlockNumber overflow, close XFN-69 (#1735)

This commit is contained in:
Daniel Liu 2025-11-15 19:14:08 +08:00 committed by benjamin202410
parent d0c92435bc
commit 9679c4e179
3 changed files with 65 additions and 11 deletions

View file

@ -85,6 +85,8 @@ func (api *API) GetSnapshot(number *rpc.BlockNumber) (*utils.PublicApiSnapshot,
var header *types.Header var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber { if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader() header = api.chain.CurrentHeader()
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} else { } else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64())) header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
} }
@ -110,6 +112,8 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
var header *types.Header var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber { if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader() header = api.chain.CurrentHeader()
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} else { } else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64())) header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
} }
@ -138,13 +142,22 @@ func (api *API) GetMasternodesByNumber(number *rpc.BlockNumber) MasternodesStatu
if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil { if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil {
header = api.chain.GetHeaderByHash(info.Hash) header = api.chain.GetHeaderByHash(info.Hash)
} }
} else if number.Int64() < 0 {
return MasternodesStatus{
Error: fmt.Errorf("invalid block number %d", number.Int64()),
}
} else { } else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64())) header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
} }
if header == nil { if header == nil {
if number == nil {
return MasternodesStatus{ return MasternodesStatus{
Error: fmt.Errorf("can not get header by number: %v", number), Error: errors.New("can not get header by nil number"),
}
}
return MasternodesStatus{
Error: fmt.Errorf("can not get header by number %d", number.Int64()),
} }
} }
@ -233,7 +246,12 @@ func (api *API) GetV2BlockByHeader(header *types.Header, uncle bool) *V2BlockInf
} }
func (api *API) GetV2BlockByNumber(number *rpc.BlockNumber) *V2BlockInfo { func (api *API) GetV2BlockByNumber(number *rpc.BlockNumber) *V2BlockInfo {
header := api.getHeaderFromApiBlockNum(number) header, err := api.getHeaderFromApiBlockNum(number)
if err != nil {
return &V2BlockInfo{
Error: err.Error(),
}
}
if header == nil { if header == nil {
if number == nil { if number == nil {
return &V2BlockInfo{ return &V2BlockInfo{
@ -290,10 +308,20 @@ func (api *API) NetworkInformation() NetworkInformation {
An API exclusively for V2 consensus, designed to assist in troubleshooting miners by identifying who mined during their allocated term. An API exclusively for V2 consensus, designed to assist in troubleshooting miners by identifying who mined during their allocated term.
*/ */
func (api *API) GetMissedRoundsInEpochByBlockNum(number *rpc.BlockNumber) (*utils.PublicApiMissedRoundsMetadata, error) { func (api *API) GetMissedRoundsInEpochByBlockNum(number *rpc.BlockNumber) (*utils.PublicApiMissedRoundsMetadata, error) {
return api.XDPoS.CalculateMissingRounds(api.chain, api.getHeaderFromApiBlockNum(number)) header, err := api.getHeaderFromApiBlockNum(number)
if err != nil {
return nil, err
}
if header == nil {
if number == nil {
return nil, errors.New("can not get header by nil number")
}
return nil, fmt.Errorf("can not get header by number %d", number.Int64())
}
return api.XDPoS.CalculateMissingRounds(api.chain, header)
} }
func (api *API) getHeaderFromApiBlockNum(number *rpc.BlockNumber) *types.Header { func (api *API) getHeaderFromApiBlockNum(number *rpc.BlockNumber) (*types.Header, error) {
var header *types.Header var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber { if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader() header = api.chain.CurrentHeader()
@ -301,10 +329,12 @@ func (api *API) getHeaderFromApiBlockNum(number *rpc.BlockNumber) *types.Header
if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil { if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil {
header = api.chain.GetHeaderByHash(info.Hash) header = api.chain.GetHeaderByHash(info.Hash)
} }
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} else { } else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64())) header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
} }
return header return header, nil
} }
func calculateSigners(message map[string]SignerTypes, pool map[string]map[common.Hash]utils.PoolObj, masternodes []common.Address) { func calculateSigners(message map[string]SignerTypes, pool map[string]map[common.Hash]utils.PoolObj, masternodes []common.Address) {
@ -333,14 +363,33 @@ func calculateSigners(message map[string]SignerTypes, pool map[string]map[common
} }
func (api *API) GetEpochNumbersBetween(begin, end *rpc.BlockNumber) ([]uint64, error) { func (api *API) GetEpochNumbersBetween(begin, end *rpc.BlockNumber) ([]uint64, error) {
beginHeader := api.getHeaderFromApiBlockNum(begin) beginHeader, err := api.getHeaderFromApiBlockNum(begin)
if err != nil {
if begin == nil {
return nil, fmt.Errorf("can not get begin header from nil number, err: %w", err)
}
return nil, fmt.Errorf("can not get begin header from number %d, err: %w", begin.Int64(), err)
}
if beginHeader == nil { if beginHeader == nil {
return nil, errors.New("illegal begin block number") if begin == nil {
return nil, errors.New("begin block is nil")
}
return nil, fmt.Errorf("illegal begin block number %d", begin.Int64())
}
endHeader, err := api.getHeaderFromApiBlockNum(end)
if err != nil {
if end == nil {
return nil, fmt.Errorf("can not get end header from nil number, err: %w", err)
}
return nil, fmt.Errorf("can not get end header from number %d, err: %w", end.Int64(), err)
} }
endHeader := api.getHeaderFromApiBlockNum(end)
if endHeader == nil { if endHeader == nil {
return nil, errors.New("illegal end block number") if end == nil {
return nil, errors.New("end block number is nil")
} }
return nil, fmt.Errorf("illegal end block number %d", end.Int64())
}
diff := new(big.Int).Sub(endHeader.Number, beginHeader.Number).Int64() diff := new(big.Int).Sub(endHeader.Number, beginHeader.Number).Int64()
if diff < 0 { if diff < 0 {
return nil, errors.New("illegal begin and end block number, begin > end") return nil, errors.New("illegal begin and end block number, begin > end")

View file

@ -158,7 +158,7 @@ func TestGetEpochNumbersBetween(t *testing.T) {
numbers, err = engine.APIs(bc.BlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end) numbers, err = engine.APIs(bc.BlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
assert.Nil(t, numbers) assert.Nil(t, numbers)
assert.EqualError(t, err, "illegal end block number") assert.EqualError(t, err, "illegal end block number 1803")
// 1803 not exist // 1803 not exist
begin = rpc.BlockNumber(1803) begin = rpc.BlockNumber(1803)
@ -166,7 +166,7 @@ func TestGetEpochNumbersBetween(t *testing.T) {
numbers, err = engine.APIs(bc.BlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end) numbers, err = engine.APIs(bc.BlockChain())[0].Service.(*XDPoS.API).GetEpochNumbersBetween(&begin, &end)
assert.Nil(t, numbers) assert.Nil(t, numbers)
assert.EqualError(t, err, "illegal begin block number") assert.EqualError(t, err, "illegal begin block number 1803")
} }
func TestGetBlockByEpochNumber(t *testing.T) { func TestGetBlockByEpochNumber(t *testing.T) {
blockchain, _, currentBlock, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, 1802, params.TestXDPoSMockChainConfig) blockchain, _, currentBlock, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, 1802, params.TestXDPoSMockChainConfig)

View file

@ -20,6 +20,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"math/big" "math/big"
"os" "os"
"path/filepath" "path/filepath"
@ -93,6 +94,8 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNum
} else { } else {
return nil, errors.New("PoS V1 does not support confirmed block lookup") return nil, errors.New("PoS V1 does not support confirmed block lookup")
} }
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} }
header := b.eth.blockchain.GetHeaderByNumber(uint64(blockNr)) header := b.eth.blockchain.GetHeaderByNumber(uint64(blockNr))
if header == nil { if header == nil {
@ -143,6 +146,8 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumb
} else { } else {
return nil, errors.New("PoS V1 does not support confirmed block lookup") return nil, errors.New("PoS V1 does not support confirmed block lookup")
} }
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} }
return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil
} }