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.
 | 
			
		||||
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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) {
 | 
			
		||||
	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{}{
 | 
			
		||||
		"fromBlock": toBlockNumArg(q.FromBlock),
 | 
			
		||||
		"toBlock":   toBlockNumArg(q.ToBlock),
 | 
			
		||||
		"address":   q.Addresses,
 | 
			
		||||
		"topics":    q.Topics,
 | 
			
		||||
		"address": q.Addresses,
 | 
			
		||||
		"topics":  q.Topics,
 | 
			
		||||
	}
 | 
			
		||||
	if q.FromBlock == nil {
 | 
			
		||||
		arg["fromBlock"] = "0x0"
 | 
			
		||||
	if q.BlockHash != nil {
 | 
			
		||||
		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
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,15 @@
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
var (
 | 
			
		||||
@@ -32,3 +40,113 @@ var (
 | 
			
		||||
	// _ = ethereum.PendingStateEventer(&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