Skip to content

Commit b16cc50

Browse files
tamirmsfjl
authored andcommitted
ethclient: include block hash from FilterQuery (#17996)
#16734 introduced BlockHash to the FilterQuery struct. However, ethclient was not updated to include BlockHash in the actual RPC request.
1 parent 9313fa6 commit b16cc50

File tree

2 files changed

+145
-11
lines changed

2 files changed

+145
-11
lines changed

ethclient/ethclient.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -365,26 +365,42 @@ func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumb
365365
// FilterLogs executes a filter query.
366366
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
367367
var result []types.Log
368-
err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q))
368+
arg, err := toFilterArg(q)
369+
if err != nil {
370+
return nil, err
371+
}
372+
err = ec.c.CallContext(ctx, &result, "eth_getLogs", arg)
369373
return result, err
370374
}
371375

372376
// SubscribeFilterLogs subscribes to the results of a streaming filter query.
373377
func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
374-
return ec.c.EthSubscribe(ctx, ch, "logs", toFilterArg(q))
378+
arg, err := toFilterArg(q)
379+
if err != nil {
380+
return nil, err
381+
}
382+
return ec.c.EthSubscribe(ctx, ch, "logs", arg)
375383
}
376384

377-
func toFilterArg(q ethereum.FilterQuery) interface{} {
385+
func toFilterArg(q ethereum.FilterQuery) (interface{}, error) {
378386
arg := map[string]interface{}{
379-
"fromBlock": toBlockNumArg(q.FromBlock),
380-
"toBlock": toBlockNumArg(q.ToBlock),
381-
"address": q.Addresses,
382-
"topics": q.Topics,
387+
"address": q.Addresses,
388+
"topics": q.Topics,
383389
}
384-
if q.FromBlock == nil {
385-
arg["fromBlock"] = "0x0"
390+
if q.BlockHash != nil {
391+
arg["blockHash"] = *q.BlockHash
392+
if q.FromBlock != nil || q.ToBlock != nil {
393+
return nil, fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
394+
}
395+
} else {
396+
if q.FromBlock == nil {
397+
arg["fromBlock"] = "0x0"
398+
} else {
399+
arg["fromBlock"] = toBlockNumArg(q.FromBlock)
400+
}
401+
arg["toBlock"] = toBlockNumArg(q.ToBlock)
386402
}
387-
return arg
403+
return arg, nil
388404
}
389405

390406
// Pending State

ethclient/ethclient_test.go

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@
1616

1717
package ethclient
1818

19-
import "github.com/ethereum/go-ethereum"
19+
import (
20+
"fmt"
21+
"math/big"
22+
"reflect"
23+
"testing"
24+
25+
"github.com/ethereum/go-ethereum"
26+
"github.com/ethereum/go-ethereum/common"
27+
)
2028

2129
// Verify that Client implements the ethereum interfaces.
2230
var (
@@ -32,3 +40,113 @@ var (
3240
// _ = ethereum.PendingStateEventer(&Client{})
3341
_ = ethereum.PendingContractCaller(&Client{})
3442
)
43+
44+
func TestToFilterArg(t *testing.T) {
45+
blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
46+
addresses := []common.Address{
47+
common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
48+
}
49+
blockHash := common.HexToHash(
50+
"0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
51+
)
52+
53+
for _, testCase := range []struct {
54+
name string
55+
input ethereum.FilterQuery
56+
output interface{}
57+
err error
58+
}{
59+
{
60+
"without BlockHash",
61+
ethereum.FilterQuery{
62+
Addresses: addresses,
63+
FromBlock: big.NewInt(1),
64+
ToBlock: big.NewInt(2),
65+
Topics: [][]common.Hash{},
66+
},
67+
map[string]interface{}{
68+
"address": addresses,
69+
"fromBlock": "0x1",
70+
"toBlock": "0x2",
71+
"topics": [][]common.Hash{},
72+
},
73+
nil,
74+
},
75+
{
76+
"with nil fromBlock and nil toBlock",
77+
ethereum.FilterQuery{
78+
Addresses: addresses,
79+
Topics: [][]common.Hash{},
80+
},
81+
map[string]interface{}{
82+
"address": addresses,
83+
"fromBlock": "0x0",
84+
"toBlock": "latest",
85+
"topics": [][]common.Hash{},
86+
},
87+
nil,
88+
},
89+
{
90+
"with blockhash",
91+
ethereum.FilterQuery{
92+
Addresses: addresses,
93+
BlockHash: &blockHash,
94+
Topics: [][]common.Hash{},
95+
},
96+
map[string]interface{}{
97+
"address": addresses,
98+
"blockHash": blockHash,
99+
"topics": [][]common.Hash{},
100+
},
101+
nil,
102+
},
103+
{
104+
"with blockhash and from block",
105+
ethereum.FilterQuery{
106+
Addresses: addresses,
107+
BlockHash: &blockHash,
108+
FromBlock: big.NewInt(1),
109+
Topics: [][]common.Hash{},
110+
},
111+
nil,
112+
blockHashErr,
113+
},
114+
{
115+
"with blockhash and to block",
116+
ethereum.FilterQuery{
117+
Addresses: addresses,
118+
BlockHash: &blockHash,
119+
ToBlock: big.NewInt(1),
120+
Topics: [][]common.Hash{},
121+
},
122+
nil,
123+
blockHashErr,
124+
},
125+
{
126+
"with blockhash and both from / to block",
127+
ethereum.FilterQuery{
128+
Addresses: addresses,
129+
BlockHash: &blockHash,
130+
FromBlock: big.NewInt(1),
131+
ToBlock: big.NewInt(2),
132+
Topics: [][]common.Hash{},
133+
},
134+
nil,
135+
blockHashErr,
136+
},
137+
} {
138+
t.Run(testCase.name, func(t *testing.T) {
139+
output, err := toFilterArg(testCase.input)
140+
if (testCase.err == nil) != (err == nil) {
141+
t.Fatalf("expected error %v but got %v", testCase.err, err)
142+
}
143+
if testCase.err != nil {
144+
if testCase.err.Error() != err.Error() {
145+
t.Fatalf("expected error %v but got %v", testCase.err, err)
146+
}
147+
} else if !reflect.DeepEqual(testCase.output, output) {
148+
t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
149+
}
150+
})
151+
}
152+
}

0 commit comments

Comments
 (0)