accounts/abi/bind: support event filtering in abigen#15832
Conversation
|
Long time coming. Well done Peter 👏🏼 |
There was a problem hiding this comment.
"strongly types bound iterator" -> "strongly typed bound iterator"
gballet
left a comment
There was a problem hiding this comment.
Question about the API: why not using a single iterator for past and future events?
Also, need some clarification about the disappearance of Indexed, didn't understand that part.
There was a problem hiding this comment.
I'm wondering why you want to make a distinction between past and future logs? Both of them could be handled by the same iterator: you could just make the Iter() function take a start parameter that would either say something like FUTURE_ONLY or PAST_PRESENT_AND_FUTURE events. I don't see any case when a user interested in past event would not also be interested in future events. Also, having an API not making the distinction would save the caller code the trouble of having to handle the case when new events arrive between the moment when they called FilterLogs and the time they call WatchLogs
There was a problem hiding this comment.
E.g. When I'm filtering for past events, my code will usually block waiting for the next past event to arrive, until I consumed all past events I filtered for and the subsystem tells me there are no more events coming.
When I'm filtering for future events, my code will not block, rather be event driven, waiting on multiple possible event sources for data to arrive and react to.
To be honest, I can't think of an application where I would want to handle past and future events the same way.
E.g. I can filter for past Akasha events to retrieve the stuff the user posted and serve on a restful API, but that needs to stop and return, not wait for arbitrary future events. On the other hand, I can filter for future Akasha events to detect when users post new content and cache them in my API server via IPFS immediately during posting while the user is still online.
The two use cases are wildly different and have different requirements.
There was a problem hiding this comment.
To be honest, I can't think of an application where I would want to handle past and future events the same way.
I was thinking that implementing something like tail -f in Unix would be very complicated with this approach. I guess that this is an unlikely use case, then.
There was a problem hiding this comment.
The latter WatchXYZ is the one which supposed to handle that case.
There was a problem hiding this comment.
I don't understand why you remove this from the list of fields to be un-marshaled? I understand that it is derived from another source, but what if the field is still present in some client code?
There was a problem hiding this comment.
Indexed only makes sense in the context of an event field (which is inside "inputs"). In the outer ABI context there's no notion of "indexed" afaik.
|
Great work, thank you! Presumably if I want to iterate through all events in the order they are received (as opposed to per-event-type ordering), I would still need to use the Update: I was able to refactor my code fairly simply by replacing Would you consider making Before: // Indexed events not unpacked correctly
err = TokenABI.Unpack(data, eventName, log.Data)After: // Indexed events unpacked correctly
err = Token.TokenCaller.contract.UnpackLog(data, eventName, log) |
|
I know this is a pretty new PR but is there any documentation or usage examples of watching events? Haven't been able to get it to work. Does this support 'geth --light'? This is what I tried: I then select on 'ch' and 'sub.Err()' but nothing fires. Normal contract calls work so I know my process is able to connect to the geth IPC. Any suggestions? |
|
A code example will really help here. Thanks. |
Why? `go-ethereum` now have the events filters (ethereum/go-ethereum#15832), so we doesnt need to do not-so-smart polling from the blockchain. As a next step, we need to rewrite some of `blockchain/api.go` internals and use new event filters. Changed: - A lot of new stuff is shipped into ./vendor. - Minor fixes to match new go-ethereum API (gas price is represented as uint64, not big.Int). - `insonmnia/npp/puncher.go` is updated because of vet is not happy (`addr` variable shadowing).
Working exampleMy eventevent YearChanged(uint32 indexed year); Past eventsListen future events |
|
I am trying to to fetch some past events from a contract as follows. In my example I have used abigen to create bindings for ZIL: `conn, err := ethclient.Dial("https://mainnet.infura.io/ACCESS_TOKEN") This follows the example above given by @ArtMartiros . The name of the contract is printed so I am sure the connection works. However, no transaction is printed and transferEvts.Error() is empty. |
|
@hossein761 your code looks correct. |
|
How can we handle connection lost ? actually i have a code like this: maybe i'm doing something wrong, but quit is never fired. Even if i loose connection to the node. also would be cool to use the event.Resubscribe function as parameter directly in abigen, what do you think ? edit: tryed also <- sub.Err(), nothing changes |
Quite a long time ago we landed support for native Go bindings for Ethereum contracts. Back then we figured events will come very soon, but they turned out to require a complete overhaul of our subscription system, filtering system, etc. In short, it never happened.
This PR is fulfilling that promise made long ago, expanding
abigenwith support for strongly typed, native event filtering for Ethereum contracts from within Go!Supersedes #15246 which only started work towards event filtering, but did not generate typed Go code. Supersedes #15832 which didn't support filtering at all, just full retrieval.
This change is both-way incompatible:
abigencontracts are running.abigenwill require the underlying supporting code (go-ethereum) to be updated too as the new code will depend on newly added features.Existing client code will not break as no client API changes have been made, only extensions!
As a recap,
abigencould take a Solidity source file (or ABI spec with an optional EVM bytecode) and generate a Go wrapper out of it. For out original code token.sol, this looked like token.go.The highlights were automatically generated types and methods to fully interact with the
Tokencontract described in the Solidity file (sample API snippet):These generated methods could be used to deploy new contracts, bind existing ones, call methods on the contracts to read its state, and initiate state modifying transactions, all from within Go with strongly typed method arguments and return values.
This PR expands the generated code with new types and methods to support filtering past contract events, and subscribing to a stream of future events!
For every event present in the contract,
abigenwill create a Go counterpart. E.g. for the Transfer event in the token contract:event Transfer(address indexed from, address indexed to, uint256 value);For each event,
abigenwill generate aFilter<event name>method to retrieve past logs. As you can see below, the topics being filtered for are strongly typed Go types, not topic hashes as all other APIs surface. This allows calling code to be meaningfully read and understood without having to guess what some cryptic numbers mean.abigenwill generate all the necessary code to convert the user types into topic filter criteria under the hood.The log filterer method returns an iterator that can be used to iterate over the found logs, each already unpacked from its raw Ethereum RLP encoded form (and topic form) into strongly typed Go structs like
MyTokenTransferlisted above.Similarly, for each event,
abigenwill generate aWatch<event name>method to subscribe to future logs and similarly to filtering past events, subscribing to future ones can be done via strongly typed criteria.The method also takes a sink channel as an argument to deliver newly found contract events on, and returns a subscription which can be used to tear down the watcher constructs. As with past event subscriptions, the events streamed in the user-provided channel are strongly typed like
MyTokenTransferabove.The full generated code with this PR's
abigenis available at token.go.Caveats
Filtering for past log events returns an iterator for future API stability. The current implementation under the hood runs the entire user filtering in one big go, caches the entire results and then uses the iterator to simulate streaming filtering. This will be replaced eventually, but to avoid breaking the API then, we're enforcing this future mode of operation in user code already now.
Watching for future log events has an optional parameter for specifying the starting block number. This is currently a noop as
go-ethereumdoes not yet support subscribing to past events, but when support lands for it,abigenwill naively be able to use it without API changes.