Skip to content

Refactor handler registration scoped to event modules - #151

Merged
JonoPrest merged 4 commits into
mainfrom
jp/refactor-registration
Aug 30, 2024
Merged

Refactor handler registration scoped to event modules#151
JonoPrest merged 4 commits into
mainfrom
jp/refactor-registration

Conversation

@JonoPrest

@JonoPrest JonoPrest commented Aug 27, 2024

Copy link
Copy Markdown
Collaborator

Refactors:

  • Handler registration now happens on each Event module and no need to pass around a registered events map
  • event mod lookup is instantiated and passed per chain to each chain worker
  • event mod lookup is refactored to not handle multichain insertions/lookups and remove the need for a generic map. It is now simply a moap for event modules.

@JonoPrest
JonoPrest force-pushed the jp/refactor-registration branch from d4b55f1 to 615eda0 Compare August 28, 2024 10:39
@JonoPrest
JonoPrest force-pushed the jp/refactor-registration branch from 615eda0 to dfa9fe1 Compare August 28, 2024 10:48
@JonoPrest
JonoPrest marked this pull request as ready for review August 28, 2024 15:26
@JonoPrest
JonoPrest requested a review from DZakh August 28, 2024 15:26

let getContractRegisterArgs = (contextEnv, ~inMemoryStore) => {
RegisteredEvents.event: contextEnv.event,
Types.Handlers.event: contextEnv.event,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RegesteredEvents module is removed and it's types are moved into Types.Handlers

? executeSetEntityWithHistory
: executeDbFunctionsEntity
let entityDbExecutionComposer =
RegisterHandlers.getConfig()->Config.shouldRollbackOnReorg

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Config.getGenerated is removed, it now needs to be accessed from RegisterHandlers.getConfig() to ensure handlers are all registered (with event options) before instantiating the workers

{{/with}}
}
{{/if}}
let makeGeneratedConfig = () => {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest reviewing this with hide whitespace setting

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I didn't know about the option

Comment on lines +94 to +97
let eventModLookup =
contracts
->Belt.Array.flatMap(contract => contract.events)
->EventModLookup.fromArrayOrThrow(~chain)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

evenModLookup is now instantiated when this makeGeneratedConfig is run and passed to the chain worker

Comment on lines +205 to +245
@genType
module Handlers = {
type args<'eventArgs, 'context> = {
event: eventLog<'eventArgs>,
context: 'context,
}

type contractRegisterArgs<'eventArgs> = args<'eventArgs, contractRegistrations>
type contractRegister<'eventArgs> = contractRegisterArgs<'eventArgs> => unit

type loaderArgs<'eventArgs> = args<'eventArgs, loaderContext>
type loader<'eventArgs, 'loaderReturn> = loaderArgs<'eventArgs> => promise<'loaderReturn>

type handlerArgs<'eventArgs, 'loaderReturn> = {
event: eventLog<'eventArgs>,
context: handlerContext,
loaderReturn: 'loaderReturn,
}

type handler<'eventArgs, 'loaderReturn> = handlerArgs<'eventArgs, 'loaderReturn> => promise<unit>

type loaderHandler<'eventArgs, 'loaderReturn> = {
loader: loader<'eventArgs, 'loaderReturn>,
handler: handler<'eventArgs, 'loaderReturn>,
}

type eventOptions = {
wildcard: bool,
topicSelections: array<LogSelection.topicSelection>,
}

let getDefaultEventOptions = (~topic0) => {
wildcard: false,
topicSelections: [LogSelection.makeTopicSelection(~topic0=[topic0])->Utils.unwrapResultExn],
}

type registeredEvent<'eventArgs, 'loaderReturn> = {
loaderHandler?: loaderHandler<'eventArgs, 'loaderReturn>,
contractRegister?: contractRegister<'eventArgs>,
eventOptions: eventOptions,
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This chunk is basically just moved from RegisteredEvents.res

Comment on lines +247 to +348
module Register: {
type t<'eventArgs>
let make: (~topic0: string, ~contractName: string, ~eventName: string) => t<'eventArgs>
let setLoaderHandler: (
t<'eventArgs>,
loaderHandler<'eventArgs, 'loaderReturn>,
~eventOptions: option<eventOptions>,
~logger: Pino.t=?,
) => unit
let setContractRegister: (
t<'eventArgs>,
contractRegister<'eventArgs>,
~eventOptions: option<eventOptions>,
~logger: Pino.t=?,
) => unit
let getLoaderHandler: t<'eventArgs> => option<loaderHandler<'eventArgs, 'loaderReturn>>
let getContractRegister: t<'eventArgs> => option<contractRegister<'eventArgs>>
let getEventOptions: t<'eventArgs> => eventOptions
let hasRegistration: t<'eventArgs> => bool
} = {
type loaderReturn

type t<'eventArgs> = {
contractName: string,
eventName: string,
topic0: string,
mutable loaderHandler: option<loaderHandler<'eventArgs, loaderReturn>>,
mutable contractRegister: option<contractRegister<'eventArgs>>,
mutable eventOptions: option<eventOptions>,
}

let getLoaderHandler = (t: t<'eventArgs>): option<loaderHandler<'eventArgs, 'loaderReturn>> =>
t.loaderHandler->(
Utils.magic: option<loaderHandler<'eventArgs, loaderReturn>> => option<
loaderHandler<'eventArgs, 'loaderReturn>,
>
)

let getContractRegister = (t: t<'eventArgs>): option<contractRegister<'eventArgs>> =>
t.contractRegister

let getEventOptions = ({eventOptions, topic0}: t<'eventArgs>): eventOptions =>
switch eventOptions {
| Some(eventOptions) => eventOptions
| None => getDefaultEventOptions(~topic0)
}

let hasRegistration = ({loaderHandler, contractRegister}) =>
loaderHandler->Belt.Option.isSome || contractRegister->Belt.Option.isSome

let make = (~topic0, ~contractName, ~eventName) => {
contractName,
eventName,
topic0,
loaderHandler: None,
contractRegister: None,
eventOptions: None,
}

type eventNamespace = {contractName: string, eventName: string}
exception DuplicateEventRegistration(eventNamespace)

let setEventOptions = (t: t<'eventArgs>, value: eventOptions, ~logger=Logging.logger) => {
switch t.eventOptions {
| None => t.eventOptions = Some(value)
| Some(_) =>
let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
~msg="Duplicate eventOptions in handlers not allowed",
)
}
}

let setLoaderHandler = (
t: t<'eventArgs>,
value: loaderHandler<'eventArgs, 'loaderReturn>,
~eventOptions,
~logger=Logging.logger,
) => {
switch t.loaderHandler {
| None =>
t.loaderHandler =
value
->(Utils.magic: loaderHandler<'eventArgs, 'loaderReturn> => loaderHandler<
'eventArgs,
loaderReturn,
>)
->Some
| Some(_) =>
let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
~msg="Duplicate registration of event handlers not allowed",
)
}

switch eventOptions {
| Some(eventOptions) => t->setEventOptions(eventOptions, ~logger)
| None => ()
}
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new abstraction for registering handlers with with options on an event module

Comment on lines +1 to +11
open Belt
type eventMod = module(Types.InternalEvent)

type errorKind = WildcardSighashCollision | Duplicate
type eventError = {eventMod: eventMod, errorKind: errorKind}
module ContractEventMods = {
type t = {
all: array<eventMod>,
byContractName: dict<eventMod>,
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange this wasn't tracked as a move... but there are quite a lot of changes here as well.

@JonoPrest
JonoPrest force-pushed the jp/refactor-registration branch from 67e050f to c7acf83 Compare August 28, 2024 15:43
let set = (
inMemTable: t<'entity>,
entityUpdate: Types.entityUpdate<'entity>,
~shouldRollbackOnReorg,

@JonoPrest JonoPrest Aug 28, 2024

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing shouldRollbackOnReorg in here because using RegisterHandlers causes dependency cycle

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, we had to get rid of Config.getGenerated() anyways

Comment on lines +45 to +47
let findWildcard = ({all}) => {
all->Js.Array2.find(event => event->isWildcard)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new design you can add wildcard: option<eventMod> field to the ContractEventMods.t type, which will simplify the hasWildcardCollision and allow getting rid of the findWildcard function


let set = ({all, byContractName}: t, eventMod: eventMod) => {
let module(Event) = eventMod
switch byContractName->Js.Dict.get(Event.contractName) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A tiny thing, but there's Utils.Dict.dangerouslyGetNonOption, which doesn't have an unnecessary runtime overhead.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok cool, I think it makes sense to improve for the get function but these values will only be set at startup

@DZakh DZakh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing 👍 The only comment is about improving the wildcard eventMod lookup 👌

Base automatically changed from jp/event-routing to main August 30, 2024 08:14
@JonoPrest
JonoPrest force-pushed the jp/refactor-registration branch from c7acf83 to 53d74dc Compare August 30, 2024 08:27
@JonoPrest
JonoPrest enabled auto-merge (squash) August 30, 2024 08:28
@JonoPrest
JonoPrest merged commit 4e076cf into main Aug 30, 2024
@JonoPrest
JonoPrest deleted the jp/refactor-registration branch August 30, 2024 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants