ethereum-optimism / ethereum-optimism/optimism
op-node: event-system customizability and plugins (ideas)
- Dominant language
- Go
- Stars
- 6.5k
- Forks
- 4k
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 145
Description
The op-node core consists of an event-broadcast system:
- Derivers: process events
- Emitters: output events
Through these events, the op-node sub-systems communicate tasks like block-processing, block-derivation from the DA, sequencing, etc.
The deriver/emitter is registered through `event.System`, which can execute these components either synchronously (current default), or in parallel (work in progress).
The components are "registered" with the system by name. This makes it possible to attribute metrics to each sub-system, and unregister as necessary.
### Plugins
This may be the beginning of a plugin-system; performing and triggering additional tasks by monitoring and emitting events is trivial.
The question is just how we load additional event derivers/emitters.
One option may be with Go plugins, to allow runtime customization. A Go plugin can be a DLL type file, auto-discovered in a directory by the op-node, and declare some global function as access-point to register new event-derivers/emitters from. Go plugins could be developed outside of the monorepo, import the monorepo as library, and utilize all the event/plugin types as necessary.
The drawback of Go plugins are the challenges with distribution; plugins are not packaged up with docker-images, or automatically platform-compatible. Still, runtime customization does open up a lot of extensibility, while keeping the core stack unified in the main repository. This may outweigh the distribution challenges. Besides, if the op-node docker image has a standard mounting point for a plugin-directory, and if a plugin is distributed as a bundle with each platform target, then it's relatively simple to work with.
Based on demand we may start a design doc in the [design-docs](https://github.com/ethereum-optimism/design-docs) repository to further expand on the idea.
### Event deriver/emitter composition
Not all plugins are additive however, some may want to *replace* certain subsets of functionality.
Unregistering/registering complete sub-systems might be too much, if only small things have to change.
To do so, we may want to change the event-deriver interface.
From:
```go
func (m *myDeriver) OnEvent(ev event.Event) bool {
switch ev.(type) {
case FooEvent: ...
case BarEvent: ...
}
}
```
To something more like:
```go
func (m *myDeriver) Setup(sys event.System) bool {
event.Register[FooEvent](sys, "foo-handling", func(ev FooEvent) {
... // replaces existing "foo-handling"
})
event.Register[BarEvent](sys, "bar-handling-my-extension", func(ev BarEvent) {
... // net-new event handler, to extend regular "bar-handling"
})
}
```
This would enable a finer level of detail, while also being more explicit about exactly *which* events a deriver needs to listen to. This way we can drop the "bool" return parameter, and possibly reduce event-processing overhead (no broadcast to derivers that just ignore the event).
### Permissions / metadata
If we are going with plugins, we may want the plugin to pre-declare which event types it will process and emit. And then enforce the input/output limitations to the plugin.
This way we can tell if a plugin is just listening to forkchoice-updates, or actually emitting engine-instructions.
Different event types could be declared, and categorized by *how they affect the op-node*, such that we can have standard-compatible extensions, as well as *consensus-breaking* extensions (for custom OP-Stack chains), or e.g. *plasma specific* extensions. This is similar to how apps in app-stores request system permission, and the user can trust that the app does not break their expectations. Or in OP-Stack context, that the plugin is compatible with a certain blockspace charter.
Contributor guide
Research direction
Start by reading the op-node event.System implementation and the existing deriver/emitter registration described in the issue. Compare the proposed plugin loading, composition, and permission models, then look for a design decision or acceptance criteria; this issue has no concrete implementation target or defined done state.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100