Skip to content

Commit

Permalink
Use single library for SSZ, bls-to-execution-change and presigned-exi…
Browse files Browse the repository at this point in the history
…t-message (#54)

* Make bls-to-execution-change command work

* [STACKED] Command to generate presigned exit message (#55)

* Command to generate presigned exit message

* Docs for presigned-exit-message

* Code review feedback

* Add support for sending signed payloads to beacon node

* Add note on backwards compatibility policy

* Unify regex usage

* Adjustments for single payload cmds

- Fix presigned-exit-message format & beacon node sending
- Rename Operator traits -> validator
- Rename operator module -> operations

* Fix README
  • Loading branch information
mksh authored Aug 23, 2024
1 parent 3e4f624 commit ae15e9b
Show file tree
Hide file tree
Showing 26 changed files with 1,673 additions and 880 deletions.
1,100 changes: 690 additions & 410 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,34 @@ ethereum_hashing = "0.6.0"
eth2_key_derivation = { git = "https://github.com/ChorusOne/lighthouse", rev = "1be5253610dc8fee3bf4b7a8dc1d01254bc5b57d"}
eth2_keystore = { git = "https://github.com/ChorusOne/lighthouse", rev = "1be5253610dc8fee3bf4b7a8dc1d01254bc5b57d"}
eth2_network_config = { git = "https://github.com/ChorusOne/lighthouse", rev = "1be5253610dc8fee3bf4b7a8dc1d01254bc5b57d" }
ethereum_ssz = "0.5.3"
ethereum_ssz = "0.5.4"
ethereum_ssz_derive = "0.5.4"
eth2_wallet = { git = "https://github.com/ChorusOne/lighthouse", rev = "1be5253610dc8fee3bf4b7a8dc1d01254bc5b57d"}
ethereum-types = { version = "0.14.1", optional = true }
env_logger = "^0.11"
hex = "0.4"
lazy_static = "1.5"
log = "^0.4"
# eth2_network_config uses native-tls, so do we
reqwest = { version = "0.11", default-features = false, features = ["native-tls"] }
getrandom = "0.2"
regex = "1.10.6"
serde = "1.0.204"
serde_derive = "1.0"
serde_json = "1.0"
ssz_rs = { git = "https://github.com/ChorusOne/ssz-rs.git", rev = "1f94d5dfc70c86dab672e91ac46af04a5f96c342" }
ssz_rs_derive = { git = "https://github.com/ChorusOne/ssz-rs.git", rev = "1f94d5dfc70c86dab672e91ac46af04a5f96c342" }
tiny-bip39 = "1.0.0"
# This must be pinned to a version that lighthouse uses
tree_hash = "0.5.2"
tree_hash_derive = "0.5.2"
types = { git = "https://github.com/ChorusOne/lighthouse", rev = "1be5253610dc8fee3bf4b7a8dc1d01254bc5b57d"}
url = "2.5"
uuid = { version = "1.10", features = ["v4"] }

[dev-dependencies]
test-log = "^0.2"
pretty_assertions = "^1.4"
assert_cmd = "2.0"
predicates = "3.0"
httpmock = "0.7"

[[test]]
name = "e2e-tests"
Expand Down
65 changes: 52 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,49 @@ You can use `eth-staking-smith` as follows to convert your address:
### Command to generate SignedBLSToExecutionChange

```
./target/debug/eth-staking-smith bls-to-execution-change --chain mainnet --mnemonic "entire habit bottom mention spoil clown finger wheat motion fox axis mechanic country make garment bar blind stadium sugar water scissors canyon often ketchup" --validator_start_index 0 --validator_index 100 --withdrawal_credentials "0x0045b91b2f60b88e7392d49ae1364b55e713d06f30e563f9f99e10994b26221d"
./target/debug/eth-staking-smith bls-to-execution-change --chain mainnet --mnemonic "entire habit bottom mention spoil clown finger wheat motion fox axis mechanic country make garment bar blind stadium sugar water scissors canyon often ketchup" --validator_start_index 0 --validator_index 100 --withdrawal_credentials "0x0045b91b2f60b88e7392d49ae1364b55e713d06f30e563f9f99e10994b26221d" \
--execution_address "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
```

Note that --validator-index and --validator-start-index are two distinct parameter, the former being index of validator on Beacon chain, and the latter is the index of validator private key derived from the seed


### Command to send SignedBLSToExecutionChange request to Beacon node

```
./target/debug/eth-staking-smith bls-to-execution-change --chain mainnet --mnemonic "entire habit bottom mention spoil clown finger wheat motion fox axis mechanic country make garment bar blind stadium sugar water scissors canyon often ketchup" --validator_start_index 0 --validator_index 100 --withdrawal_credentials "0x0045b91b2f60b88e7392d49ae1364b55e713d06f30e563f9f99e10994b26221d" \
--execution_address "0x71C7656EC7ab88b098defB751B7401B5f6d8976F" \
--beacon-node-uri http://beacon-node.local:5052
```

Notice `--beacon-node-uri` parameter which makes payload to be sent to beacon node

## Generating pre-signed exit message

It is possible to create pre-signed voluntary exit message for every validator that
is generated from some known mnemonic, given the minimum epoch for exit to trigger.

Use `eth-staking-smith` via command line like:

### Command to generate presigned exit message

```
./target/debug/eth-staking-smith presigned-exit-message --chain mainnet --mnemonic "entire habit bottom mention spoil clown finger wheat motion fox axis mechanic country make garment bar blind stadium sugar water scissors canyon often ketchup" --validator_seed_index 0 --validator_beacon_index 100 --epoch 300000
```

Note that --validator-beacon-index and --validator-seed-index are two distinct parameter, the former being index of validator on Beacon chain, and the latter is the index of validator private key derived from the seed


### Command to send VoluntaryExitMessage request to Beacon node

```
./target/debug/eth-staking-smith presigned-exit-message --chain mainnet --mnemonic "entire habit bottom mention spoil clown finger wheat motion fox axis mechanic country make garment bar blind stadium sugar water scissors canyon often ketchup" --validator_seed_index 0 --validator_beacon_index 100 --epoch 300000 \
--beacon-node-uri http://beacon-node.local:5052
```

Notice `--beacon-node-uri` parameter which makes payload to be sent to beacon node


## Exporting CLI standard output into common keystores folder format

Most validator clients recognize the keystore folder format,
Expand Down Expand Up @@ -117,18 +154,6 @@ lighthouse account validator import \
--directory validator_keys/ --password-file ./password.txt
```

### Command to send SignedBLSToExecutionChange request to Beacon node

```
curl -H "Content-Type: application/json" -d '{
"message": {
"validator_index": 100,
"from_bls_pubkey": "0x0045b91b2f60b88e7392d49ae1364b55e713d06f30e563f9f99e10994b26221d",
"to_execution_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
},
"signature": "0x9220e5badefdfe8abc36cae01af29b981edeb940ff88c438f72c8af876fbd6416138c85f5348c5ace92a081fa15291aa0ffb856141b871dc807f3ec2fe9c8415cac3d76579c61455ab3938bc162e139d060c8aa13fcd670febe46bf0bb579c5a"
}' http://localhost:3500/eth/v1/beacon/pool/bls_to_execution_change
```

# Implementation Details
To avoid heavy lifting, we're interfacing [Lighthouse account manager](https://github.com/sigp/lighthouse/blob/stable/account_manager), but optimizing it in a way so all operations are done in memory and key material is never written to filesystem during the generation to cater for our use case.
Expand Down Expand Up @@ -163,3 +188,17 @@ To test our code e2e, we've generated files using the [staking deposit cli v2.3.
| seed | secret value used to derive HD wallet addresses from a mnemonic phrase (BIP39 standard) |
| withdrawal credentials | Withdrawal Credentials is a 32-byte field in the deposit data, for verifying the destination of valid withdrawals. Currently, there are two types of withdrawals: BLS withdrawal (with a 00 prefix) and Ethereum withdrawals (with a 01 prefix). By default the former will be generated, however Ethereum is planning to fully move to 01 credentials once withdrawals become available |
| withdrawal address | Address for which withdrawal credentials should be generated. Eth staking smith allows execution addresses with the format `^(0x[a-fA-F0-9]{40})$` |


## Backwards compatibility
This project aims to present state-of-art Ethereum staking experience,
and does not follow semver approach for new releases.
Instead, backwards compatibility is provided on best-effort basis for both
library and command line interfaces, and every release that adds new
functionality can be treated as major release.

Interfaces may change as result of implementing new features, and/or
backwards incompatible changes in Ethereum protocol.

It is recommended to pin release version for users of command line interface,
and pin specific git commit of `eth-staking-smith` for library interface users.
44 changes: 44 additions & 0 deletions src/beacon_node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#[derive(Debug)]
pub enum BeaconNodeError {
InvalidBeaconNodeURI,
ClientConfigurationError,
NodeCommunicationError,
Non200Response,
}

/// A trait for types that can be sent to beacon node as-is
/// without transformations
pub trait BeaconNodeExportable {
/// Export an entity as JSON
fn export(&self) -> serde_json::Value;

/// The path at beacon node where to send data
fn beacon_node_path(&self) -> String;

/// Send the JSON payload to beacon node
fn send_beacon_payload(&self, beacon_node_uri: url::Url) -> Result<(), BeaconNodeError> {
let reqwc = reqwest::blocking::Client::builder()
.build()
.map_err(|_| BeaconNodeError::ClientConfigurationError)?;
let joined_url = beacon_node_uri
.join(&self.beacon_node_path())
.map_err(|_| BeaconNodeError::InvalidBeaconNodeURI)?;
let resp = reqwc
.post(joined_url)
.header("Content-Type", "application/json")
.body(self.export().to_string())
.send();

match resp {
Ok(response) => {
let code = response.status().as_u16();
if code != 200 {
Err(BeaconNodeError::Non200Response)
} else {
Ok(())
}
}
Err(_) => Err(BeaconNodeError::NodeCommunicationError),
}
}
}
Loading

0 comments on commit ae15e9b

Please sign in to comment.