Skip to content
This repository has been archived by the owner on Jul 1, 2021. It is now read-only.

Commit

Permalink
Allow db-shell to inspect beacon nodes (#801)
Browse files Browse the repository at this point in the history
  • Loading branch information
s0b0lev authored and cburgdorf committed Jul 23, 2019
1 parent 0ebc5c6 commit 06e2c17
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 32 deletions.
1 change: 1 addition & 0 deletions newsfragments/809.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow trinity db-shell to inspect the beacon node
3 changes: 3 additions & 0 deletions trinity/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,6 @@

# Amount of time a peer will be blacklisted if their network or genesis hash does not match
BLACKLIST_SECONDS_WRONG_NETWORK_OR_GENESIS = 600

# Enables connection when clients launch from another process on the shell
AUTH_KEY = b"not secure, but only connect over IPC"
10 changes: 10 additions & 0 deletions trinity/db/beacon/manager.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import multiprocessing
from multiprocessing.managers import (
BaseManager,
)
Expand All @@ -10,6 +11,9 @@
BeaconAppConfig,
TrinityConfig,
)
from trinity.constants import (
AUTH_KEY,
)
from trinity.db.base import AsyncDBProxy
from trinity.db.beacon.chain import AsyncBeaconChainDBProxy

Expand All @@ -32,6 +36,9 @@ def create_db_server_manager(trinity_config: TrinityConfig,
if not is_beacon_database_initialized(chaindb, BeaconBlock):
initialize_beacon_database(chain_config, chaindb, base_db, BeaconBlock)

# This enables connection when clients launch from another process on the shell
multiprocessing.current_process().authkey = AUTH_KEY

class DBManager(BaseManager):
pass

Expand All @@ -53,6 +60,9 @@ def create_db_consumer_manager(ipc_path: pathlib.Path, connect: bool=True) -> Ba
We're still using 'str' here on param ipc_path because an issue with
multi-processing not being able to interpret 'Path' objects correctly
"""
# This enables connection when launched from another process on the shell
multiprocessing.current_process().authkey = AUTH_KEY

class DBManager(BaseManager):
pass

Expand Down
5 changes: 3 additions & 2 deletions trinity/db/eth1/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
Eth1AppConfig,
TrinityConfig,
)
from trinity.constants import (
AUTH_KEY,
)
from trinity.db.base import AsyncDBProxy
from trinity.db.eth1.chain import AsyncChainDBProxy
from trinity.db.eth1.header import (
Expand All @@ -23,8 +26,6 @@
)
from trinity._utils.mp import TracebackRecorder

AUTH_KEY = b"not secure, but only connect over IPC"


def create_db_server_manager(trinity_config: TrinityConfig,
base_db: BaseAtomicDB) -> BaseManager:
Expand Down
103 changes: 77 additions & 26 deletions trinity/plugins/builtin/attach/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@
from eth.db.chain import ChainDB
from eth.db.backends.level import LevelDB

from trinity._utils.log_messages import (
create_missing_ipc_error_message,
)
from eth2.beacon.db.chain import BeaconChainDB
from eth2.beacon.types.blocks import BeaconBlock
from eth2.beacon.operations.attestation_pool import AttestationPool

from trinity.config import (
Eth1AppConfig,
BeaconAppConfig,
TrinityConfig,
)
from trinity.db.eth1.manager import (
create_db_consumer_manager,
from trinity.db import eth1, beacon
from trinity._utils.log_messages import (
create_missing_ipc_error_message,
)


DEFAULT_BANNER: str = (
"Trinity Console\n"
"---------------\n"
Expand Down Expand Up @@ -98,44 +100,93 @@ def rpc(method: str, params: Dict[str, Any] = None) -> str:
shell(use_ipython, namespace, banner)


def db_shell(use_ipython: bool, database_dir: Path, trinity_config: TrinityConfig) -> None:
def db_shell(use_ipython: bool, config: Dict[str, str]) -> None:
greeter = """
Head: #%(block_number)s
Hash: %(hex_hash)s
State Root: %(state_root_hex)s
Inspecting active Trinity? %(trinity_already_running)s
db_ipc_path = trinity_config.database_ipc_path
trinity_already_running = db_ipc_path.exists()
Available Context Variables:
- `db`: base database object
- `chaindb`: `ChainDB` instance
- `trinity_config`: `TrinityConfig` instance
- `chain_config`: `ChainConfig` instance
- `chain`: `Chain` instance
""" % config

namespace = {
'db': config.get("db"),
'chaindb': config.get("chaindb"),
'trinity_config': config.get("trinity_config"),
'chain_config': config.get("chain_config"),
'chain': config.get("chain"),
}
shell(use_ipython, namespace, DB_SHELL_BANNER + greeter)


def get_eth1_shell_context(database_dir: Path, trinity_config: TrinityConfig) -> Dict[str, Any]:
app_config = trinity_config.get_app_config(Eth1AppConfig)
ipc_path = trinity_config.database_ipc_path

trinity_already_running = ipc_path.exists()
if trinity_already_running:
db_manager = create_db_consumer_manager(db_ipc_path)
db = db_manager.get_db() # type: ignore
db_manager = eth1.manager.create_db_consumer_manager(ipc_path) # type: ignore
db = db_manager.get_db()
else:
db = LevelDB(database_dir)

chaindb = ChainDB(db)
head = chaindb.get_canonical_head()
app_config = trinity_config.get_app_config(Eth1AppConfig)
chain_config = app_config.get_chain_config()
chain = chain_config.full_chain_class(db)
return {
'db': db,
'chaindb': chaindb,
'trinity_config': trinity_config,
'chain_config': chain_config,
'chain': chain,
'block_number': head.block_number,
'hex_hash': head.hex_hash,
'state_root_hex': encode_hex(head.state_root),
'trinity_already_running': trinity_already_running,
}

greeter = f"""
Head: #{head.block_number}
Hash: {head.hex_hash}
State Root: {encode_hex(head.state_root)}
Inspecting active Trinity? {trinity_already_running}

Available Context Variables:
- `db`: base database object
- `chaindb`: `ChainDB` instance
- `trinity_config`: `TrinityConfig` instance
- `chain_config`: `ChainConfig` instance
- `chain`: `Chain` instance
"""
def get_beacon_shell_context(database_dir: Path, trinity_config: TrinityConfig) -> Dict[str, Any]:
app_config = trinity_config.get_app_config(BeaconAppConfig)

namespace = {
ipc_path = trinity_config.database_ipc_path

trinity_already_running = ipc_path.exists()
if trinity_already_running:
db_manager = beacon.manager.create_db_consumer_manager(ipc_path) # type: ignore
db = db_manager.get_db()
else:
db = LevelDB(database_dir)

chain_config = app_config.get_chain_config()
chain = chain_config.beacon_chain_class
attestation_pool = AttestationPool()
chain = chain_config.beacon_chain_class(
db,
attestation_pool,
chain_config.genesis_config
)

chaindb = BeaconChainDB(db, chain_config.genesis_config)
head = chaindb.get_canonical_head(BeaconBlock)
return {
'db': db,
'chaindb': chaindb,
'trinity_config': trinity_config,
'chain_config': chain_config,
'chain': chain,
'block_number': head.slot,
'hex_hash': head.hash_tree_root.hex(),
'state_root_hex': encode_hex(head.state_root),
'trinity_already_running': trinity_already_running
}
shell(use_ipython, namespace, DB_SHELL_BANNER + greeter)


def shell(use_ipython: bool, namespace: Dict[str, Any], banner: str) -> None:
Expand Down
15 changes: 12 additions & 3 deletions trinity/plugins/builtin/attach/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import pathlib

from trinity.config import (
BaseAppConfig,
Eth1AppConfig,
BeaconAppConfig,
TrinityConfig,
)
from trinity.extensibility import (
Expand All @@ -18,6 +20,8 @@
from trinity.plugins.builtin.attach.console import (
console,
db_shell,
get_eth1_shell_context,
get_beacon_shell_context,
)


Expand Down Expand Up @@ -77,16 +81,21 @@ def configure_parser(cls,
'db-shell',
help='open a REPL to inspect the db',
)

attach_parser.set_defaults(func=cls.run_shell)

@classmethod
def run_shell(cls, args: Namespace, trinity_config: TrinityConfig) -> None:
config: BaseAppConfig

if trinity_config.has_app_config(Eth1AppConfig):
config = trinity_config.get_app_config(Eth1AppConfig)
db_shell(is_ipython_available(), config.database_dir, trinity_config)
context = get_eth1_shell_context(config.database_dir, trinity_config)
db_shell(is_ipython_available(), context)
elif trinity_config.has_app_config(BeaconAppConfig):
config = trinity_config.get_app_config(BeaconAppConfig)
context = get_beacon_shell_context(config.database_dir, trinity_config)
db_shell(is_ipython_available(), context)
else:
cls.get_logger().error(
"DB Shell only supports the Ethereum 1 node at this time"
"DB Shell only supports the Ethereum 1 and Beacon nodes at this time"
)
2 changes: 1 addition & 1 deletion trinity/plugins/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

BASE_PLUGINS: Tuple[Type[BasePlugin], ...] = (
AttachPlugin,
DbShellPlugin,
FixUncleanShutdownPlugin,
JsonRpcServerPlugin,
NetworkDBPlugin,
Expand All @@ -63,7 +64,6 @@

ETH1_NODE_PLUGINS: Tuple[Type[BasePlugin], ...] = (
BeamChainExecutionPlugin,
DbShellPlugin,
EthstatsPlugin,
SyncerPlugin,
TxPlugin,
Expand Down

0 comments on commit 06e2c17

Please sign in to comment.