-
Notifications
You must be signed in to change notification settings - Fork 146
Make RPCModules independent of concrete chain #121
Make RPCModules independent of concrete chain #121
Conversation
RPCModules need to access the chain regulary so it makes sense for them to depend and provide access to the chain. However, the RPCServer doesn't care about the concrete chain type and we can get away with making it generic since Eth1 and Beacon chain don't share a common ancestor.
`chain` and `event_bus` are being used in child classes and should hence not be written with _ (underscore) notation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to accomplish #79 I believe that we end up needing to completely or almost completely stop using a remote Chain
object.
Ignoring the special evm_resetToGenesisFixture
method, that implies that all of our RPC modules which need access to the Chain
need to be converted to use one of:
- A: Event bus based data retrieval
- B: A fully local
Chain
instance using a local database connection (probably a read-only one)
Doing B
depends on database architecture that we cannot support with our existing LevelDB backend.
This leaves us with option A which requires us to create a new service that exposes Chain
data over the event bus.
I recognize this pull request isn't exactly targeting #79 but I'm curious if it can be reworked to bring us closer to that goal. Thoughts?
The JSON-RPC Server already runs in it's own isolated process and the As I said in #79, I don't think we should funnel all db read/writes through the event bus and instead focus on moving to something like RocksDB to get rid of remaining process hoping (caused by the db proxy to leveldb). I believe funneling all db access through the eventbus will almost certainly have a worse performance than going through the db proxy, because:
|
Oh on
I want to highlight that just exposing the chain data through another service doesn't buy us anything here because that other service would still need to talk to the So, if we just add another service to expose Chain access you end up with: |
👍 on the correction that this is less about the |
trinity/rpc/modules/main.py
Outdated
def initialize_modules(modules: Iterable[Type[RPCModule]], | ||
chain: BaseAsyncChain, | ||
event_bus: Endpoint) -> Iterable[RPCModule]: | ||
def initialize_modules(modules: Iterable[Type[RPCModule[TChain]]], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious about us re-working this API to remove the chain
component and instead have the signature be something like initialize_modules(module_classes, trinity_config, event_bus)
. This should allow any module that needs Chain
access to connect to the chain itself, which I think also means that we could drop the Generic
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with this is that under testing, we want to inject a TestChain
(which obviously we can't resolve through the TrinityConfig
). And if we think about it, being able to pass chain instances into RPCModule
s gives us much more flexibility in general. The chain
is what most of the modules want to access anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
chain
is what most of the modules want to access anyway.
There are plenty of modules that don't need the chain
which is why I want to get the Chain
requirement fully removed from the RPCModule
concept.
As for testing and needing to inject a TestChain
there are plenty of ways we can solve that problem.
RPC APIs that don't need the Chain
net
admin
from https://github.com/ethereum/go-ethereum/wiki/Management-APIsshh
(Whisper)pss
(PSS that Swarm uses)bzz
if we ever get swarm implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are plenty of modules that don't need the chain which is why I want to get the
Chain
requirement fully removed from theRPCModule
concept.
Ah ok. Well, I kinda removed the Chain
already by creating an BaseRPCModule
that is basically just an interface that defines an abstract name
property.
class BaseRPCModule(ABC):
@property
@abstractmethod
def name(self) -> str:
pass
That's the only thing RPC modules need to implement to work with the RPCServer
because BaseRPCModule
is the only thing the server cares about.
But I realize that I missed the opportunity to make that more clear by providing one class RPCModule
that uses a chain and using that class even for modules that don't need the chain (e.g. net
).
I'm going to iterate on that and will further comment after I refactored some things to be clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pipermerriam I pushed another commit for some cleanups and added inline comments to explain.
yield Eth(chain, event_bus) | ||
yield EVM(chain, event_bus) | ||
yield Net(event_bus) | ||
yield Web3() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
↑
The BaseRPCModule
has zero implementation and only defines an abstract name
(so more of an interface than a base class). We initialize every module with the dependencies that the specific module needs. But since no one outside of the module cares about these internals the returned value can be treated as Tuple[BaseRPCModule, ...]
@@ -40,29 +35,20 @@ def name(self) -> str: | |||
pass | |||
|
|||
|
|||
class RPCModule(BaseRPCModule, Generic[TChain]): | |||
class ChainBasedRPCModule(BaseRPCModule, Generic[TChain]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just to have a DRY base class for all the modules that do depend on a chain. No part of the RPC system cares about it except the module itself. Every other code place just deals with BaseRPCModule
.
|
||
class Net(Eth1RPCModule): | ||
def __init__(self, event_bus: Endpoint): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Net
module even defines its very own __init__
as it needs an event bus but no chain.
What was wrong?
RPC Modules were locked to depend on
BaseAsyncChain
.How was it fixed?
RPCModule
is genreic overTChain
name
which means it is satisfied by the new non-genericBaseRPCModule
.chain
dependency on theRPCServer
Cute Animal Picture