diff --git a/accounts/abi/bind/v2/lib.go b/accounts/abi/bind/v2/lib.go index ed741e2397..3e677d6ce0 100644 --- a/accounts/abi/bind/v2/lib.go +++ b/accounts/abi/bind/v2/lib.go @@ -233,7 +233,10 @@ func FilterLogs[T any](instance *ContractInstance, opts *bind.FilterOpts, eventI return &EventIterator[T]{unpack: unpack, logs: logs, sub: sub}, nil } -// TODO: adding docs soon (jwasinger) +// WatchLogs causes logs emitted with a given event id from a specified +// contract to be intercepted, unpacked, and forwarded to sink. If +// unpack returns an error, the returned subscription is closed with the +// error. func WatchLogs[T any](instance *ContractInstance, abi abi.ABI, opts *bind.WatchOpts, eventID common.Hash, unpack func(*types.Log) (*T, error), sink chan<- *T, topics ...[]any) (event.Subscription, error) { backend := instance.Backend c := bind.NewBoundContract(instance.Address, abi, backend, backend, backend) @@ -270,7 +273,7 @@ func WatchLogs[T any](instance *ContractInstance, abi abi.ABI, opts *bind.WatchO // EventIterator is returned from FilterLogs and is used to iterate over the raw logs and unpacked data for events. 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 unpack func(*types.Log) (*T, error) // Unpack function for the event @@ -280,6 +283,11 @@ type EventIterator[T any] struct { fail error // Occurred error to stop iteration } +// Value returns the current value of the iterator, or nil if there isn't one. +func (it *EventIterator[T]) Value() *T { + return it.event +} + // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. @@ -297,7 +305,7 @@ func (it *EventIterator[T]) Next() bool { it.fail = err return false } - it.Event = res + it.event = res return true default: @@ -312,7 +320,7 @@ func (it *EventIterator[T]) Next() bool { it.fail = err return false } - it.Event = res + it.event = res return true case err := <-it.sub.Err(): diff --git a/accounts/abi/bind/v2/lib_test.go b/accounts/abi/bind/v2/lib_test.go index a891b5eb36..d8b0c5ee42 100644 --- a/accounts/abi/bind/v2/lib_test.go +++ b/accounts/abi/bind/v2/lib_test.go @@ -350,11 +350,6 @@ func TestEvents(t *testing.T) { sub2, err := WatchLogs[events.CBasic2](&boundContract, *abi, watchOpts, events.CBasic2EventID(), unpackBasic2, newCBasic2Ch) defer sub1.Unsubscribe() defer sub2.Unsubscribe() - fmt.Printf("watching for event with id %x\n", events.CBasic1EventID()) - fmt.Printf("watching for event with id %x\n", events.CBasic2EventID()) - //wtf do I do with this subscriptions?? - _ = sub1 - _ = sub2 crtctInstance := &ContractInstance{ Address: res.Addrs[events.CMetaData.Pattern], @@ -397,10 +392,36 @@ done: if e2Count != 1 { t.Fatalf("expected event type 2 count to be 1. got %d", e2Count) } - // commit a few blocks... - // now filter for the previously-emitted events. + // now, test that we can filter those events that were just caught through the subscription + + filterOpts := &bind.FilterOpts{ + Start: 0, + Context: context.Background(), + } // TODO: test that returning error from unpack prevents event from being received by sink. + it, err := FilterLogs[events.CBasic1](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic) + if err != nil { + t.Fatalf("error filtering logs %v\n", err) + } + it2, err := FilterLogs[events.CBasic2](crtctInstance, filterOpts, events.CBasic1EventID(), unpackBasic2) + if err != nil { + t.Fatalf("error filtering logs %v\n", err) + } + e1Count = 0 + e2Count = 0 + for it.Next() { + e1Count++ + } + for it2.Next() { + e2Count++ + } + if e2Count != 1 { + t.Fatalf("bad") + } + if e1Count != 1 { + t.Fatalf("bad") + } } func TestEventsUnpackFailure(t *testing.T) { @@ -445,7 +466,7 @@ func TestEventsUnpackFailure(t *testing.T) { } unpackBasic := func(raw *types.Log) (*events.CBasic1, error) { - return nil, fmt.Errorf("could not unpack event") + return nil, fmt.Errorf("this error should stop the filter that uses this unpack.") } unpackBasic2 := func(raw *types.Log) (*events.CBasic2, error) { return &events.CBasic2{ @@ -463,9 +484,6 @@ func TestEventsUnpackFailure(t *testing.T) { sub2, err := WatchLogs[events.CBasic2](&boundContract, *abi, watchOpts, events.CBasic2EventID(), unpackBasic2, newCBasic2Ch) defer sub1.Unsubscribe() defer sub2.Unsubscribe() - //wtf do I do with this subscriptions?? - _ = sub1 - _ = sub2 crtctInstance := &ContractInstance{ Address: res.Addrs[events.CMetaData.Pattern],