Skip to content

Commit

Permalink
Adapted remote keystore for Obol (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
evgeny-stakewise authored Oct 18, 2024
1 parent e55f275 commit db6449d
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 10 deletions.
13 changes: 12 additions & 1 deletion src/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@
ssv_api_base_url = 'https://api.ssv.network/api/v4'
ssv_api_timeout = 10

remote_signer_url: str = config('remote_signer_url', default='')
remote_signer_url: str = config('REMOTE_SIGNER_URL', default='')
remote_signer_timeout: int = config('REMOTE_SIGNER_TIMEOUT', cast=int, default=10)

# validations

# Check OBOL_KEYSTORES_DIR
if (
not remote_signer_url
and cluster_type == OBOL
Expand All @@ -63,6 +64,15 @@
):
raise RuntimeError('OBOL_KEYSTORES_DIR or OBOL_KEYSTORES_DIR_TEMPLATE must be set')

# Check cluster type for remote signer
if remote_signer_url and cluster_type != OBOL:
raise RuntimeError('Remote signer keystore is implemented for Obol only')

# Check OBOL_CLUSTER_LOCK_FILE
if cluster_type == OBOL and not obol_cluster_lock_file:
raise RuntimeError('OBOL_CLUSTER_LOCK_FILE must be set')

# Check SSV_OPERATOR_KEY_FILE
if (
not remote_signer_url
and cluster_type == SSV
Expand All @@ -71,6 +81,7 @@
):
raise RuntimeError('SSV_OPERATOR_KEY_FILE or SSV_OPERATOR_KEY_FILE_TEMPLATE must be set')

# Check SSV_OPERATOR_PASSWORD_FILE
if (
not remote_signer_url
and cluster_type == SSV
Expand Down
4 changes: 2 additions & 2 deletions src/validators/keystores/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
from src.config.settings import OBOL, SSV
from src.validators.keystores.base import BaseKeystore
from src.validators.keystores.obol import ObolKeystore
from src.validators.keystores.remote import RemoteSignerKeystore
from src.validators.keystores.obol_remote import ObolRemoteKeystore
from src.validators.keystores.ssv import SSVKeystore

logger = cast(ExtendedLogger, logging.getLogger(__name__))


async def load_keystore() -> BaseKeystore:
if settings.remote_signer_url:
remote_keystore = await RemoteSignerKeystore.load()
remote_keystore = await ObolRemoteKeystore.load()
logger.info(
'Using remote signer at %s for %i public keys',
settings.remote_signer_url,
Expand Down
3 changes: 0 additions & 3 deletions src/validators/keystores/obol.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ async def load_from_dir(keystores_dir: Path, node_index: int) -> 'ObolKeystore':

@staticmethod
def load_cluster_lock() -> dict:
if not settings.obol_cluster_lock_file:
raise RuntimeError('OBOL_CLUSTER_LOCK_FILE must be set')

return json.load(open(settings.obol_cluster_lock_file, encoding='ascii'))

@staticmethod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import dataclasses
import json
import logging
from dataclasses import dataclass
from typing import cast
Expand Down Expand Up @@ -45,14 +46,40 @@ class VoluntaryExitRequestModel:
voluntary_exit: VoluntaryExitMessage


class RemoteSignerKeystore(BaseKeystore):
def __init__(self, public_keys: list[HexStr]):
class ObolRemoteKeystore(BaseKeystore):
"""
Similar to RemoteKeystore from Stakewise Operator.
Also pubkey_to_share attribute is filled using cluster lock file.
"""

def __init__(self, public_keys: list[HexStr], pubkey_to_share: dict[HexStr, HexStr]):
self._public_keys = public_keys
self.pubkey_to_share = pubkey_to_share

@staticmethod
async def load() -> 'BaseKeystore':
public_keys = await RemoteSignerKeystore._get_remote_signer_public_keys()
return RemoteSignerKeystore(public_keys)
if settings.obol_node_index is None:
raise RuntimeError('OBOL_NODE_INDEX must be set')

public_keys = await ObolRemoteKeystore._get_remote_signer_public_keys()
pubkey_to_share = ObolRemoteKeystore.get_pubkey_to_share(settings.obol_node_index)
return ObolRemoteKeystore(public_keys, pubkey_to_share)

@staticmethod
def load_cluster_lock() -> dict:
return json.load(open(settings.obol_cluster_lock_file, encoding='ascii'))

@staticmethod
def get_pubkey_to_share(node_index: int) -> dict[HexStr, HexStr]:
cluster_lock = ObolRemoteKeystore.load_cluster_lock()

pub_key_to_share = {}
for dv in cluster_lock['distributed_validators']:
public_key = dv['distributed_public_key']
public_key_share = dv['public_shares'][node_index]
pub_key_to_share[public_key] = public_key_share

return pub_key_to_share

def __bool__(self) -> bool:
return bool(self._public_keys)
Expand Down

0 comments on commit db6449d

Please sign in to comment.