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 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()))
} }
@ -164,6 +166,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()))
} }
@ -192,13 +196,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{
Error: errors.New("can not get header by nil number"),
}
}
return MasternodesStatus{ 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 { 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{
@ -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. 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()
@ -379,10 +407,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) {
@ -464,16 +494,34 @@ func (api *API) GetRewardByAccount(account common.Address, begin rpc.BlockNumber
} }
func (api *API) getRewardFileNamesInRange(begin, end *rpc.BlockNumber) ([]rewardFileName, error) { func (api *API) getRewardFileNamesInRange(begin, end *rpc.BlockNumber) ([]rewardFileName, error) {
beginHeader := api.getHeaderFromApiBlockNum(begin) beginHeader, err := api.getHeaderFromApiBlockNum(begin)
if beginHeader == nil { if err != nil {
return nil, errors.New("illegal begin block number") 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 { 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 { 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() diff := new(big.Int).Sub(endHeader.Number, beginHeader.Number).Int64()
if diff < 0 { if diff < 0 {
@ -621,18 +669,36 @@ func (rewardObj *AccountEpochReward) getRewardAndStatus(account string, data map
return return
} }
} }
} }
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"
@ -97,6 +98,8 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number 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())
} }
header := b.eth.blockchain.GetHeaderByNumber(uint64(number)) header := b.eth.blockchain.GetHeaderByNumber(uint64(number))
if header == nil { if header == nil {
@ -147,6 +150,8 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
} 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(number)), nil return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil
} }