Skip to content

Commit 0b0b6ec

Browse files
committed
Teach TrinityConfig to handle sub configs
This commits adds sub config handling to TrinityConfig. This is needed to support different kinds of nodes that are loosely related yet different enough to demand different configurations. This allows us to handle shared configs on a base level as well as mixing in different sub configs depending on the use case.
1 parent dae7910 commit 0b0b6ec

File tree

6 files changed

+121
-21
lines changed

6 files changed

+121
-21
lines changed

tests/trinity/core/configuration/test_trinity_config_object.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
)
1616
from trinity.config import (
1717
TrinityConfig,
18+
BeaconAppConfig,
1819
DATABASE_DIR_NAME,
1920
)
2021
from trinity.utils.filesystem import (
@@ -90,3 +91,12 @@ def test_trinity_config_explictely_provided_nodekey(nodekey_bytes, as_bytes):
9091
)
9192

9293
assert trinity_config.nodekey.to_bytes() == nodekey_bytes
94+
95+
96+
def test_trinity_config_sub_configs():
97+
trinity_config = TrinityConfig(network_id=1)
98+
trinity_config.initialize_app_configs(None, (BeaconAppConfig,))
99+
100+
assert trinity_config.has_app_config(BeaconAppConfig)
101+
beacon_config = trinity_config.get_app_config(BeaconAppConfig)
102+
assert type(beacon_config) is BeaconAppConfig

trinity/bootstrap.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
subparser,
3333
)
3434
from trinity.config import (
35+
BaseAppConfig,
3536
TrinityConfig,
3637
)
3738
from trinity.constants import (
@@ -106,7 +107,9 @@
106107
], None]
107108

108109

109-
def main_entry(trinity_boot: BootFn, plugins: Iterable[BasePlugin]) -> None:
110+
def main_entry(trinity_boot: BootFn,
111+
plugins: Iterable[BasePlugin],
112+
sub_configs: Iterable[Type[BaseAppConfig]]) -> None:
110113
event_bus = EventBus(ctx)
111114
main_endpoint = event_bus.create_endpoint(MAIN_EVENTBUS_ENDPOINT)
112115
main_endpoint.connect_no_wait()
@@ -149,7 +152,7 @@ def main_entry(trinity_boot: BootFn, plugins: Iterable[BasePlugin]) -> None:
149152
setup_log_levels(args.log_levels)
150153

151154
try:
152-
trinity_config = TrinityConfig.from_parser_args(args)
155+
trinity_config = TrinityConfig.from_parser_args(args, sub_configs)
153156
except AmbigiousFileSystem:
154157
parser.error(TRINITY_AMBIGIOUS_FILESYSTEM_INFO)
155158

trinity/config.py

Lines changed: 97 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from abc import (
2+
ABC,
3+
abstractmethod,
4+
)
15
import argparse
26
from contextlib import contextmanager
37
import json
@@ -6,9 +10,11 @@
610
Any,
711
cast,
812
Dict,
13+
Iterable,
914
TYPE_CHECKING,
1015
Tuple,
1116
Type,
17+
TypeVar,
1218
Union,
1319
)
1420

@@ -185,6 +191,9 @@ def vm_configuration(self) -> VMConfiguration:
185191
return self.genesis_data.vm_configuration
186192

187193

194+
TAppConfig = TypeVar('TAppConfig', bound='BaseAppConfig')
195+
196+
188197
class TrinityConfig:
189198
_trinity_root_dir: Path = None
190199

@@ -203,6 +212,8 @@ class TrinityConfig:
203212

204213
_genesis_config: Dict[str, Any] = None
205214

