# Validator Accounts Revamp - Prysmatic Labs This design document is a summary of how Prysmatic Labs is thinking about validator accounts management in light of the recent conversations regarding the topic. The goal of this document is to propose an extensible design for clients to define their accounts model and discuss some common terminology: ## Background Client teams have held a call regarding accounts management on June 18th 14:00GMT https://github.com/ethereum/eth2.0-pm/issues/161. Prysmatic Labs was not in attendance, but several valuable insights were shared by Jim Mcdee and Paul Hauner. Paul has proposed a hackmd for revamping validator accounts in lighthouse that is planned to be done collaboratively here: https://notes.ethereum.org/r6UL8XeuSfaewZwS8wzGig?view Paul's core idea is to have two directories: `keystores` and `passwords` which both contain simple files. Keystores are derived using EIP-2335 and we do not store withdrawal keys on disk but instead use mnemonics. We also create a lockfile whenever a voting keystore is being used by a validator client and remove that lockfile when we are done. The rationale is dealing with a file system is far easier than dealing with something like ethdo. In this simple structure, there can be a nested hierarchy in both directories, as there will be a recursive matching involved at runtime to be able to unlock keystores properly. A nice example Paul proposed is as follows: Joe has three validators, one of which he is managing for his Mum. He is also using the same password for both of his keystores. - keystores - my_validators - joe_1.voting-keystore.json - joe_2.voting-keystore.json - mums_validators - mum.voting-keystore.json - passwords - joe.pass - mum.pass Taking some ideas from this proposal, we created this document after some discussion with users of the Prysm eth2 client and internal discussions with our team on how to best revamp our accounts management for mainnet. ## Our Proposal Although the simple proposal is a great start and encompasses the general desire to move towards a file-based approach for handling direct keystore access, we propose a more extensible structure that can offer either direct, derived, or remote keystore access. ### Proposed Terminology In terms of user experience, we must avoid new and foreign terminology when possible. Wallets and accounts are familiar to users of ETH1 where a wallet may contain multiple accounts and an account represents a single public key or externally owned account on ethereum. - A **wallet** is the tangible, on disk metadata about the various accounts that an user owns and there may be multiple accounts within a given wallet. The `./prysm.sh validator accounts` command, for example, interacts with an on disk wallet at a specified directory path to perform its responsibilities - An **account** is a unique namespace that identifies a keystore and its associated metadata. We propose that one account should correspond to a single public key identifier (this is the same as popular eth1 wallets such as Metamask, in which one account is uniquely identified by its public key) - A **keymanager** defines a software interface which provides keystore access and management: can either be "remote", "derived", "direct", "unencrypted" (for interop / local dev). Proposed by Jim Mcdee - A **keystore**, based on [EIP-2335](https://eips.ethereum.org/EIPS/eip-2335) is "a mechanism for storing private keys. It is a JSON file that encrypts a private key and is the standard for interchanging keys between devices as until a user provides their password, their key is safe" While some new terminology exists for developers, (e.g. keystore, walletstore, BLS, etc), much of this can be abstracted and hidden from end users. ### Keymanager Types Based on user feedback, here are the most common types of **keymanagers** that are desirable in eth2 clients are: 1. **Direct keymanager** - An on disk, encrypted by passphrase, JSON storage format compatible with EIP-2386. These accounts provide hierarchical deterministic key generation. Each key, if stored or exported, will utilize the EIP-2335 format for representing BLS keys in JSON. 2. **Derived keymanager** - The deterministic account hierarchy implements EIP-2386 with the exception of using the same seed for generating withdrawal keys. A withdrawal key is managed separately from any hot / signing key account. 3. **Remote keymanager** - Some metadata about how to access public keys and request signatures from a remote service or device. There may be multiple implementations of remote signing such as gRPC service, hardware/USB wallets, etc. A keymanager can be described by an interface which allows access to the following information: ```go type Keymanager interface { SigningPublicKey() *bls.PublicKey WithdrawalPublicKey() *bls.PublicKey Sign(context.Context, interface{}) (interface{}, error) } ``` In this interface, we have read access to the account’s signing public key as well as their withdrawal public key. Users of this API can ask the account to sign an object. The keymanager will return an error if the provided object is not supported for signing or another unexpected error occurs. A keymanager has access to the underlying private key and has the ability to generate signatures. This access may be via remote access, on disk access, or some derived key in memory. #### Example Remote Keymanager ```go service RemoteKeymanager { rpc Sign(SignRequest) returns (SignResponse); } message SignRequest { bytes public_key = 1; bytes data = 2; bytes signature_domain = 3; oneof object { ethereum.eth.v1alpha1.BeaconBlock block = 4; ethereum.eth.v1alpha1.AttestationData = attestation_data = 5; ethereum.eth.v1alpha1.VoluntaryExit exit = 7; ... } } message SignResponse { bytes signature = 1; } ``` A signature request includes the public key expected to sign the data and the expected data to sign. The server may also use the signature domain and the provided object to verify the requested data and perform any additional validation on the object as desired. One potential use case for providing the domain and object is that the server may check the object does not produce a slashable condition. ### Proposed Folder Structure ``` datadir/ direct-wallet/ keymanageropts.json (type of keymanager: remote, direct, derived, etc.) account1/ deposit_data.rlp keystore.json (may not exist depending on the keymanageropts) ... account2/ deposit_data.rlp keystore.json (may not exist depending on the keymanageropts) remote-wallet/ keymanageropts.json (type of keymanager: remote, direct, derived, etc.) account1/ deposit_data.rlp keystore.json (may not exist depending on the keymanageropts) ... account2/ deposit_data.rlp keystore.json (may not exist depending on the keymanageropts) ... validator.db passwords/ account1.pass account2.pass ``` As in Paul's proposal, the account passwords (if using a direct keystore), will live somewhere on disk and allow for easy unlocking of validator accounts without needing to resort to ENV vars or CLI input. ### Keymanager Options File The keymanageropts.json file was suggested by Jim Mcdee as a simple way of specifying options and metadata for the type of keymanager utilized by an eth2 account. This file should: - Tell us what type of keymanager the account should use (direct, derived, remote) - Should include necessary metadata to establish access to the account, such as gRPC credentials, the derivation path for the derived keymanager, etc. - Should prefix every field with the keymanager type: `remote_, direct_, derived_` Remote keymanageropts.json example: ```json { account_type: "remote", remote_address: "grpc://localhost:5432", remote_grpc_crt_path: "/path/to/secret.crt" ... // TODO: Define more fields } ``` Direct keystore example: ```json { account_type: “direct”, direct_eip: “2335” ... // TODO: Define more fields } ``` Derived example: ```json { account_type: “derived”, derived_paths: [0, 2, 5], ... // TODO: Define more fields } ``` ## User Experience We can abstract away much of this underlying implementation and keymanageropts configuration by providing interactive account creation which creates these necessary options upon completion. Power users can instead provide keymanageropts.json via flags to satisfy any complex workflow. We want to maintain parity with eth1 terminology users are comfortable with, all the way from what a "wallet" is to the definition of an "account", and we believe this approach is flexible enough to accommodate various use-cases and is also extensible. ## References Our original design document that is summarized by this hackmd: https://docs.google.com/document/d/1u_P8veBtIj97u33y_bhOxmVOJJxkMHGNPoF6TvFhz2w/edit# (contains decisions specific to the Prysm client)