ethclient: include block hash from FilterQuery (#17996)
ethereum/go-ethereum#16734 introduced BlockHash to the FilterQuery struct. However, ethclient was not updated to include BlockHash in the actual RPC request.
This commit is contained in:
		@@ -365,26 +365,42 @@ func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumb
 | 
				
			|||||||
// FilterLogs executes a filter query.
 | 
					// FilterLogs executes a filter query.
 | 
				
			||||||
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
 | 
					func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
 | 
				
			||||||
	var result []types.Log
 | 
						var result []types.Log
 | 
				
			||||||
	err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q))
 | 
						arg, err := toFilterArg(q)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = ec.c.CallContext(ctx, &result, "eth_getLogs", arg)
 | 
				
			||||||
	return result, err
 | 
						return result, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SubscribeFilterLogs subscribes to the results of a streaming filter query.
 | 
					// SubscribeFilterLogs subscribes to the results of a streaming filter query.
 | 
				
			||||||
func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
 | 
					func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
 | 
				
			||||||
	return ec.c.EthSubscribe(ctx, ch, "logs", toFilterArg(q))
 | 
						arg, err := toFilterArg(q)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ec.c.EthSubscribe(ctx, ch, "logs", arg)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func toFilterArg(q ethereum.FilterQuery) interface{} {
 | 
					func toFilterArg(q ethereum.FilterQuery) (interface{}, error) {
 | 
				
			||||||
	arg := map[string]interface{}{
 | 
						arg := map[string]interface{}{
 | 
				
			||||||
		"fromBlock": toBlockNumArg(q.FromBlock),
 | 
							"address": q.Addresses,
 | 
				
			||||||
		"toBlock":   toBlockNumArg(q.ToBlock),
 | 
							"topics":  q.Topics,
 | 
				
			||||||
		"address":   q.Addresses,
 | 
					 | 
				
			||||||
		"topics":    q.Topics,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if q.FromBlock == nil {
 | 
						if q.BlockHash != nil {
 | 
				
			||||||
		arg["fromBlock"] = "0x0"
 | 
							arg["blockHash"] = *q.BlockHash
 | 
				
			||||||
 | 
							if q.FromBlock != nil || q.ToBlock != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if q.FromBlock == nil {
 | 
				
			||||||
 | 
								arg["fromBlock"] = "0x0"
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								arg["fromBlock"] = toBlockNumArg(q.FromBlock)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							arg["toBlock"] = toBlockNumArg(q.ToBlock)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return arg
 | 
						return arg, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pending State
 | 
					// Pending State
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package ethclient
 | 
					package ethclient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "github.com/ethereum/go-ethereum"
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum"
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/common"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Verify that Client implements the ethereum interfaces.
 | 
					// Verify that Client implements the ethereum interfaces.
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -32,3 +40,113 @@ var (
 | 
				
			|||||||
	// _ = ethereum.PendingStateEventer(&Client{})
 | 
						// _ = ethereum.PendingStateEventer(&Client{})
 | 
				
			||||||
	_ = ethereum.PendingContractCaller(&Client{})
 | 
						_ = ethereum.PendingContractCaller(&Client{})
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestToFilterArg(t *testing.T) {
 | 
				
			||||||
 | 
						blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
 | 
				
			||||||
 | 
						addresses := []common.Address{
 | 
				
			||||||
 | 
							common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						blockHash := common.HexToHash(
 | 
				
			||||||
 | 
							"0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, testCase := range []struct {
 | 
				
			||||||
 | 
							name   string
 | 
				
			||||||
 | 
							input  ethereum.FilterQuery
 | 
				
			||||||
 | 
							output interface{}
 | 
				
			||||||
 | 
							err    error
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"without BlockHash",
 | 
				
			||||||
 | 
								ethereum.FilterQuery{
 | 
				
			||||||
 | 
									Addresses: addresses,
 | 
				
			||||||
 | 
									FromBlock: big.NewInt(1),
 | 
				
			||||||
 | 
									ToBlock:   big.NewInt(2),
 | 
				
			||||||
 | 
									Topics:    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								map[string]interface{}{
 | 
				
			||||||
 | 
									"address":   addresses,
 | 
				
			||||||
 | 
									"fromBlock": "0x1",
 | 
				
			||||||
 | 
									"toBlock":   "0x2",
 | 
				
			||||||
 | 
									"topics":    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nil,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"with nil fromBlock and nil toBlock",
 | 
				
			||||||
 | 
								ethereum.FilterQuery{
 | 
				
			||||||
 | 
									Addresses: addresses,
 | 
				
			||||||
 | 
									Topics:    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								map[string]interface{}{
 | 
				
			||||||
 | 
									"address":   addresses,
 | 
				
			||||||
 | 
									"fromBlock": "0x0",
 | 
				
			||||||
 | 
									"toBlock":   "latest",
 | 
				
			||||||
 | 
									"topics":    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nil,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"with blockhash",
 | 
				
			||||||
 | 
								ethereum.FilterQuery{
 | 
				
			||||||
 | 
									Addresses: addresses,
 | 
				
			||||||
 | 
									BlockHash: &blockHash,
 | 
				
			||||||
 | 
									Topics:    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								map[string]interface{}{
 | 
				
			||||||
 | 
									"address":   addresses,
 | 
				
			||||||
 | 
									"blockHash": blockHash,
 | 
				
			||||||
 | 
									"topics":    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nil,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"with blockhash and from block",
 | 
				
			||||||
 | 
								ethereum.FilterQuery{
 | 
				
			||||||
 | 
									Addresses: addresses,
 | 
				
			||||||
 | 
									BlockHash: &blockHash,
 | 
				
			||||||
 | 
									FromBlock: big.NewInt(1),
 | 
				
			||||||
 | 
									Topics:    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nil,
 | 
				
			||||||
 | 
								blockHashErr,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"with blockhash and to block",
 | 
				
			||||||
 | 
								ethereum.FilterQuery{
 | 
				
			||||||
 | 
									Addresses: addresses,
 | 
				
			||||||
 | 
									BlockHash: &blockHash,
 | 
				
			||||||
 | 
									ToBlock:   big.NewInt(1),
 | 
				
			||||||
 | 
									Topics:    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nil,
 | 
				
			||||||
 | 
								blockHashErr,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"with blockhash and both from / to block",
 | 
				
			||||||
 | 
								ethereum.FilterQuery{
 | 
				
			||||||
 | 
									Addresses: addresses,
 | 
				
			||||||
 | 
									BlockHash: &blockHash,
 | 
				
			||||||
 | 
									FromBlock: big.NewInt(1),
 | 
				
			||||||
 | 
									ToBlock:   big.NewInt(2),
 | 
				
			||||||
 | 
									Topics:    [][]common.Hash{},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nil,
 | 
				
			||||||
 | 
								blockHashErr,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						} {
 | 
				
			||||||
 | 
							t.Run(testCase.name, func(t *testing.T) {
 | 
				
			||||||
 | 
								output, err := toFilterArg(testCase.input)
 | 
				
			||||||
 | 
								if (testCase.err == nil) != (err == nil) {
 | 
				
			||||||
 | 
									t.Fatalf("expected error %v but got %v", testCase.err, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if testCase.err != nil {
 | 
				
			||||||
 | 
									if testCase.err.Error() != err.Error() {
 | 
				
			||||||
 | 
										t.Fatalf("expected error %v but got %v", testCase.err, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else if !reflect.DeepEqual(testCase.output, output) {
 | 
				
			||||||
 | 
									t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user