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 GitHub
parent 0fc4c82350
commit f24e68b015
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 89 additions and 18 deletions

View file

@ -139,6 +139,8 @@ func (api *API) GetSnapshot(number *rpc.BlockNumber) (*utils.PublicApiSnapshot,
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
@ -164,6 +166,8 @@ func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
@ -192,13 +196,22 @@ func (api *API) GetMasternodesByNumber(number *rpc.BlockNumber) MasternodesStatu
if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil {
header = api.chain.GetHeaderByHash(info.Hash)
}
} else if number.Int64() < 0 {
return MasternodesStatus{
Error: fmt.Errorf("invalid block number %d", number.Int64()),
}
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
if header == nil {
if number == nil {
return MasternodesStatus{
Error: errors.New("can not get header by nil number"),
}
}
return MasternodesStatus{
Error: fmt.Errorf("can not get header by number: %v", number),
Error: fmt.Errorf("can not get header by number %d", number.Int64()),
}
}
@ -311,7 +324,12 @@ func (api *API) GetV2BlockByHeader(header *types.Header, uncle bool) *V2BlockInf
}
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 number == nil {
return &V2BlockInfo{
@ -368,10 +386,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.
*/
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
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
@ -379,10 +407,12 @@ func (api *API) getHeaderFromApiBlockNum(number *rpc.BlockNumber) *types.Header
if info := api.XDPoS.EngineV2.GetLatestCommittedBlockInfo(); info != nil {
header = api.chain.GetHeaderByHash(info.Hash)
}
} else if number.Int64() < 0 {
return nil, fmt.Errorf("invalid block number %d", number.Int64())
} else {
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) {
@ -464,16 +494,34 @@ func (api *API) GetRewardByAccount(account common.Address, begin rpc.BlockNumber
}
func (api *API) getRewardFileNamesInRange(begin, end *rpc.BlockNumber) ([]rewardFileName, error) {
beginHeader := api.getHeaderFromApiBlockNum(begin)
if beginHeader == nil {
return nil, errors.New("illegal begin block number")
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 begin == nil {
return nil, errors.New("begin block number 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 {
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())
}
if beginHeader.Number.Cmp(endHeader.Number) > 0 {
return nil, errors.New("illegal begin and end block number, begin > end")
return nil, fmt.Errorf("illegal block numbers: begin(%d) > end(%d)", beginHeader.Number.Int64(), endHeader.Number.Int64())
}
diff := new(big.Int).Sub(endHeader.Number, beginHeader.Number).Int64()
if diff < 0 {
@ -621,18 +669,36 @@ func (rewardObj *AccountEpochReward) getRewardAndStatus(account string, data map
return
}
}
}
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 {
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 {
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()
if diff < 0 {
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)
assert.Nil(t, numbers)
assert.EqualError(t, err, "illegal end block number")
assert.EqualError(t, err, "illegal end block number 1803")
// 1803 not exist
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)
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) {
blockchain, _, currentBlock, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, 1802, params.TestXDPoSMockChainConfig)

View file

@ -20,6 +20,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"math/big"
"os"
"path/filepath"
@ -97,6 +98,8 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
} else {
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(number))
if header == nil {
@ -147,6 +150,8 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
} else {
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(number)), nil
}