From 9231770811cda0473a7fa4e2bccc95bf62aae634 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 23 May 2023 07:18:38 -0400 Subject: [PATCH] rpc: change BlockNumber constant values to match ethclient (#27219) ethclient accepts certain negative block number values as specifiers for the "pending", "safe" and "finalized" block. In case of "pending", the value accepted by ethclient (-1) did not match rpc.PendingBlockNumber (-2). This wasn't really a problem, but other values accepted by ethclient did match the definitions in package rpc, and it's weird to have this one special case where they don't. To fix it, we decided to change the values of the constants rather than changing ethclient. The constant values are not otherwise significant. This is a breaking API change, but we believe not a dangerous one. --------- Co-authored-by: Felix Lange --- eth/filters/api_test.go | 2 +- eth/filters/filter.go | 3 ++ eth/filters/filter_test.go | 27 ++++++++++-------- ethclient/ethclient.go | 18 +++++------- ethclient/gethclient/gethclient.go | 19 ++++++------- rpc/types.go | 44 ++++++++++++++++++------------ 6 files changed, 60 insertions(+), 53 deletions(-) diff --git a/eth/filters/api_test.go b/eth/filters/api_test.go index 0a80d0f8dd..822bc826f6 100644 --- a/eth/filters/api_test.go +++ b/eth/filters/api_test.go @@ -56,7 +56,7 @@ func TestUnmarshalJSONNewFilterArgs(t *testing.T) { // from, to block number var test1 FilterCriteria - vector := fmt.Sprintf(`{"fromBlock":"%#x","toBlock":"%#x"}`, fromBlock, toBlock) + vector := fmt.Sprintf(`{"fromBlock":"%v","toBlock":"%v"}`, fromBlock, toBlock) if err := json.Unmarshal([]byte(vector), &test1); err != nil { t.Fatal(err) } diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 8ba482817e..122676e96c 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -296,6 +296,9 @@ func (f *Filter) checkMatches(ctx context.Context, header *types.Header) ([]*typ // pendingLogs returns the logs matching the filter criteria within the pending block. func (f *Filter) pendingLogs() ([]*types.Log, error) { block, receipts := f.sys.backend.PendingBlockAndReceipts() + if block == nil { + return nil, errors.New("pending state not available") + } if bloomFilter(block.Bloom(), f.addresses, f.topics) { var unfiltered []*types.Log for _, r := range receipts { diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index d10e0f1d94..0e42c798ec 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" ) func makeReceipt(addr common.Address) *types.Receipt { @@ -179,7 +180,7 @@ func TestFilters(t *testing.T) { // Set block 998 as Finalized (-3) rawdb.WriteFinalizedBlockHash(db, chain[998].Hash()) - filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) + filter := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) logs, _ := filter.Logs(context.Background()) if len(logs) != 4 { t.Error("expected 4 log, got", len(logs)) @@ -193,34 +194,36 @@ func TestFilters(t *testing.T) { sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}), []common.Hash{hash3}, }, { - sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}), + sys.NewRangeFilter(990, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash3}}), []common.Hash{hash3}, }, { sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}), []common.Hash{hash1, hash2}, }, { - sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}), + sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}), nil, }, { - sys.NewRangeFilter(0, -1, []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil), + sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil), nil, }, { - sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}), + sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}), nil, }, { - sys.NewRangeFilter(-1, -1, nil, nil), []common.Hash{hash4}, + sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash4}, }, { - sys.NewRangeFilter(-3, -1, nil, nil), []common.Hash{hash3, hash4}, + sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash3, hash4}, }, { - sys.NewRangeFilter(-3, -3, nil, nil), []common.Hash{hash3}, + sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), []common.Hash{hash3}, }, { - sys.NewRangeFilter(-1, -3, nil, nil), nil, + sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), nil, }, { - sys.NewRangeFilter(-4, -1, nil, nil), nil, + sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), nil, }, { - sys.NewRangeFilter(-4, -4, nil, nil), nil, + sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), nil, }, { - sys.NewRangeFilter(-1, -4, nil, nil), nil, + sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), nil, + }, { + sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), nil, }, } { logs, _ := tc.f.Logs(context.Background()) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 09d3f37d1e..59e95f629a 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -592,19 +592,15 @@ func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } - pending := big.NewInt(-1) - if number.Cmp(pending) == 0 { - return "pending" + if number.Sign() >= 0 { + return hexutil.EncodeBig(number) } - finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) - if number.Cmp(finalized) == 0 { - return "finalized" + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() } - safe := big.NewInt(int64(rpc.SafeBlockNumber)) - if number.Cmp(safe) == 0 { - return "safe" - } - return hexutil.EncodeBig(number) + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) } func toCallArg(msg ethereum.CallMsg) interface{} { diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 718cdfea42..c029611678 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -20,6 +20,7 @@ package gethclient import ( "context" "encoding/json" + "fmt" "math/big" "runtime" "runtime/debug" @@ -207,19 +208,15 @@ func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } - pending := big.NewInt(-1) - if number.Cmp(pending) == 0 { - return "pending" + if number.Sign() >= 0 { + return hexutil.EncodeBig(number) } - finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) - if number.Cmp(finalized) == 0 { - return "finalized" + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() } - safe := big.NewInt(int64(rpc.SafeBlockNumber)) - if number.Cmp(safe) == 0 { - return "safe" - } - return hexutil.EncodeBig(number) + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) } func toCallArg(msg ethereum.CallMsg) interface{} { diff --git a/rpc/types.go b/rpc/types.go index 55d11fbaaf..34a1451dea 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -65,8 +65,8 @@ type BlockNumber int64 const ( SafeBlockNumber = BlockNumber(-4) FinalizedBlockNumber = BlockNumber(-3) - PendingBlockNumber = BlockNumber(-2) - LatestBlockNumber = BlockNumber(-1) + LatestBlockNumber = BlockNumber(-2) + PendingBlockNumber = BlockNumber(-1) EarliestBlockNumber = BlockNumber(0) ) @@ -111,28 +111,36 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { return nil } +// Int64 returns the block number as int64. +func (bn BlockNumber) Int64() int64 { + return (int64)(bn) +} + // MarshalText implements encoding.TextMarshaler. It marshals: // - "safe", "finalized", "latest", "earliest" or "pending" as strings // - other numbers as hex func (bn BlockNumber) MarshalText() ([]byte, error) { - switch bn { - case EarliestBlockNumber: - return []byte("earliest"), nil - case LatestBlockNumber: - return []byte("latest"), nil - case PendingBlockNumber: - return []byte("pending"), nil - case FinalizedBlockNumber: - return []byte("finalized"), nil - case SafeBlockNumber: - return []byte("safe"), nil - default: - return hexutil.Uint64(bn).MarshalText() - } + return []byte(bn.String()), nil } -func (bn BlockNumber) Int64() int64 { - return (int64)(bn) +func (bn BlockNumber) String() string { + switch bn { + case EarliestBlockNumber: + return "earliest" + case LatestBlockNumber: + return "latest" + case PendingBlockNumber: + return "pending" + case FinalizedBlockNumber: + return "finalized" + case SafeBlockNumber: + return "safe" + default: + if bn < 0 { + return fmt.Sprintf("", bn) + } + return hexutil.Uint64(bn).String() + } } type BlockNumberOrHash struct {