@@ -28,6 +28,7 @@ import (
28
28
ethereum "github.com/ethereum/go-ethereum"
29
29
"github.com/ethereum/go-ethereum/common"
30
30
"github.com/ethereum/go-ethereum/common/hexutil"
31
+ "github.com/ethereum/go-ethereum/core/rawdb"
31
32
"github.com/ethereum/go-ethereum/core/types"
32
33
"github.com/ethereum/go-ethereum/ethdb"
33
34
"github.com/ethereum/go-ethereum/event"
@@ -324,15 +325,35 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
324
325
//
325
326
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
326
327
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
+ }
333
353
}
354
+
334
355
// 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 )
336
357
337
358
logs , err := filter .Logs (ctx )
338
359
if err != nil {
@@ -444,7 +465,8 @@ func returnLogs(logs []*types.Log) []*types.Log {
444
465
// UnmarshalJSON sets *args fields with given data.
445
466
func (args * FilterCriteria ) UnmarshalJSON (data []byte ) error {
446
467
type input struct {
447
- From * rpc.BlockNumber `json:"fromBlock"`
468
+ BlockHash * common.Hash `json:"blockHash"`
469
+ FromBlock * rpc.BlockNumber `json:"fromBlock"`
448
470
ToBlock * rpc.BlockNumber `json:"toBlock"`
449
471
Addresses interface {} `json:"address"`
450
472
Topics []interface {} `json:"topics"`
@@ -455,12 +477,20 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
455
477
return err
456
478
}
457
479
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
+ }
461
490
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
+ }
464
494
}
465
495
466
496
args .Addresses = []common.Address {}
0 commit comments