Skip to content

Commit 96339da

Browse files
reductionistakaralabe
authored andcommitted
eth/filters, ethereum: EIP-234 add blockHash param for eth_getLogs
1 parent e8824f6 commit 96339da

File tree

3 files changed

+71
-13
lines changed

3 files changed

+71
-13
lines changed

eth/filters/api.go

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
ethereum "github.com/ethereum/go-ethereum"
2929
"github.com/ethereum/go-ethereum/common"
3030
"github.com/ethereum/go-ethereum/common/hexutil"
31+
"github.com/ethereum/go-ethereum/core/rawdb"
3132
"github.com/ethereum/go-ethereum/core/types"
3233
"github.com/ethereum/go-ethereum/ethdb"
3334
"github.com/ethereum/go-ethereum/event"
@@ -324,15 +325,35 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
324325
//
325326
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
326327
func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) {
327-
// Convert the RPC block numbers into internal representations
328-
if crit.FromBlock == nil {
329-
crit.FromBlock = big.NewInt(rpc.LatestBlockNumber.Int64())
330-
}
331-
if crit.ToBlock == nil {
332-
crit.ToBlock = big.NewInt(rpc.LatestBlockNumber.Int64())
328+
var (
329+
fromBlock int64
330+
toBlock int64
331+
)
332+
333+
if crit.BlockHash != nil {
334+
// look up block number from block hash
335+
if block := rawdb.ReadHeaderNumber(api.chainDb, *crit.BlockHash); block != nil {
336+
// verify block is part of canonical chain
337+
if canonical := rawdb.ReadCanonicalHash(api.chainDb, *block); canonical != *crit.BlockHash {
338+
return nil, fmt.Errorf("Block with hash %s was removed from canonical chain", crit.BlockHash.Hex())
339+
}
340+
fromBlock = int64(*block)
341+
toBlock = fromBlock
342+
} else {
343+
return nil, fmt.Errorf("Block with hash %s was not found", crit.BlockHash.Hex())
344+
}
345+
} else {
346+
// Convert the RPC block numbers into internal representations
347+
if crit.FromBlock == nil {
348+
fromBlock = int64(rpc.LatestBlockNumber)
349+
}
350+
if crit.ToBlock == nil {
351+
toBlock = int64(rpc.LatestBlockNumber)
352+
}
333353
}
354+
334355
// Create and run the filter to get all the logs
335-
filter := New(api.backend, crit.FromBlock.Int64(), crit.ToBlock.Int64(), crit.Addresses, crit.Topics)
356+
filter := New(api.backend, fromBlock, toBlock, crit.Addresses, crit.Topics)
336357

337358
logs, err := filter.Logs(ctx)
338359
if err != nil {
@@ -444,7 +465,8 @@ func returnLogs(logs []*types.Log) []*types.Log {
444465
// UnmarshalJSON sets *args fields with given data.
445466
func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
446467
type input struct {
447-
From *rpc.BlockNumber `json:"fromBlock"`
468+
BlockHash *common.Hash `json:"blockHash"`
469+
FromBlock *rpc.BlockNumber `json:"fromBlock"`
448470
ToBlock *rpc.BlockNumber `json:"toBlock"`
449471
Addresses interface{} `json:"address"`
450472
Topics []interface{} `json:"topics"`
@@ -455,12 +477,20 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
455477
return err
456478
}
457479

458-
if raw.From != nil {
459-
args.FromBlock = big.NewInt(raw.From.Int64())
460-
}
480+
if raw.BlockHash != nil {
481+
if raw.FromBlock != nil || raw.ToBlock != nil {
482+
// BlockHash is mutually exclusive with FromBlock/ToBlock criteria
483+
return fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock, choose one or the other")
484+
}
485+
args.BlockHash = raw.BlockHash
486+
} else {
487+
if raw.FromBlock != nil {
488+
args.FromBlock = big.NewInt(raw.FromBlock.Int64())
489+
}
461490

462-
if raw.ToBlock != nil {
463-
args.ToBlock = big.NewInt(raw.ToBlock.Int64())
491+
if raw.ToBlock != nil {
492+
args.ToBlock = big.NewInt(raw.ToBlock.Int64())
493+
}
464494
}
465495

466496
args.Addresses = []common.Address{}

eth/filters/filter_system_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,33 @@ func TestInvalidLogFilterCreation(t *testing.T) {
343343
}
344344
}
345345

346+
func TestInvalidGetLogsRequest(t *testing.T) {
347+
var (
348+
mux = new(event.TypeMux)
349+
db = ethdb.NewMemDatabase()
350+
txFeed = new(event.Feed)
351+
rmLogsFeed = new(event.Feed)
352+
logsFeed = new(event.Feed)
353+
chainFeed = new(event.Feed)
354+
backend = &testBackend{mux, db, 0, txFeed, rmLogsFeed, logsFeed, chainFeed}
355+
api = NewPublicFilterAPI(backend, false)
356+
blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
357+
)
358+
359+
// Reason: Cannot specify both BlockHash and FromBlock/ToBlock)
360+
testCases := []FilterCriteria{
361+
0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)},
362+
1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)},
363+
2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
364+
}
365+
366+
for i, test := range testCases {
367+
if _, err := api.GetLogs(context.Background(), test); err == nil {
368+
t.Errorf("Expected Logs for case #%d to fail", i)
369+
}
370+
}
371+
}
372+
346373
// TestLogFilter tests whether log filters match the correct logs that are posted to the event feed.
347374
func TestLogFilter(t *testing.T) {
348375
t.Parallel()

interfaces.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ type ContractCaller interface {
131131

132132
// FilterQuery contains options for contract log filtering.
133133
type FilterQuery struct {
134+
BlockHash *common.Hash // used by eth_getLogs, return logs only from block with this hash
134135
FromBlock *big.Int // beginning of the queried range, nil means genesis block
135136
ToBlock *big.Int // end of the range, nil means latest block
136137
Addresses []common.Address // restricts matches to events created by specific contracts

0 commit comments

Comments
 (0)