fix contract filter test. rename *Logs methods to *Events, to reflect the fact that these are specific to solidity events.

This commit is contained in:
Jared Wasinger 2024-12-02 12:57:09 +07:00 committed by Felix Lange
parent 1f25c68ec4
commit d3d6926683
3 changed files with 28 additions and 24 deletions

View File

@ -153,8 +153,6 @@ func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend Co
} }
func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBackend, packedParams []byte) (common.Address, *types.Transaction, *BoundContract, error) { func DeployContractRaw(opts *TransactOpts, bytecode []byte, backend ContractBackend, packedParams []byte) (common.Address, *types.Transaction, *BoundContract, error) {
// TODO: it's weird to instantiate a bound contract (implies existence of contract) in order to deploy a contract
// that doesn't yet exist
c := NewBoundContract(common.Address{}, abi.ABI{}, backend, backend, backend) c := NewBoundContract(common.Address{}, abi.ABI{}, backend, backend, backend)
tx, err := c.transact(opts, nil, append(bytecode, packedParams...)) tx, err := c.transact(opts, nil, append(bytecode, packedParams...))
@ -463,6 +461,12 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
return signedTx, nil return signedTx, nil
} }
// FilterLogsByID filters contract logs for past blocks, returning the necessary
// channels to construct a strongly typed bound iterator on top of them.
func (c *BoundContract) FilterLogsByID(opts *FilterOpts, eventID common.Hash, query ...[]interface{}) (chan types.Log, event.Subscription, error) {
return c.filterLogs(opts, eventID, query...)
}
// FilterLogs filters contract logs for past blocks, returning the necessary // FilterLogs filters contract logs for past blocks, returning the necessary
// channels to construct a strongly typed bound iterator on top of them. // channels to construct a strongly typed bound iterator on top of them.
func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) {

View File

@ -222,22 +222,24 @@ func LinkAndDeploy(auth *bind.TransactOpts, backend bind.ContractBackend, deploy
return res, nil return res, nil
} }
// TODO: adding docs soon (jwasinger) // FilterEvents returns an iterator for filtering events that match the query
func FilterLogs[T any](instance *ContractInstance, opts *bind.FilterOpts, eventID common.Hash, unpack func(*types.Log) (*T, error), topics ...[]any) (*EventIterator[T], error) { // parameters (filter range, eventID, topics). If unpack returns an error,
// the iterator value is not updated, and the iterator is stopped with the
// returned error.
func FilterEvents[T any](instance *ContractInstance, opts *bind.FilterOpts, eventID common.Hash, unpack func(*types.Log) (*T, error), topics ...[]any) (*EventIterator[T], error) {
backend := instance.Backend backend := instance.Backend
c := bind.NewBoundContract(instance.Address, abi.ABI{}, backend, backend, backend) c := bind.NewBoundContract(instance.Address, abi.ABI{}, backend, backend, backend)
logs, sub, err := c.FilterLogs(opts, eventID.String(), topics...) logs, sub, err := c.FilterLogsByID(opts, eventID, topics...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &EventIterator[T]{unpack: unpack, logs: logs, sub: sub}, nil return &EventIterator[T]{unpack: unpack, logs: logs, sub: sub}, nil
} }
// WatchLogs causes logs emitted with a given event id from a specified // WatchEvents causes events emitted from a specified contract to be forwarded to
// contract to be intercepted, unpacked, and forwarded to sink. If // onLog if they match the query parameters (matching eventID and topics). If
// unpack returns an error, the returned subscription is closed with the // onLog returns an error, the returned subscription is cancelled with that error.
// error. func WatchEvents(instance *ContractInstance, abi abi.ABI, opts *bind.WatchOpts, eventID common.Hash, onLog func(*types.Log) error, topics ...[]any) (event.Subscription, error) {
func WatchLogs(instance *ContractInstance, abi abi.ABI, opts *bind.WatchOpts, eventID common.Hash, onLog func(*types.Log) error, topics ...[]any) (event.Subscription, error) {
backend := instance.Backend backend := instance.Backend
c := bind.NewBoundContract(instance.Address, abi, backend, backend, backend) c := bind.NewBoundContract(instance.Address, abi, backend, backend, backend)
logs, sub, err := c.WatchLogsForId(opts, eventID, topics...) logs, sub, err := c.WatchLogsForId(opts, eventID, topics...)
@ -262,7 +264,7 @@ func WatchLogs(instance *ContractInstance, abi abi.ABI, opts *bind.WatchOpts, ev
}), nil }), nil
} }
// EventIterator is returned from FilterLogs and is used to iterate over the raw logs and unpacked data for events. // EventIterator is returned from FilterEvents and is used to iterate over the raw logs and unpacked data for events.
type EventIterator[T any] struct { type EventIterator[T any] struct {
event *T // event containing the contract specifics and raw log event *T // event containing the contract specifics and raw log

View File

@ -375,7 +375,6 @@ func TestEvents(t *testing.T) {
t.Fatalf("error getting contract abi: %v", err) t.Fatalf("error getting contract abi: %v", err)
} }
// TODO: why did I introduce separate type, and not just use bound contract?
boundContract := ContractInstance{ boundContract := ContractInstance{
res.Addrs[events.CMetaData.Pattern], res.Addrs[events.CMetaData.Pattern],
backend, backend,
@ -387,7 +386,7 @@ func TestEvents(t *testing.T) {
Start: nil, Start: nil,
Context: context.Background(), Context: context.Background(),
} }
sub1, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic1EventID(), func(raw *types.Log) error { sub1, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic1EventID(), func(raw *types.Log) error {
event := &events.CBasic1{ event := &events.CBasic1{
Id: (new(big.Int)).SetBytes(raw.Topics[0].Bytes()), Id: (new(big.Int)).SetBytes(raw.Topics[0].Bytes()),
Data: (new(big.Int)).SetBytes(raw.Data), Data: (new(big.Int)).SetBytes(raw.Data),
@ -395,7 +394,7 @@ func TestEvents(t *testing.T) {
newCBasic1Ch <- event newCBasic1Ch <- event
return nil return nil
}) })
sub2, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic2EventID(), func(raw *types.Log) error { sub2, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic2EventID(), func(raw *types.Log) error {
event := &events.CBasic2{ event := &events.CBasic2{
Flag: false, // TODO: how to unpack different types to go types? this should be exposed via abi package. Flag: false, // TODO: how to unpack different types to go types? this should be exposed via abi package.
Data: (new(big.Int)).SetBytes(raw.Data), Data: (new(big.Int)).SetBytes(raw.Data),
@ -448,7 +447,7 @@ done:
t.Fatalf("expected event type 2 count to be 1. got %d", e2Count) t.Fatalf("expected event type 2 count to be 1. got %d", e2Count)
} }
// now, test that we can filter those events that were just caught through the subscription // now, test that we can filter those same logs after they were included in the chain
filterOpts := &bind.FilterOpts{ filterOpts := &bind.FilterOpts{
Start: 0, Start: 0,
@ -466,12 +465,11 @@ done:
Data: (new(big.Int)).SetBytes(raw.Data), Data: (new(big.Int)).SetBytes(raw.Data),
}, nil }, nil
} }
// TODO: test that returning error from unpack prevents event from being received by sink. it, err := FilterEvents[events.CBasic1](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic)
it, err := FilterLogs[events.CBasic1](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic)
if err != nil { if err != nil {
t.Fatalf("error filtering logs %v\n", err) t.Fatalf("error filtering logs %v\n", err)
} }
it2, err := FilterLogs[events.CBasic2](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic2) it2, err := FilterEvents[events.CBasic2](crtctInstance, filterOpts, events.CBasic2EventID(), unpackBasic2)
if err != nil { if err != nil {
t.Fatalf("error filtering logs %v\n", err) t.Fatalf("error filtering logs %v\n", err)
} }
@ -483,11 +481,11 @@ done:
for it2.Next() { for it2.Next() {
e2Count++ e2Count++
} }
if e2Count != 1 { if e1Count != 2 {
t.Fatalf("bad") t.Fatalf("expected e1Count of 2 from filter call. got %d", e1Count)
} }
if e1Count != 1 { if e2Count != 1 {
t.Fatalf("bad") t.Fatalf("expected e2Count of 1 from filter call. got %d", e1Count)
} }
} }
@ -549,8 +547,8 @@ func TestEventsUnpackFailure(t *testing.T) {
Start: nil, Start: nil,
Context: context.Background(), Context: context.Background(),
} }
sub1, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic1EventID(), unpackBasic) sub1, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic1EventID(), unpackBasic)
sub2, err := WatchLogs(&boundContract, *abi, watchOpts, events.CBasic2EventID(), unpackBasic2) sub2, err := WatchEvents(&boundContract, *abi, watchOpts, events.CBasic2EventID(), unpackBasic2)
defer sub1.Unsubscribe() defer sub1.Unsubscribe()
defer sub2.Unsubscribe() defer sub2.Unsubscribe()