215+
_app_configs: Dict[Type['BaseAppConfig'], 'BaseAppConfig'] = None
216+
206217
def __init__(self,
207218
network_id: int,
208219
genesis_config: Dict[str, Any]=None,
@@ -222,6 +233,7 @@ def __init__(self,
222233
self.sync_mode = sync_mode
223234
self.port = port
224235
self.use_discv5 = use_discv5
236+
self._app_configs = {}
225237

226238
if genesis_config is not None:
227239
self.genesis_config = genesis_config
@@ -285,14 +297,6 @@ def sync_mode(self, value: str) -> None:
285297
raise ValueError(f"Unknown sync mode: {value}")
286298
self._sync_mode = value
287299

288-
@property
289-
def is_light_mode(self) -> bool:
290-
return self.sync_mode == SYNC_LIGHT
291-
292-
@property
293-
def is_full_mode(self) -> bool:
294-
return self.sync_mode == SYNC_FULL
295-
296300
@property
297301
def logfile_path(self) -> Path:
298302
"""
@@ -440,14 +444,89 @@ def nodekey(self, value: Union[bytes, PrivateKey]) -> None:
440444
f"`PrivateKey` instance: got {type(self._nodekey)}"
441445
)
442446

447+
@contextmanager
448+
def process_id_file(self, process_name: str): # type: ignore
449+
with PidFile(process_name, self.data_dir):
450+
yield
451+
443452
@classmethod
444-
def from_parser_args(cls, parser_args: argparse.Namespace) -> 'TrinityConfig':
453+
def from_parser_args(cls,
454+
parser_args: argparse.Namespace,
455+
app_config_types: Iterable[Type['BaseAppConfig']]) -> 'TrinityConfig':
445456
"""
446457
Helper function for initializing from the namespace object produced by
447458
an ``argparse.ArgumentParser``
448459
"""
449460
constructor_kwargs = construct_trinity_config_params(parser_args)
450-
return cls(**constructor_kwargs)
461+
trinity_config = cls(**constructor_kwargs)
462+
463+
trinity_config.initialize_app_configs(parser_args, app_config_types)
464+
465+
return trinity_config
466+
467+
def initialize_app_configs(self,
468+
parser_args: argparse.Namespace,
469+
app_config_types: Iterable[Type['BaseAppConfig']]) -> None:
470+
"""
471+
Initialize all available ``BaseAppConfig`` based on their concrete types,
472+
the ``parser_args`` and the existing ``TrinityConfig`` instance.
473+
"""
474+
for app_config_type in app_config_types:
475+
self.add_app_config(app_config_type.from_parser_args(parser_args, self))
476+
477+
def add_app_config(self, app_config: 'BaseAppConfig') -> None:
478+
"""
479+
Register the given ``app_config``.
480+
"""
481+
self._app_configs[type(app_config)] = app_config
482+
483+
def has_app_config(self, app_config_type: Type['BaseAppConfig']) -> bool:
484+
"""
485+
Check if a ``BaseAppConfig`` exists based on the given ``app_config_type``.
486+
"""
487+
return app_config_type in self._app_configs.keys()
488+
489+
def get_app_config(self, app_config_type: Type[TAppConfig]) -> TAppConfig:
490+
"""
491+
Return the ``BaseAppConfig`` derived instance based on the given ``app_config_type``.
492+
"""
493+
# We want this API to return the specific type of the app config that is requested.
494+
# Our backing field only knows that it is holding `BaseAppConfig`'s but not concrete types
495+
return cast(TAppConfig, self._app_configs[app_config_type])
496+
497+
498+
class BaseAppConfig(ABC):
499+
500+
def __init__(self, trinity_config: TrinityConfig):
501+
self.trinity_config = trinity_config
502+
503+
@classmethod
504+
@abstractmethod
505+
def from_parser_args(cls,
506+
args: argparse.Namespace,
507+
trinity_config: TrinityConfig) -> 'BaseAppConfig':
508+
"""
509+
Initialize from the namespace object produced by
510+
an ``argparse.ArgumentParser`` and the ``TrinityConfig``
511+
"""
512+
pass
513+
514+
515+
class Eth1AppConfig(BaseAppConfig):
516+
517+
@classmethod
518+
def from_parser_args(cls,
519+
args: argparse.Namespace,
520+
trinity_config: TrinityConfig) -> 'BaseAppConfig':
521+
return cls(trinity_config)
522+
523+
@property
524+
def is_light_mode(self) -> bool:
525+
return self.trinity_config.sync_mode == SYNC_LIGHT
526+
527+
@property
528+
def is_full_mode(self) -> bool:
529+
return self.trinity_config.sync_mode == SYNC_FULL
451530

452531
@property
453532
def node_class(self) -> Type['Node']:
@@ -464,7 +543,11 @@ def node_class(self) -> Type['Node']:
464543
else:
465544
raise NotImplementedError("Only full and light sync modes are supported")
466545

467-
@contextmanager
468-
def process_id_file(self, process_name: str): # type: ignore
469-
with PidFile(process_name, self.data_dir):
470-
yield
546+
547+
class BeaconAppConfig(BaseAppConfig):
548+
549+
@classmethod
550+
def from_parser_args(cls,
551+
args: argparse.Namespace,
552+
trinity_config: TrinityConfig) -> 'BaseAppConfig':
553+
return cls(trinity_config)

trinity/main.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
)
2626
from trinity.config import (
2727
TrinityConfig,
28+
Eth1AppConfig,
2829
)
2930
from trinity.constants import (
3031
NETWORKING_EVENTBUS_ENDPOINT,
@@ -65,7 +66,7 @@ def get_all_plugins() -> Iterable[BasePlugin]:
6566

6667

6768
def main() -> None:
68-
main_entry(trinity_boot, get_all_plugins())
69+
main_entry(trinity_boot, get_all_plugins(), (Eth1AppConfig,))
6970

7071

7172
def trinity_boot(args: Namespace,
@@ -147,7 +148,7 @@ def kill_trinity_with_reason(reason: str) -> None:
147148
def launch_node(args: Namespace, trinity_config: TrinityConfig, endpoint: Endpoint) -> None:
148149
with trinity_config.process_id_file('networking'):
149150

150-
NodeClass = trinity_config.node_class
151+
NodeClass = trinity_config.get_app_config(Eth1AppConfig).node_class
151152
node = NodeClass(endpoint, trinity_config)
152153
loop = node.get_event_loop()
153154

trinity/main_beacon.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
)
2222
from trinity.config import (
2323
TrinityConfig,
24+
BeaconAppConfig
2425
)
2526
from trinity.events import (
2627
ShutdownRequest
@@ -41,7 +42,7 @@
4142

4243

4344
def main_beacon() -> None:
44-
main_entry(trinity_boot, BASE_PLUGINS)
45+
main_entry(trinity_boot, BASE_PLUGINS, (BeaconAppConfig,))
4546

4647

4748
def trinity_boot(args: Namespace,

trinity/plugins/builtin/json_rpc/plugin.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
)
55
import asyncio
66

7+
from trinity.config import Eth1AppConfig
78
from trinity.chains.base import BaseAsyncChain
89
from trinity.db.manager import (
910
create_db_manager
@@ -47,15 +48,16 @@ def do_start(self) -> None:
4748
db_manager.connect()
4849

4950
trinity_config = self.context.trinity_config
51+
eth1_app_config = self.context.trinity_config.get_app_config(Eth1AppConfig)
5052
chain_config = trinity_config.get_chain_config()
5153

5254
chain: BaseAsyncChain
5355

54-
if self.context.trinity_config.is_light_mode:
56+
if eth1_app_config.is_light_mode:
5557
header_db = db_manager.get_headerdb() # type: ignore
5658
event_bus_light_peer_chain = EventBusLightPeerChain(self.context.event_bus)
5759
chain = chain_config.light_chain_class(header_db, peer_chain=event_bus_light_peer_chain)
58-
elif trinity_config.is_full_mode:
60+
elif eth1_app_config.is_full_mode:
5961
db = db_manager.get_db() # type: ignore
6062
chain = chain_config.full_chain_class(db)
6163
else:

0 commit comments

Comments
 (0)