From df350e9b747a195352f4a312cbe1202a2dd886c8 Mon Sep 17 00:00:00 2001 From: Dmitri Tsumak Date: Mon, 21 Feb 2022 00:29:40 +0200 Subject: [PATCH] Add permissioned goerli network (#19) --- README.md | 12 +++--- operator_cli/commands/create_deposit_data.py | 44 ++++++++++---------- operator_cli/commands/sync_local.py | 11 ++--- operator_cli/commands/sync_vault.py | 11 ++--- operator_cli/commands/upload_deposit_data.py | 11 ++--- operator_cli/eth1.py | 4 +- operator_cli/networks.py | 35 +++++++++++++--- poetry.lock | 32 +++++++------- pyproject.toml | 2 +- 9 files changed, 86 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 32f76e4..7ecfe58 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Operator CLI Operators CLI generates validators keys and deposit data for the validators. -The validator keys have to be uploaded to the Hashicorp Vault for the secure storage. -Read more about operators onboarding process [here](https://docs.stakewise.io/node-operator/dao-proposal) +The validator keys have to be uploaded to the Hashicorp Vault or fetched locally. +Read more about [operators onboarding process](https://docs.stakewise.io/node-operator/onboarding-process) ## Usage @@ -12,7 +12,7 @@ See [releases page](https://github.com/stakewise/cli/releases) to download and d ### Step 2. Create Deposit Data -Run the following command to generate the DAO proposal specification: +Run the following command to create deposit data and DAO proposal specification: ```bash ./operator-cli create-deposit-data @@ -28,7 +28,7 @@ In your post you must include the `Specification` section that was generated in ### Step 4. Deploy ETH2 infrastructure -If the proposal from the previous step got approved by the DAO, follow the instructions [here](https://docs.stakewise.io/node-operator/stakewise-infra-package) +If the proposal from the previous step got approved by the DAO, follow the instructions [here](https://docs.stakewise.io/node-operator/stakewise-infra-package/usage) to deploy the ETH2 staking infrastructure. ### Step 5. Sync keys to the Vault or locally @@ -48,13 +48,13 @@ or to sync them locally ./operator-cli sync-local ``` -After uploading the keys, make sure you have the right number of validators running and restart those that got new keys added. +After fetching the keys, make sure you have the right number of validators running and restart those that got new keys added. ### Step 6. Commit Operator Once you're 100% ready for Ether assignments, commit your operator: -- Go to the Operators smart contract ([Goerli](https://goerli.etherscan.io/address/0x0d92156861a0BC7037cC21470327Bd3Bc750EB1D#writeProxyContract), [Mainnet](https://etherscan.io/address/0x002932e11E95DC84C17ed5f94a0439645D8a97BC)) +- Go to the Operators smart contract ([Goerli](https://goerli.etherscan.io/address/0x0d92156861a0BC7037cC21470327Bd3Bc750EB1D#writeProxyContract), [Perm Goerli](https://goerli.etherscan.io/address/0x7C27896338e3130036E53BCC0f013cB20e21991c#writeProxyContract), [Mainnet](https://etherscan.io/address/0x002932e11E95DC84C17ed5f94a0439645D8a97BC)) - Click on `Connect to Web3` button and connect your wallet. The address must match the one used during proposal generation. - Call `commitOperator` function. If that's your onboarding, you must deposit 1 ETH (specified in Wei) collateral together with the call. diff --git a/operator_cli/commands/create_deposit_data.py b/operator_cli/commands/create_deposit_data.py index 3114878..1f4756a 100644 --- a/operator_cli/commands/create_deposit_data.py +++ b/operator_cli/commands/create_deposit_data.py @@ -14,23 +14,18 @@ validate_mnemonic, ) from operator_cli.ipfs import upload_deposit_data_to_ipfs -from operator_cli.networks import ( - ETHEREUM_GOERLI, - ETHEREUM_MAINNET, - GNOSIS_CHAIN, - NETWORKS, -) +from operator_cli.networks import GNOSIS_CHAIN, GOERLI, MAINNET, NETWORKS, PERM_GOERLI from operator_cli.queries import get_ethereum_gql_client, get_stakewise_gql_client @click.command(help="Creates deposit data and generates a forum post specification") @click.option( "--network", - default=ETHEREUM_MAINNET, + default=MAINNET, help="The network to generate the deposit data for", prompt="Enter the network name", type=click.Choice( - [ETHEREUM_MAINNET, ETHEREUM_GOERLI, GNOSIS_CHAIN], case_sensitive=False + [MAINNET, GOERLI, PERM_GOERLI, GNOSIS_CHAIN], case_sensitive=False ), ) @click.option( @@ -90,13 +85,15 @@ def create_deposit_data( # 4. Generate private key shares for the committee sw_gql_client = get_stakewise_gql_client(network) - committee_paths = create_committee_shares( - network=network, - gql_client=sw_gql_client, - operator=operator, - committee_folder=committee_folder, - keypairs=keypairs, - ) + if network != PERM_GOERLI: + # no private key shares form permissioned network + committee_paths = create_committee_shares( + network=network, + gql_client=sw_gql_client, + operator=operator, + committee_folder=committee_folder, + keypairs=keypairs, + ) # 5. Upload deposit data to IPFS ipfs_url = upload_deposit_data_to_ipfs(deposit_data) @@ -117,10 +114,13 @@ def create_deposit_data( click.echo(specification) # 7. Generate committee message - click.secho( - "Share the encrypted validator key shares with the committee members through Telegram:", - bold=True, - fg="green", - ) - for username, path in committee_paths.items(): - click.echo(f"- @{username}: {path}") + if network != PERM_GOERLI: + # no private key shares form permissioned network + click.secho( + "Share the encrypted validator key shares with the committee members through Telegram:", + bold=True, + fg="green", + ) + # noinspection PyUnboundLocalVariable + for username, path in committee_paths.items(): + click.echo(f"- @{username}: {path}") diff --git a/operator_cli/commands/sync_local.py b/operator_cli/commands/sync_local.py index 80d453c..22f39aa 100644 --- a/operator_cli/commands/sync_local.py +++ b/operator_cli/commands/sync_local.py @@ -7,12 +7,7 @@ from web3 import Web3 from operator_cli.eth2 import get_beacon_client, validate_mnemonic -from operator_cli.networks import ( - ETHEREUM_GOERLI, - ETHEREUM_MAINNET, - GNOSIS_CHAIN, - NETWORKS, -) +from operator_cli.networks import GNOSIS_CHAIN, GOERLI, MAINNET, NETWORKS, PERM_GOERLI from operator_cli.storages.local import LocalStorage @@ -29,11 +24,11 @@ def validate_operator_address(ctx, param, value): @click.command(help="Synchronizes validator keystores to the local folder") @click.option( "--network", - default=ETHEREUM_MAINNET, + default=MAINNET, help="The network of ETH2 you are targeting.", prompt="Please choose the network name", type=click.Choice( - [ETHEREUM_MAINNET, ETHEREUM_GOERLI, GNOSIS_CHAIN], case_sensitive=False + [MAINNET, GOERLI, PERM_GOERLI, GNOSIS_CHAIN], case_sensitive=False ), ) @click.option( diff --git a/operator_cli/commands/sync_vault.py b/operator_cli/commands/sync_vault.py index 073704d..6c7729e 100644 --- a/operator_cli/commands/sync_vault.py +++ b/operator_cli/commands/sync_vault.py @@ -7,12 +7,7 @@ from web3 import Web3 from operator_cli.eth2 import get_beacon_client, validate_mnemonic -from operator_cli.networks import ( - ETHEREUM_GOERLI, - ETHEREUM_MAINNET, - GNOSIS_CHAIN, - NETWORKS, -) +from operator_cli.networks import GNOSIS_CHAIN, GOERLI, MAINNET, NETWORKS, PERM_GOERLI from operator_cli.settings import VAULT_VALIDATORS_MOUNT_POINT from operator_cli.storages.vault import Vault @@ -44,11 +39,11 @@ def validate_operator_address(ctx, param, value): @click.command(help="Synchronizes validator keystores in the vault") @click.option( "--network", - default=ETHEREUM_MAINNET, + default=MAINNET, help="The network of ETH2 you are targeting.", prompt="Please choose the network name", type=click.Choice( - [ETHEREUM_MAINNET, ETHEREUM_GOERLI, GNOSIS_CHAIN], case_sensitive=False + [MAINNET, GOERLI, PERM_GOERLI, GNOSIS_CHAIN], case_sensitive=False ), ) @click.option( diff --git a/operator_cli/commands/upload_deposit_data.py b/operator_cli/commands/upload_deposit_data.py index dc559be..ec239ee 100644 --- a/operator_cli/commands/upload_deposit_data.py +++ b/operator_cli/commands/upload_deposit_data.py @@ -13,12 +13,7 @@ from operator_cli.eth2 import verify_deposit_data from operator_cli.ipfs import upload_deposit_data_to_ipfs from operator_cli.merkle_tree import MerkleTree -from operator_cli.networks import ( - ETHEREUM_GOERLI, - ETHEREUM_MAINNET, - GNOSIS_CHAIN, - NETWORKS, -) +from operator_cli.networks import GNOSIS_CHAIN, GOERLI, MAINNET, NETWORKS, PERM_GOERLI from operator_cli.queries import ( REGISTRATIONS_QUERY, get_ethereum_gql_client, @@ -162,11 +157,11 @@ def check_public_keys_not_registered( ) @click.option( "--network", - default=ETHEREUM_MAINNET, + default=MAINNET, help="The network of ETH2 you are targeting.", prompt="Please choose the network name", type=click.Choice( - [ETHEREUM_MAINNET, ETHEREUM_GOERLI, GNOSIS_CHAIN], case_sensitive=False + [MAINNET, GOERLI, PERM_GOERLI, GNOSIS_CHAIN], case_sensitive=False ), ) @click.option( diff --git a/operator_cli/eth1.py b/operator_cli/eth1.py index 3cb3126..20b3253 100644 --- a/operator_cli/eth1.py +++ b/operator_cli/eth1.py @@ -9,7 +9,7 @@ from operator_cli.contracts import get_ens_node_id, get_ens_resolver, get_web3_client from operator_cli.ipfs import ipfs_fetch -from operator_cli.networks import ETHEREUM_MAINNET, GNOSIS_CHAIN, NETWORKS +from operator_cli.networks import GNOSIS_CHAIN, MAINNET, NETWORKS from operator_cli.queries import OPERATOR_QUERY, VALIDATORS_QUERY @@ -63,7 +63,7 @@ def get_operators_committee(network: str) -> List[List[str]]: """Fetches committee config from the DAO's ENS text record.""" # XXX: ENS does not support gnosis chain if network == GNOSIS_CHAIN: - network = ETHEREUM_MAINNET + network = MAINNET w3 = get_web3_client(network) ens_resolver = get_ens_resolver(network, w3) diff --git a/operator_cli/networks.py b/operator_cli/networks.py index f988f89..c00768f 100644 --- a/operator_cli/networks.py +++ b/operator_cli/networks.py @@ -1,11 +1,12 @@ from decouple import config -ETHEREUM_MAINNET = "mainnet" -ETHEREUM_GOERLI = "goerli" +MAINNET = "mainnet" +GOERLI = "goerli" +PERM_GOERLI = "perm_goerli" GNOSIS_CHAIN = "gnosis" NETWORKS = { - ETHEREUM_MAINNET: dict( + MAINNET: dict( STAKEWISE_SUBGRAPH_URL=config( "STAKEWISE_SUBGRAPH_URL", default="https://api.thegraph.com/subgraphs/name/stakewise/stakewise-mainnet", @@ -29,7 +30,7 @@ OPERATORS_COMMITTEE_ENS_KEY="operators_committee", IS_POA=False, ), - ETHEREUM_GOERLI: dict( + GOERLI: dict( STAKEWISE_SUBGRAPH_URL=config( "STAKEWISE_SUBGRAPH_URL", default="https://api.thegraph.com/subgraphs/name/stakewise/stakewise-goerli", @@ -45,7 +46,7 @@ GENESIS_FORK_VERSION=bytes.fromhex("00001020"), MAX_KEYS_PER_VALIDATOR=100, ETH1_ENDPOINT=config( - "WITHDRAWAL_CREDENTIALS", + "ETH1_ENDPOINT", default="https://goerli.infura.io/v3/84842078b09946638c03157f83405213", ), DAO_ENS_NAME="stakewise.eth", @@ -53,6 +54,30 @@ OPERATORS_COMMITTEE_ENS_KEY="operators_committee", IS_POA=True, ), + PERM_GOERLI: dict( + STAKEWISE_SUBGRAPH_URL=config( + "STAKEWISE_SUBGRAPH_URL", + default="https://api.thegraph.com/subgraphs/name/stakewise/stakewise-perm-goerli", + ), + ETHEREUM_SUBGRAPH_URL=config( + "ETHEREUM_SUBGRAPH_URL", + default="https://api.thegraph.com/subgraphs/name/stakewise/ethereum-goerli", + ), + WITHDRAWAL_CREDENTIALS=config( + "WITHDRAWAL_CREDENTIALS", + default="0x0100000000000000000000006dfc9682e3c3263758ad96e2b2ba9822167f81ee", + ), + GENESIS_FORK_VERSION=bytes.fromhex("00001020"), + MAX_KEYS_PER_VALIDATOR=100, + ETH1_ENDPOINT=config( + "ETH1_ENDPOINT", + default="https://goerli.infura.io/v3/84842078b09946638c03157f83405213", + ), + DAO_ENS_NAME="", + ENS_RESOLVER_CONTRACT_ADDRESS="0x4B1488B7a6B320d2D721406204aBc3eeAa9AD329", + OPERATORS_COMMITTEE_ENS_KEY="", + IS_POA=True, + ), GNOSIS_CHAIN: dict( STAKEWISE_SUBGRAPH_URL=config( "STAKEWISE_SUBGRAPH_URL", diff --git a/poetry.lock b/poetry.lock index 9d53dd0..560a135 100644 --- a/poetry.lock +++ b/poetry.lock @@ -376,7 +376,7 @@ test = ["hypothesis (>=4.43.0,<5.0.0)", "pytest (==5.4.1)", "pytest-xdist", "tox [[package]] name = "filelock" -version = "3.4.2" +version = "3.6.0" description = "A platform independent file lock." category = "dev" optional = false @@ -506,7 +506,7 @@ parser = ["pyhcl (>=0.3.10)"] [[package]] name = "identify" -version = "2.4.9" +version = "2.4.10" description = "File identification library for Python" category = "dev" optional = false @@ -688,7 +688,7 @@ future = "*" [[package]] name = "platformdirs" -version = "2.5.0" +version = "2.5.1" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false @@ -816,7 +816,7 @@ hook_testing = ["pytest (>=2.7.3)", "execnet (>=1.5.0)", "psutil"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2022.1" +version = "2022.2" description = "Community maintained hooks for PyInstaller" category = "dev" optional = false @@ -980,7 +980,7 @@ python-versions = ">=3.5" [[package]] name = "typing-extensions" -version = "4.1.0" +version = "4.1.1" description = "Backported and Experimental Type Hints for Python 3.6+" category = "dev" optional = false @@ -1078,7 +1078,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = ">=3.8,<3.9" -content-hash = "9086543f568b6b788b564a8a2da633ff93df3041606aff259694b99887878136" +content-hash = "2d9a9d6dfd67e1ccd883aa42c2d0e65df90de84afcacfaf1050d30a5fb36a17c" [metadata.files] aiodns = [ @@ -1422,8 +1422,8 @@ eth-utils = [ {file = "eth_utils-1.10.0-py3-none-any.whl", hash = "sha256:74240a8c6f652d085ed3c85f5f1654203d2f10ff9062f83b3bad0a12ff321c7a"}, ] filelock = [ - {file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"}, - {file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"}, + {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"}, + {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"}, ] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, @@ -1517,8 +1517,8 @@ hvac = [ {file = "hvac-0.11.2.tar.gz", hash = "sha256:f905c59d32d88d3f67571fe5a8a78de4659e04798ad809de439f667247d13626"}, ] identify = [ - {file = "identify-2.4.9-py2.py3-none-any.whl", hash = "sha256:bff7c4959d68510bc28b99d664b6a623e36c6eadc933f89a4e0a9ddff9b4fee4"}, - {file = "identify-2.4.9.tar.gz", hash = "sha256:e926ae3b3dc142b6a7a9c65433eb14ccac751b724ee255f7c2ed3b5970d764fb"}, + {file = "identify-2.4.10-py2.py3-none-any.whl", hash = "sha256:7d10baf6ba6f1912a0a49f4c1c2c49fa1718765c3a37d72d13b07779567c5b85"}, + {file = "identify-2.4.10.tar.gz", hash = "sha256:e12b2aea3cf108de73ae055c2260783bde6601de09718f6768cf8e9f6f6322a6"}, ] idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, @@ -1657,8 +1657,8 @@ pefile = [ {file = "pefile-2021.9.3.tar.gz", hash = "sha256:344a49e40a94e10849f0fe34dddc80f773a12b40675bf2f7be4b8be578bdd94a"}, ] platformdirs = [ - {file = "platformdirs-2.5.0-py3-none-any.whl", hash = "sha256:30671902352e97b1eafd74ade8e4a694782bd3471685e78c32d0fdfd3aa7e7bb"}, - {file = "platformdirs-2.5.0.tar.gz", hash = "sha256:8ec11dfba28ecc0715eb5fb0147a87b1bf325f349f3da9aab2cd6b50b96b692b"}, + {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, + {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, ] pre-commit = [ {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"}, @@ -1790,8 +1790,8 @@ pyinstaller = [ {file = "pyinstaller-4.9.tar.gz", hash = "sha256:75a180a658871bc41f9cf94b6f90ffa54e98f5d6a7cdb02d7530f0360afe24f9"}, ] pyinstaller-hooks-contrib = [ - {file = "pyinstaller-hooks-contrib-2022.1.tar.gz", hash = "sha256:f0a40fbe1842598a7066f785da5ac103ae2a86b4cebf478e530e1df57464814e"}, - {file = "pyinstaller_hooks_contrib-2022.1-py2.py3-none-any.whl", hash = "sha256:37f0a16df336c69c8c7bf76105a6c4a53a270d648920fa21de654a6649e70404"}, + {file = "pyinstaller-hooks-contrib-2022.2.tar.gz", hash = "sha256:ab1d14fe053016fff7b0c6aea51d980bac6d02114b04063b46ef7dac70c70e1e"}, + {file = "pyinstaller_hooks_contrib-2022.2-py2.py3-none-any.whl", hash = "sha256:7605e440ccb55904cb2a87d72e83642ef176fb7030c77e52ac4d9679bb3d1537"}, ] pyrsistent = [ {file = "pyrsistent-0.16.1.tar.gz", hash = "sha256:aa2ae1c2e496f4d6777f869ea5de7166a8ccb9c2e06ebcf6c7ff1b670c98c5ef"}, @@ -1887,8 +1887,8 @@ toolz = [ {file = "toolz-0.11.2.tar.gz", hash = "sha256:6b312d5e15138552f1bda8a4e66c30e236c831b612b2bf0005f8a1df10a4bc33"}, ] typing-extensions = [ - {file = "typing_extensions-4.1.0-py3-none-any.whl", hash = "sha256:c13180fbaa7cd97065a4915ceba012bdb31dc34743e63ddee16360161d358414"}, - {file = "typing_extensions-4.1.0.tar.gz", hash = "sha256:ba97c5143e5bb067b57793c726dd857b1671d4b02ced273ca0538e71ff009095"}, + {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, + {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] urllib3 = [ {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, diff --git a/pyproject.toml b/pyproject.toml index bead332..587b678 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "operator-cli" -version = "0.1.0" +version = "1.0.0" description = "StakeWise Operator CLI is used to generate and manage ETH2 validator keys." authors = ["Dmitri Tsumak "] license = "AGPL-3.0-only"