Generic event processing#63
Conversation
|
Here's the diff of the codegen output.🙌🧠🦜 |
8cb65d1 to
8f55503
Compare
DZakh
left a comment
There was a problem hiding this comment.
The idea of the PR in a nutshell is to select an eventMod related to an event when we parse a log and store it in the batch item. This way we can use the eventMod to get an eventName without generating a switch. Later I want to include more functions to eventMod, so we can remove more generated parts.
For example, for decoding it'll allow to have different implementations for Evm and Fuel.
| decodedEvent | ||
| ->{{contract.name.capitalized}}.{{event.name.capitalized}}.convertViemDecodedEvent | ||
| ->{{contract.name.capitalized}}.{{event.name.capitalized}}.convertLogViem(~log, ~blockTimestamp, ~chainId, ~txOrigin, ~txTo) |
There was a problem hiding this comment.
Next step. Move Converters to static and get the decoder from eventMod
| } | ||
|
|
||
| Ok(event) | ||
| Ok(event, eventMod) |
There was a problem hiding this comment.
It's a small performance regression, but it shouldn't be noticeable considering the whole indexer codebase.
There was a problem hiding this comment.
Agreed 👍🏼,
But I guess you could always just store contract name and event name and look up the module where needed
There was a problem hiding this comment.
I'd say it's better to store eventMod and get contract name and event name from it whenever we need. This is actually how it's done. Later I think we'll separate eventMod lookup and event decoding, so there won't be the tuple anymore.
| ~schema: S.t<'a>, | ||
| ~variantAccessor: Types.eventLog<'a> => Types.event, | ||
| ~eventMod: module(Types.Event), | ||
| ~eventAccessor: Types.eventLog<eventArgs> => Types.event, |
There was a problem hiding this comment.
Next step: Move eventAccessor to the eventMod and apply it only when we expose event to users. Work with eventLog internally
There was a problem hiding this comment.
Not sure if this is what you mean but we can always add eventMod to the data structure of "Event", then cast the inner event type to some opaque type and deal with the inner values using eventMod functions
There was a problem hiding this comment.
I actually think we don't need the Types.event type whatsoever. So, instead of what I said above, I'll eliminate the Types.event.
| ~txOrigin: option<Ethers.ethAddress>, | ||
| ~txTo: option<Ethers.ethAddress>, | ||
| ): result<Types.eventBatchQueueItem, S.error> => { | ||
| let module(Event) = eventMod->(Utils.magic: module(Types.Event) => module(Types.Event with type eventArgs = eventArgs)) |
There was a problem hiding this comment.
I hope we won't need to do this type castings when we start using eventLog instead of event
There was a problem hiding this comment.
Why are you casting here rather than just having the module type in the function parameter?
There was a problem hiding this comment.
In this case it'd complain on type mismatch when we create Types.eventBatchQueueItem, because it expects module(Types.Event) instead of module(Types.Event with type eventArgs = eventArgs). So I decided to cast only the part which is used inside of the function
| events: [ | ||
| {{#each contract.events as | event |}} | ||
| {{event.event_type.full}}, | ||
| module(Types.{{contract.name.capitalized}}.{{event.name.capitalized}}), |
There was a problem hiding this comment.
Here it's not really needed to use mod yet, but later we should use the array from config to find the correct eventMod for an event. Currently it's codegened in Types and Converters
| | Error(e) => S.Error.raise(e) | ||
| }, | ||
| eventType: Event.eventName, | ||
| params: event.params->S.serializeToJsonStringOrRaiseWith(Event.eventArgsSchema), |
There was a problem hiding this comment.
Nice addition of rescript-schema v7
There was a problem hiding this comment.
But not needed, since params are Js.Json.t now 😅
| let eventBatches = await eventBatchPromises->Promise.all | ||
| let parsedQueueItemsPreFilter = eventBatches |
There was a problem hiding this comment.
I think eventBatchPromises is something weird and should be awaited in the place where it's used. But I decided not to change here anything, in case there's some reason to apply Promise.all only at the step.
| let getHandlerArgs = (contextEnv, ~asyncGetters, ~inMemoryStore, ~loaderReturn) => { | ||
| let getHandlerArgs = (contextEnv, ~asyncGetters=asyncGetters, ~inMemoryStore, ~loaderReturn) => { |
There was a problem hiding this comment.
Why is this not punned? 🤔, would have thought the formatter would do that.
|
Merged as part of #67 |
No description provided.