Skip to content

Commit

Permalink
sync-validator-keys: Add fees distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
cyc60 committed Sep 1, 2022
1 parent 6f811cd commit 0d8997d
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 4 deletions.
82 changes: 78 additions & 4 deletions stakewise_cli/commands/sync_validator_keys.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
import json
import os
from os import mkdir
from os.path import exists, join
from typing import List
from typing import Dict, List

import click
import yaml

from stakewise_cli.networks import MAINNET, NETWORKS
from stakewise_cli.storages.database import Database, check_db_connection
from stakewise_cli.utils import is_lists_equal
from stakewise_cli.validators import validate_db_uri, validate_env_name

PUBLIC_KEYS_CSV_FILENAME = "validator_keys.csv"
LIGHTHOUSE_CONFIG_FILENAME = "validator_definitions.yml"
SIGNER_CONFIG_FILENAME = "signer_keys.yml"
SIGNER_PROPOSER_CONFIG_FILENAME = "proposerConfig.json"
WEB3SIGNER_URL_ENV = "WEB3SIGNER_URL"


@click.command(help="Synchronizes validator public keys from the database")
@click.option(
"--network",
default=MAINNET,
help="The network to generate the deposit data for",
prompt="Enter the network name",
type=click.Choice(
NETWORKS.keys(),
case_sensitive=False,
),
)
@click.option(
"--db-url",
help="The database connection address.",
Expand All @@ -39,8 +52,18 @@
default=WEB3SIGNER_URL_ENV,
callback=validate_env_name,
)
@click.option(
"--solo-fees-file",
help="The path to solo validator's fee distribution path",
type=click.Path(exists=True, file_okay=True, dir_okay=False),
)
def sync_validator_keys(
db_url: str, index: int, output_dir: str, web3signer_url_env: str
network: str,
db_url: str,
index: int,
output_dir: str,
web3signer_url_env: str,
solo_fees_file: str,
) -> None:
"""
The command is running by the init container in validator pods.
Expand All @@ -67,10 +90,19 @@ def sync_validator_keys(
)
return

default_fee_recipient = NETWORKS[network]["FEE_DISTRIBUTION_CONTRACT_ADDRESS"]
solo_fee_mapping = {}
if solo_fees_file:
with open(solo_fees_file) as f:
solo_fee_mapping = json.load(f)

# save lighthouse config
web3signer_url = os.environ[web3signer_url_env]
lighthouse_config = _generate_lighthouse_config(
public_keys=keys, web3signer_url=web3signer_url
public_keys=keys,
web3signer_url=web3signer_url,
default_fee_recipient=default_fee_recipient,
solo_fee_mapping=solo_fee_mapping,
)
with open(join(output_dir, LIGHTHOUSE_CONFIG_FILENAME), "w") as f:
f.write(lighthouse_config)
Expand All @@ -79,6 +111,12 @@ def sync_validator_keys(
signer_keys_config = _generate_signer_keys_config(public_keys=keys)
with open(join(output_dir, SIGNER_CONFIG_FILENAME), "w") as f:
f.write(signer_keys_config)
proposer_config = _generate_proposer_config(
default_fee_recipient=default_fee_recipient,
solo_fee_mapping=solo_fee_mapping,
)
with open(join(output_dir, SIGNER_PROPOSER_CONFIG_FILENAME), "w") as f:
f.write(proposer_config)

click.secho(
f"The validator now uses {len(keys)} public keys.\n",
Expand All @@ -87,7 +125,12 @@ def sync_validator_keys(
)


def _generate_lighthouse_config(public_keys: List[str], web3signer_url: str) -> str:
def _generate_lighthouse_config(
public_keys: List[str],
web3signer_url: str,
default_fee_recipient: str,
solo_fee_mapping: Dict[str, str],
) -> str:
"""
Generate config for Lighthouse clients
"""
Expand All @@ -97,6 +140,9 @@ def _generate_lighthouse_config(public_keys: List[str], web3signer_url: str) ->
"voting_public_key": public_key,
"type": "web3signer",
"url": web3signer_url,
"suggested_fee_recipient": solo_fee_mapping.get(
public_key, default_fee_recipient
),
}
for public_key in public_keys
]
Expand All @@ -121,3 +167,31 @@ def _generate_signer_keys_config(public_keys: List[str]) -> str:
"""
keys = ",".join([f'"{public_key}"' for public_key in public_keys])
return f"""validators-external-signer-public-keys: [{keys}]"""


