Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sign_voluntary_exit_message command #7

Merged
merged 12 commits into from
Feb 26, 2024
635 changes: 314 additions & 321 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 1 addition & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
[package]
name = "coral"
version = "0.1.0"
edition = "2021"

[workspace]
resolver = "2"
members = [
"coral-lib",
"coral-cli",
Expand Down
18 changes: 9 additions & 9 deletions coral-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.2"
chrono = "0.4.31"
clap = { version = "4.4.11", features = ["derive"] }
clap_complete = "4.4.4"
axum = "0.7.4"
chrono = "0.4.34"
clap = { version = "4.5.1", features = ["derive"] }
clap_complete = "4.5.1"
colored = "2.1.0"
dirs-next = "2.0.0"
ecies = { version = "0.2.6", default-features = false, features = ["pure"] }
hex = "0.4.3"
lazy_static = "1.4.0"
reqwest = { version = "0.11.23", features = ["json"] }
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
reqwest = { version = "0.11.24", features = ["json"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
shellexpand = { version = "3.1.0", features = ["full"] }
tokio = { version = "1.35.1", features = ["full"] }
tower-http = { version = "0.5.0", features = [ "cors", "trace" ] }
tokio = { version = "1.36.0", features = ["full"] }
tower-http = { version = "0.5.2", features = [ "cors", "trace" ] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = [ "std", "env-filter" ] }

Expand Down
16 changes: 16 additions & 0 deletions coral-cli/docs/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- [list-keys](#validator-list-keys)
- [register](#validator-register)
- [sign-voluntary-exit](#validator-sign-voluntary-exit)

## `validator list-keys`
List keys associated with this node
Expand Down Expand Up @@ -30,4 +31,19 @@ coral-cli validator register \
--withdrawal-credentials 0x01000000000000000000000049ce199bba75926ab5c6fc16fedd11d418cb2edf
--output-file registration_001.json \
--guardian-pubkeys 0x040783e639f5675cd12c86bab61678a2c4be44846b36df9a9648970ea803e92fd8dd25c51660b64f61d20fc04c77c34145410496fd923309a5c143b9c5eadd19e7
```

## `validator sign-voluntary-exit`
Sign voluntary exit message and stop validating

```
coral-cli validator sign-voluntary-exit \
--bls-public-key 0x94505f60bb8e48ddafb8835ec08537c48ed1bb9bc6a95fe941f37869b5eb0950c9023b7a997fe12d8aa79076561e009f \
--beacon-index 1605300 \
--enclave-url http://localhost:9001 \
--fork-previous-version 0x04017000 \
--fork-current-version 0x05017000 \
--epoch 29696 \
--genesis-validators-root 0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1 \
--output-file sign_vem_001.json
```
41 changes: 41 additions & 0 deletions coral-cli/src/commands/validator/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod list_keys;
pub mod register_validator;
pub mod sign_vem;

use std::path::PathBuf;

Expand Down Expand Up @@ -40,6 +41,24 @@ pub enum ValidatorCommand {
#[arg(long = "input-file")]
input_file: PathBuf,
},
SignVoluntaryExit {
#[arg(long = "bls-public-key")]
bls_pubkey: String,
#[arg(long = "beacon-index")]
beacon_index: u64,
#[arg(long = "enclave-url")]
enclave_url: String,
#[arg(long = "fork-previous-version")]
fork_previous_version: String,
#[arg(long = "fork-current-version")]
fork_current_version: String,
#[arg(long = "epoch")]
epoch: u64,
#[arg(long = "genesis-validators-root")]
genesis_validators_root: String,
#[arg(long = "output-file")]
output_file: String,
},
}

impl ValidatorCommand {
Expand Down Expand Up @@ -75,6 +94,28 @@ impl ValidatorCommand {
Self::RegisterWithFile { input_file } => {
register_validator::register_validator_from_file(input_file.as_path()).await?;
}
Self::SignVoluntaryExit {
enclave_url,
bls_pubkey,
beacon_index,
fork_current_version,
fork_previous_version,
epoch,
genesis_validators_root,
output_file,
} => {
sign_vem::sign_vem_from_cmd(
enclave_url,
bls_pubkey,
beacon_index,
fork_current_version,
fork_previous_version,
epoch,
genesis_validators_root,
output_file,
)
.await?;
}
}
Ok(0)
}
Expand Down
2 changes: 0 additions & 2 deletions coral-cli/src/commands/validator/register_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ pub struct RegisterValidatorInput {
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RegisterValidatorOutput {
pub guardian_threshold: u64,

pub bls_pub_key_set: String,
pub bls_pub_key: String,
pub signature: String,
Expand Down Expand Up @@ -177,7 +176,6 @@ pub async fn register_validator(input_data: &RegisterValidatorInput) -> AppResul
}

// enclave

validator_enclave_client
.attest_fresh_bls_key(&enclave_payload)
.await
Expand Down
191 changes: 191 additions & 0 deletions coral-cli/src/commands/validator/sign_vem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use axum::http::StatusCode;
use coral_lib::add_0x_prefix;
use coral_lib::error::{AppError, AppErrorKind, AppResult, ServerErrorResponse};
use coral_lib::structs::eth_types::ForkVersion;
use puffersecuresigner::client::{traits::ValidatorClientTrait, ClientBuilder};
use puffersecuresigner::eth2::eth_types::{Fork, ForkInfo, Root};
use puffersecuresigner::strip_0x_prefix;
use serde::{Deserialize, Serialize};
use std::io::Write;

#[derive(Serialize, Deserialize, Debug)]
pub struct ExitResponseOutput {
pub signature: String,
pub beacon_index: u64,
pub epoch: u64,
pub bls_pubkey: String,
}

#[derive(Clone, Debug)]
pub struct SignVoluntaryExitMessageInput {
pub bls_pubkey: String,
pub beacon_index: u64,
pub enclave_url: String,
pub fork: Fork,
pub genesis_validators_root: [u8; 32],
pub output_file: String,
}

#[allow(clippy::too_many_arguments)]
pub async fn sign_vem_from_cmd(
enclave_url: String,
bls_pubkey: String,
beacon_index: u64,
fork_current_version: String,
fork_previous_version: String,
epoch: u64,
genesis_validators_root: String,
output_file: String,
) -> AppResult<i32> {
let converted_fork_info: ForkInfo = convert_to_fork_formats(
fork_current_version,
fork_previous_version,
epoch,
genesis_validators_root,
)
.unwrap();

let input_data = SignVoluntaryExitMessageInput {
bls_pubkey,
beacon_index,
enclave_url,
fork: converted_fork_info.fork,
genesis_validators_root: converted_fork_info.genesis_validators_root,
output_file,
};
sign_voluntary_exit_message(input_data).await
}

pub async fn sign_voluntary_exit_message(
input_data: SignVoluntaryExitMessageInput,
) -> AppResult<i32> {
let enclave_url = input_data.enclave_url;

let enclave_client = ClientBuilder::new()
.validator_url(enclave_url.to_string())
.build();

let validator_enclave_client = enclave_client.validator;

let health_status = validator_enclave_client.health().await;
if !health_status {
let err = AppError::new(
AppErrorKind::EnclaveError,
"Enclave health check failed".to_string(),
);
return Err(err);
}

let bls_public_key = add_0x_prefix(&input_data.bls_pubkey);

let fork_info = ForkInfo {
fork: Fork {
previous_version: input_data.fork.previous_version,
current_version: input_data.fork.current_version,
epoch: input_data.fork.epoch,
},
genesis_validators_root: input_data.genesis_validators_root,
};

let sign_exit_resp = validator_enclave_client
.sign_voluntary_exit_message(
bls_public_key,
fork_info.fork.epoch,
input_data.beacon_index,
fork_info.clone(),
)
.await
.map_err(|err| {
let error_msg = "Failed to sign_voluntary_exit_message";
tracing::error!("{error_msg}");
tracing::error!("{err}");
ServerErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, 1000, error_msg)
})?;

let epoch = fork_info.clone().fork.epoch;
let exit_payload = ExitResponseOutput {
signature: sign_exit_resp.signature,
beacon_index: input_data.beacon_index,
epoch,
bls_pubkey: input_data.bls_pubkey,
};

let json_string_pretty = serde_json::to_string_pretty(&exit_payload)?;
println!("{}", json_string_pretty);

{
let mut file = std::fs::File::create(&input_data.output_file)?;
file.write_all(json_string_pretty.as_bytes())?;
}

Ok(0)
}

// Helper to convert from String to Fork formats
fn convert_to_fork_formats(
fork_current_version: String,
fork_previous_version: String,
epoch: u64,
genesis_validators_root: String,
) -> AppResult<ForkInfo> {
let previous_version: &str = strip_0x_prefix!(fork_previous_version.as_str());
let fork_previous_version: ForkVersion = hex::decode(previous_version)
.map_err(|_err| {
AppError::new(
AppErrorKind::DecodeError,
"fork.previous_version: Failed to decode hex".to_string(),
)
})?
.as_slice()
.try_into()
.map_err(|_err| {
AppError::new(
AppErrorKind::DecodeError,
"fork.previous_version: Invalid length".to_string(),
)
})?;
let current_version: &str = strip_0x_prefix!(fork_current_version.as_str());
let fork_current_version: ForkVersion = hex::decode(current_version)
.map_err(|_err| {
AppError::new(
AppErrorKind::DecodeError,
"fork.current_version: Failed to decode hex".to_string(),
)
})?
.as_slice()
.try_into()
.map_err(|_err| {
AppError::new(
AppErrorKind::DecodeError,
"fork.current_version: Invalid length".to_string(),
)
})?;

let genesis_validators_root: &str = strip_0x_prefix!(genesis_validators_root.as_str());
let genesis_validators_root: Root = hex::decode(genesis_validators_root)
.map_err(|_err| {
AppError::new(
AppErrorKind::DecodeError,
"genesis_validators_root: Failed to decode hex".to_string(),
)
})?
.as_slice()
.try_into()
.map_err(|_err| {
AppError::new(
AppErrorKind::DecodeError,
"fork.genesis_validators_root: Invalid length".to_string(),
)
})?;

let fork_config = ForkInfo {
fork: Fork {
current_version: fork_current_version,
previous_version: fork_previous_version,
epoch,
},
genesis_validators_root,
};

Ok(fork_config)
}
18 changes: 9 additions & 9 deletions coral-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.2"
ethers = "2.0.11"
reqwest = { version = "0.11.23", features = ["json"] }
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
tokio = { version = "1.35.1", features = ["full"] }
toml = "0.8.8"
tower-http = { version = "0.5.0", features = [ "cors", "trace" ] }
axum = "0.7.4"
ethers = "2.0.13"
reqwest = { version = "0.11.24", features = ["json"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.111"
tokio = { version = "1.36.0", features = ["full"] }
toml = "0.8.10"
tower-http = { version = "0.5.2", features = [ "cors", "trace" ] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = [ "std", "env-filter" ] }
tracing-subscriber = { version = "0.3.18", features = [ "std", "env-filter" ] }
3 changes: 0 additions & 3 deletions src/main.rs

This file was deleted.