def _generate_proposer_config(
default_fee_recipient: str, solo_fee_mapping: Dict[str, str]
) -> str:
"""
Generate config for Teku and Prysm clients
"""
config = {
"proposer_config": {
**{
public_key: {
"fee_recipient": fee_recipient,
"builder": {
"enabled": True,
},
}
for public_key, fee_recipient in solo_fee_mapping.items()
}
},
"default_config": {
"fee_recipient": default_fee_recipient,
"builder": {
"enabled": True,
},
},
}
return json.dumps(config)
5 changes: 5 additions & 0 deletions stakewise_cli/networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
DAO_ENS_NAME="stakewise.eth",
ENS_RESOLVER_CONTRACT_ADDRESS="0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41",
SWISE_TOKEN_CONTRACT_ADDRESS="0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2",
FEE_DISTRIBUTION_CONTRACT_ADDRESS="0x0000000000000000000000000000000000000000",
OPERATORS_COMMITTEE_ENS_KEY="operators_committee",
IS_POA=False,
),
Expand All @@ -54,6 +55,7 @@
DAO_ENS_NAME="stakewise.eth",
ENS_RESOLVER_CONTRACT_ADDRESS="0x4B1488B7a6B320d2D721406204aBc3eeAa9AD329",
SWISE_TOKEN_CONTRACT_ADDRESS="0x0e2497aACec2755d831E4AFDEA25B4ef1B823855",
FEE_DISTRIBUTION_CONTRACT_ADDRESS="0x6A9d30e05C6832E868390F155388c7d97A6faEAC",
OPERATORS_COMMITTEE_ENS_KEY="operators_committee",
IS_POA=True,
),
Expand All @@ -79,6 +81,7 @@
DAO_ENS_NAME="",
ENS_RESOLVER_CONTRACT_ADDRESS="",
SWISE_TOKEN_CONTRACT_ADDRESS="0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2",
FEE_DISTRIBUTION_CONTRACT_ADDRESS="0x0000000000000000000000000000000000000000",
OPERATORS_COMMITTEE_ENS_KEY="",
IS_POA=False,
),
Expand All @@ -104,6 +107,7 @@
DAO_ENS_NAME="",
ENS_RESOLVER_CONTRACT_ADDRESS="",
SWISE_TOKEN_CONTRACT_ADDRESS="0x0e2497aACec2755d831E4AFDEA25B4ef1B823855",
FEE_DISTRIBUTION_CONTRACT_ADDRESS="0x0000000000000000000000000000000000000000",
OPERATORS_COMMITTEE_ENS_KEY="",
IS_POA=True,
),
Expand All @@ -127,6 +131,7 @@
DAO_ENS_NAME="",
ENS_RESOLVER_CONTRACT_ADDRESS="",
SWISE_TOKEN_CONTRACT_ADDRESS="0xfdA94F056346d2320d4B5E468D6Ad099b2277746",
FEE_DISTRIBUTION_CONTRACT_ADDRESS="0x0000000000000000000000000000000000000000",
OPERATORS_COMMITTEE_ENS_KEY="",
IS_POA=True,
),
Expand Down
26 changes: 26 additions & 0 deletions stakewise_cli/tests/test_sync_validator_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

from stakewise_cli.commands.sync_validator_keys import sync_validator_keys
from stakewise_cli.eth2 import WORD_LISTS_PATH, get_mnemonic_signing_key
from stakewise_cli.networks import MAINNET, NETWORKS

from .factories import faker

w3 = Web3()

Expand Down Expand Up @@ -38,29 +41,39 @@ def get_public_keys(mnemonic, keys_count):
class TestCommand(unittest.TestCase):
def test_sync_validator_keys(self, *mocks):
db_url = "postgresql://username:pass@hostname/dbname"
network = MAINNET
index = 1
runner = CliRunner()
solo_pub_key, solo_address = faker.public_key(), faker.eth_address()
args = [
"--network",
network,
"--index",
index,
"--db-url",
db_url,
"--output-dir",
"./valdata",
"--solo-fees-file",
"./solo-fees.json",
]
with runner.isolated_filesystem():
with open("./solo-fees.json", "w") as f:
f.writelines('{"%s":"%s"}' % (solo_pub_key, solo_address))
result = runner.invoke(sync_validator_keys, args)
assert result.exit_code == 0

assert (
f"The validator now uses {keys_count} public keys."
== result.output.strip()
)

with open("./valdata/validator_definitions.yml") as f:
s = """---"""
for public_key in public_keys:
s += f"""
- enabled: true
suggested_fee_recipient: \'{NETWORKS[network]["FEE_DISTRIBUTION_CONTRACT_ADDRESS"]}\'
type: web3signer
url: {web3_signer_url}
voting_public_key: \'{public_key}\'"""
Expand All @@ -72,6 +85,19 @@ def test_sync_validator_keys(self, *mocks):
ff = f.read()
assert ff == s, (ff, s)

with open("./valdata/proposerConfig.json") as f:
s = (
'{"proposer_config": {"%s": {"fee_recipient": "%s", "builder": {"enabled": true}}}, "default_config": {"fee_recipient": "%s", "builder": {"enabled": true}}}'
% (
solo_pub_key,
solo_address,
NETWORKS[network]["FEE_DISTRIBUTION_CONTRACT_ADDRESS"],
)
)
ff = f.read()

assert ff == s, (ff, s)

result = runner.invoke(sync_validator_keys, args)
assert result.exit_code == 0
assert "Keys already synced to the last version." == result.output.strip()

0 comments on commit 0d8997d

Please sign in to comment.