From 803b7fdb5eb26c41e70dbe626068a375c1d8e4d7 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:10:47 +0200 Subject: [PATCH 01/16] chore: rename delegations-cli to bolt-cli --- README.md | 5 ++--- .../.env.keystore.example | 0 .../.env.local.example | 0 {bolt-delegations-cli => bolt-cli}/.gitignore | 0 {bolt-delegations-cli => bolt-cli}/Cargo.lock | 0 {bolt-delegations-cli => bolt-cli}/Cargo.toml | 2 +- {bolt-delegations-cli => bolt-cli}/README.md | 14 ++++++++++---- {bolt-delegations-cli => bolt-cli}/rustfmt.toml | 0 {bolt-delegations-cli => bolt-cli}/src/config.rs | 0 {bolt-delegations-cli => bolt-cli}/src/main.rs | 0 {bolt-delegations-cli => bolt-cli}/src/types.rs | 0 {bolt-delegations-cli => bolt-cli}/src/utils.rs | 0 .../test_data/README.md | 0 ...689873980a23c70570dfd08abc3b267003b32d2e1c015eb | 0 ...390ddfa726d1112b182af8547a8393af24116173832442f | 0 .../voting-keystore.json | 0 .../voting-keystore.json | 0 bolt-delegations-cli/delegations.json | 1 - 18 files changed, 13 insertions(+), 9 deletions(-) rename {bolt-delegations-cli => bolt-cli}/.env.keystore.example (100%) rename {bolt-delegations-cli => bolt-cli}/.env.local.example (100%) rename {bolt-delegations-cli => bolt-cli}/.gitignore (100%) rename {bolt-delegations-cli => bolt-cli}/Cargo.lock (100%) rename {bolt-delegations-cli => bolt-cli}/Cargo.toml (96%) rename {bolt-delegations-cli => bolt-cli}/README.md (91%) rename {bolt-delegations-cli => bolt-cli}/rustfmt.toml (100%) rename {bolt-delegations-cli => bolt-cli}/src/config.rs (100%) rename {bolt-delegations-cli => bolt-cli}/src/main.rs (100%) rename {bolt-delegations-cli => bolt-cli}/src/types.rs (100%) rename {bolt-delegations-cli => bolt-cli}/src/utils.rs (100%) rename {bolt-delegations-cli => bolt-cli}/test_data/README.md (100%) rename {bolt-delegations-cli => bolt-cli}/test_data/lighthouse/secrets/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb (100%) rename {bolt-delegations-cli => bolt-cli}/test_data/lighthouse/secrets/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f (100%) rename {bolt-delegations-cli => bolt-cli}/test_data/lighthouse/validators/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb/voting-keystore.json (100%) rename {bolt-delegations-cli => bolt-cli}/test_data/lighthouse/validators/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f/voting-keystore.json (100%) delete mode 100644 bolt-delegations-cli/delegations.json diff --git a/README.md b/README.md index 990e02fa..445271c7 100644 --- a/README.md +++ b/README.md @@ -111,9 +111,8 @@ In particular, the core components are: such as proposer registration and permissionless dispute resolution for attributable faults. - [**Bolt Boost**](./bolt-boost/): A [Commit-Boost][commit-boost] module that implements the Constraints-API and is compatible with the Bolt Sidecar. -- [**Bolt client**](./bolt-client/): A CLI tool to send preconfirmations on enabled test networks. -- [**Bolt Kurtosis client**](./bolt-kurtosis-client/): A CLI tool to send preconfirmations on our Kurtosis devnet. -- [**Bolt delegations CLI**](./bolt-delegations-cli/): A CLI tool to generate signed delegation and revocation messages for ETH validators. +- [**Bolt CLI**](./bolt-cli/): A CLI tool to interact with Bolt contracts, register proposers, + and submit transactions to the Bolt Sidecar. - [**Testnets**](./testnets/): A set of guides and scripts to deploy the Bolt contracts on testnets. Additionally, this repository contains the necessary scripts to spin up a [Kurtosis][kurtosis] diff --git a/bolt-delegations-cli/.env.keystore.example b/bolt-cli/.env.keystore.example similarity index 100% rename from bolt-delegations-cli/.env.keystore.example rename to bolt-cli/.env.keystore.example diff --git a/bolt-delegations-cli/.env.local.example b/bolt-cli/.env.local.example similarity index 100% rename from bolt-delegations-cli/.env.local.example rename to bolt-cli/.env.local.example diff --git a/bolt-delegations-cli/.gitignore b/bolt-cli/.gitignore similarity index 100% rename from bolt-delegations-cli/.gitignore rename to bolt-cli/.gitignore diff --git a/bolt-delegations-cli/Cargo.lock b/bolt-cli/Cargo.lock similarity index 100% rename from bolt-delegations-cli/Cargo.lock rename to bolt-cli/Cargo.lock diff --git a/bolt-delegations-cli/Cargo.toml b/bolt-cli/Cargo.toml similarity index 96% rename from bolt-delegations-cli/Cargo.toml rename to bolt-cli/Cargo.toml index 9fb05a9f..968a94ef 100644 --- a/bolt-delegations-cli/Cargo.toml +++ b/bolt-cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bolt-delegations-cli" +name = "bolt-cli" version = "0.1.0" edition = "2021" diff --git a/bolt-delegations-cli/README.md b/bolt-cli/README.md similarity index 91% rename from bolt-delegations-cli/README.md rename to bolt-cli/README.md index db588907..64098fba 100644 --- a/bolt-delegations-cli/README.md +++ b/bolt-cli/README.md @@ -1,4 +1,10 @@ -# Bolt Delegations CLI +# Bolt CLI + +Components: + +- `bolt-delegations-cli`: A command-line tool for generating delegation messages signed with a BLS12-381 key. + +## Bolt-delegations-cli `bolt-delegations-cli` is an offline command-line tool for safely generating delegation messages signed with a BLS12-381 key for the [Constraints API](https://docs.boltprotocol.xyz/api/builder) @@ -15,7 +21,7 @@ Features: - Flexible key source: Support for both direct local BLS private keys and Ethereum keystore files (ERC-2335 format). - BLS delegation signing: Sign delegation messages using a BLS secret key and output the signed delegation in JSON format. -## Usage +### Usage ```text A CLI tool to generate signed delegation messages for BLS keys @@ -31,7 +37,7 @@ Options: -V, --version Print version ``` -### Example +#### Example 1. Using a local BLS private key: @@ -64,7 +70,7 @@ flag must be used instead of `--password`, pointing to the directory containing You can find a reference Lighthouse keystore [here](./test_data/lighthouse/). -### Supported Chains +#### Supported Chains The tool supports the following chains: diff --git a/bolt-delegations-cli/rustfmt.toml b/bolt-cli/rustfmt.toml similarity index 100% rename from bolt-delegations-cli/rustfmt.toml rename to bolt-cli/rustfmt.toml diff --git a/bolt-delegations-cli/src/config.rs b/bolt-cli/src/config.rs similarity index 100% rename from bolt-delegations-cli/src/config.rs rename to bolt-cli/src/config.rs diff --git a/bolt-delegations-cli/src/main.rs b/bolt-cli/src/main.rs similarity index 100% rename from bolt-delegations-cli/src/main.rs rename to bolt-cli/src/main.rs diff --git a/bolt-delegations-cli/src/types.rs b/bolt-cli/src/types.rs similarity index 100% rename from bolt-delegations-cli/src/types.rs rename to bolt-cli/src/types.rs diff --git a/bolt-delegations-cli/src/utils.rs b/bolt-cli/src/utils.rs similarity index 100% rename from bolt-delegations-cli/src/utils.rs rename to bolt-cli/src/utils.rs diff --git a/bolt-delegations-cli/test_data/README.md b/bolt-cli/test_data/README.md similarity index 100% rename from bolt-delegations-cli/test_data/README.md rename to bolt-cli/test_data/README.md diff --git a/bolt-delegations-cli/test_data/lighthouse/secrets/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb b/bolt-cli/test_data/lighthouse/secrets/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb similarity index 100% rename from bolt-delegations-cli/test_data/lighthouse/secrets/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb rename to bolt-cli/test_data/lighthouse/secrets/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb diff --git a/bolt-delegations-cli/test_data/lighthouse/secrets/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f b/bolt-cli/test_data/lighthouse/secrets/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f similarity index 100% rename from bolt-delegations-cli/test_data/lighthouse/secrets/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f rename to bolt-cli/test_data/lighthouse/secrets/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f diff --git a/bolt-delegations-cli/test_data/lighthouse/validators/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb/voting-keystore.json b/bolt-cli/test_data/lighthouse/validators/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb/voting-keystore.json similarity index 100% rename from bolt-delegations-cli/test_data/lighthouse/validators/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb/voting-keystore.json rename to bolt-cli/test_data/lighthouse/validators/0x8a37d5942b2919e4e77f7784805146da013bd4cd0c77eee5f689873980a23c70570dfd08abc3b267003b32d2e1c015eb/voting-keystore.json diff --git a/bolt-delegations-cli/test_data/lighthouse/validators/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f/voting-keystore.json b/bolt-cli/test_data/lighthouse/validators/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f/voting-keystore.json similarity index 100% rename from bolt-delegations-cli/test_data/lighthouse/validators/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f/voting-keystore.json rename to bolt-cli/test_data/lighthouse/validators/0x8a5985a8000d845913dad7651ea42f30b71b561cf759189f3390ddfa726d1112b182af8547a8393af24116173832442f/voting-keystore.json diff --git a/bolt-delegations-cli/delegations.json b/bolt-delegations-cli/delegations.json deleted file mode 100644 index 0637a088..00000000 --- a/bolt-delegations-cli/delegations.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file From 21b7b1d8950b4943b44e4e484642a1cf53b8d1dc Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:28:54 +0200 Subject: [PATCH 02/16] feat: refactor delegation cli for modularity --- bolt-cli/Cargo.lock | 2 +- bolt-cli/src/config.rs | 4 +- bolt-cli/src/delegation.rs | 164 +++++++++++++++++ bolt-cli/src/main.rs | 174 ++----------------- bolt-cli/src/types.rs | 12 -- bolt-cli/src/{utils.rs => utils/keystore.rs} | 90 ++-------- bolt-cli/src/utils/mod.rs | 15 ++ bolt-cli/src/utils/signing.rs | 65 +++++++ bolt-cli/test_data/README.md | 2 +- 9 files changed, 276 insertions(+), 252 deletions(-) create mode 100644 bolt-cli/src/delegation.rs rename bolt-cli/src/{utils.rs => utils/keystore.rs} (55%) create mode 100644 bolt-cli/src/utils/mod.rs create mode 100644 bolt-cli/src/utils/signing.rs diff --git a/bolt-cli/Cargo.lock b/bolt-cli/Cargo.lock index 31990b74..502dd91d 100644 --- a/bolt-cli/Cargo.lock +++ b/bolt-cli/Cargo.lock @@ -1177,7 +1177,7 @@ dependencies = [ ] [[package]] -name = "bolt-delegations-cli" +name = "bolt-cli" version = "0.1.0" dependencies = [ "account_utils", diff --git a/bolt-cli/src/config.rs b/bolt-cli/src/config.rs index 5b2294fa..7609d51d 100644 --- a/bolt-cli/src/config.rs +++ b/bolt-cli/src/config.rs @@ -1,7 +1,7 @@ use clap::{Parser, Subcommand, ValueEnum}; use serde::Deserialize; -use crate::utils::KEYSTORE_PASSWORD; +use crate::utils::keystore::DEFAULT_KEYSTORE_PASSWORD; /// A CLI tool to generate signed delegation messages for BLS keys. #[derive(Parser, Debug, Clone, Deserialize)] @@ -70,7 +70,7 @@ pub enum KeySource { long, env = "KEYSTORE_PASSWORD", hide_env_values = true, - default_value = KEYSTORE_PASSWORD, + default_value = DEFAULT_KEYSTORE_PASSWORD, conflicts_with = "password_path" )] password: Option, diff --git a/bolt-cli/src/delegation.rs b/bolt-cli/src/delegation.rs new file mode 100644 index 00000000..a3e31dc1 --- /dev/null +++ b/bolt-cli/src/delegation.rs @@ -0,0 +1,164 @@ +use ethereum_consensus::crypto::{ + PublicKey as BlsPublicKey, SecretKey as BlsSecretKey, Signature as BlsSignature, +}; +use eyre::Result; +use lighthouse_eth2_keystore::Keystore; + +use crate::{ + config::{Action, Chain}, + types::{ + DelegationMessage, RevocationMessage, SignedDelegation, SignedMessage, SignedRevocation, + }, + utils::{ + keystore::{keystore_paths, KeystoreError, KeystoreSecret}, + signing::compute_commit_boost_signing_root, + }, +}; + +/// Generate signed delegations/revocations using local BLS private keys +/// +/// - Use the provided private keys from either CLI or env variable +/// - Create message +/// - Compute the signing roots and sign the messages +/// - Return the signed messages +pub fn generate_from_local_keys( + secret_keys: &Vec, + delegatee_pubkey: BlsPublicKey, + chain: &Chain, + action: Action, +) -> Result> { + let mut signed_messages = Vec::with_capacity(secret_keys.len()); + + for sk in secret_keys { + let sk = BlsSecretKey::try_from(sk.trim().to_string())?; + + match action { + Action::Delegate => { + let message = DelegationMessage::new(sk.public_key(), delegatee_pubkey.clone()); + let signing_root = compute_commit_boost_signing_root(message.digest(), chain)?; + let signature = sk.sign(signing_root.0.as_ref()); + let signed = SignedDelegation { message, signature }; + signed_messages.push(SignedMessage::Delegation(signed)) + } + Action::Revoke => { + let message = RevocationMessage::new(sk.public_key(), delegatee_pubkey.clone()); + let signing_root = compute_commit_boost_signing_root(message.digest(), chain)?; + let signature = sk.sign(signing_root.0.as_ref()); + let signed = SignedRevocation { message, signature }; + signed_messages.push(SignedMessage::Revocation(signed)); + } + } + } + + Ok(signed_messages) +} + +/// Generate signed delegations/revocations using a keystore file +/// +/// - Read the keystore file +/// - Decrypt the keypairs using the password +/// - Create messages +/// - Compute the signing roots and sign the message +/// - Return the signed message +pub fn generate_from_keystore( + keys_path: &str, + keystore_secret: KeystoreSecret, + delegatee_pubkey: BlsPublicKey, + chain: Chain, + action: Action, +) -> Result> { + let keystores_paths = keystore_paths(keys_path)?; + let mut signed_messages = Vec::with_capacity(keystores_paths.len()); + + for path in keystores_paths { + let ks = Keystore::from_json_file(path).map_err(KeystoreError::Eth2Keystore)?; + let password = keystore_secret.get(ks.pubkey()).ok_or(KeystoreError::MissingPassword)?; + let kp = ks.decrypt_keypair(password.as_bytes()).map_err(KeystoreError::Eth2Keystore)?; + let validator_pubkey = BlsPublicKey::try_from(kp.pk.serialize().to_vec().as_ref())?; + let validator_private_key = kp.sk; + + match action { + Action::Delegate => { + let message = DelegationMessage::new(validator_pubkey, delegatee_pubkey.clone()); + let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; + let signature = validator_private_key.sign(signing_root.0.into()); + let signature = BlsSignature::try_from(signature.serialize().as_ref())?; + let signed = SignedDelegation { message, signature }; + signed_messages.push(SignedMessage::Delegation(signed)); + } + Action::Revoke => { + let message = RevocationMessage::new(validator_pubkey, delegatee_pubkey.clone()); + let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; + let signature = validator_private_key.sign(signing_root.0.into()); + let signature = BlsSignature::try_from(signature.serialize().as_ref())?; + let signed = SignedRevocation { message, signature }; + signed_messages.push(SignedMessage::Revocation(signed)); + } + } + } + + Ok(signed_messages) +} + +#[cfg(test)] +mod tests { + use ethereum_consensus::crypto::PublicKey as BlsPublicKey; + + use crate::{ + config::{Action, Chain}, + types::SignedMessage, + utils::{keystore::KeystoreSecret, parse_public_key, signing::verify_commit_boost_root}, + }; + + use super::generate_from_keystore; + + #[test] + fn test_delegation_keystore_signer_lighthouse() -> eyre::Result<()> { + // Read the keystore from test_data + let keys_path = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/lighthouse/validators"; + let secrets_path = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/lighthouse/secrets"; + + let keystore_secret = KeystoreSecret::from_directory(secrets_path)?; + + let delegatee_pubkey = "0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93"; + let delegatee_pubkey = parse_public_key(delegatee_pubkey)?; + let chain = Chain::Mainnet; + + let signed_delegations = generate_from_keystore( + &keys_path, + keystore_secret, + delegatee_pubkey.clone(), + chain, + Action::Delegate, + )?; + + let signed_message = signed_delegations.first().expect("to get signed delegation"); + + verify_delegation_signature(signed_message, delegatee_pubkey, chain); + + Ok(()) + } + + fn verify_delegation_signature( + message: &SignedMessage, + delegatee_pubkey: BlsPublicKey, + chain: Chain, + ) { + match message { + SignedMessage::Delegation(signed_delegation) => { + let output_delegatee_pubkey = signed_delegation.message.delegatee_pubkey.clone(); + let signer_pubkey = signed_delegation.message.validator_pubkey.clone(); + let digest = signed_delegation.message.digest(); + assert_eq!(output_delegatee_pubkey, delegatee_pubkey); + + let blst_sig = + blst::min_pk::Signature::from_bytes(signed_delegation.signature.as_ref()) + .expect("Failed to convert delegation signature"); + + // Verify the signature + assert!(verify_commit_boost_root(signer_pubkey, digest, &blst_sig, &chain).is_ok()); + } + _ => panic!("Expected a delegation message"), + } + } +} diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index 57246220..49eff94b 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -1,24 +1,19 @@ use std::{fs, path::PathBuf}; use clap::Parser; -use ethereum_consensus::crypto::{ - PublicKey as BlsPublicKey, SecretKey as BlsSecretKey, Signature as BlsSignature, -}; use eyre::{bail, Result}; -use lighthouse_eth2_keystore::Keystore; use serde::Serialize; -pub mod config; -use config::{Action, Chain, Commands, KeySource, Opts}; +mod config; +use config::{Commands, KeySource, Opts}; -pub mod types; -use types::{ - DelegationMessage, KeystoreError, RevocationMessage, SignedDelegation, SignedMessage, - SignedRevocation, -}; +mod delegation; +use delegation::{generate_from_keystore, generate_from_local_keys}; +use utils::{keystore::KeystoreSecret, parse_public_key}; -pub mod utils; -use utils::{compute_commit_boost_signing_root, keystore_paths, parse_public_key, KeystoreSecret}; +mod types; + +mod utils; fn main() -> Result<()> { let _ = dotenvy::dotenv(); @@ -54,157 +49,10 @@ fn main() -> Result<()> { Ok(()) } -/// Generate signed delegations/revocations using local BLS private keys -/// -/// - Use the provided private keys from either CLI or env variable -/// - Create message -/// - Compute the signing roots and sign the messages -/// - Return the signed messages -fn generate_from_local_keys( - secret_keys: &Vec, - delegatee_pubkey: BlsPublicKey, - chain: &Chain, - action: Action, -) -> Result> { - let mut signed_messages = Vec::with_capacity(secret_keys.len()); - - for sk in secret_keys { - let sk = BlsSecretKey::try_from(sk.trim().to_string())?; - - match action { - Action::Delegate => { - let message = DelegationMessage::new(sk.public_key(), delegatee_pubkey.clone()); - let signing_root = compute_commit_boost_signing_root(message.digest(), chain)?; - let signature = sk.sign(signing_root.0.as_ref()); - let signed = SignedDelegation { message, signature }; - signed_messages.push(SignedMessage::Delegation(signed)) - } - Action::Revoke => { - let message = RevocationMessage::new(sk.public_key(), delegatee_pubkey.clone()); - let signing_root = compute_commit_boost_signing_root(message.digest(), chain)?; - let signature = sk.sign(signing_root.0.as_ref()); - let signed = SignedRevocation { message, signature }; - signed_messages.push(SignedMessage::Revocation(signed)); - } - } - } - - Ok(signed_messages) -} - -/// Generate signed delegations/revocations using a keystore file -/// -/// - Read the keystore file -/// - Decrypt the keypairs using the password -/// - Create messages -/// - Compute the signing roots and sign the message -/// - Return the signed message -fn generate_from_keystore( - keys_path: &str, - keystore_secret: KeystoreSecret, - delegatee_pubkey: BlsPublicKey, - chain: Chain, - action: Action, -) -> Result> { - let keystores_paths = keystore_paths(keys_path)?; - let mut signed_messages = Vec::with_capacity(keystores_paths.len()); - - for path in keystores_paths { - let ks = Keystore::from_json_file(path).map_err(KeystoreError::Eth2Keystore)?; - let password = keystore_secret.get(ks.pubkey()).ok_or(KeystoreError::MissingPassword)?; - let kp = ks.decrypt_keypair(password.as_bytes()).map_err(KeystoreError::Eth2Keystore)?; - let validator_pubkey = BlsPublicKey::try_from(kp.pk.serialize().to_vec().as_ref())?; - let validator_private_key = kp.sk; - - match action { - Action::Delegate => { - let message = DelegationMessage::new(validator_pubkey, delegatee_pubkey.clone()); - let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; - let signature = validator_private_key.sign(signing_root.0.into()); - let signature = BlsSignature::try_from(signature.serialize().as_ref())?; - let signed = SignedDelegation { message, signature }; - signed_messages.push(SignedMessage::Delegation(signed)); - } - Action::Revoke => { - let message = RevocationMessage::new(validator_pubkey, delegatee_pubkey.clone()); - let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; - let signature = validator_private_key.sign(signing_root.0.into()); - let signature = BlsSignature::try_from(signature.serialize().as_ref())?; - let signed = SignedRevocation { message, signature }; - signed_messages.push(SignedMessage::Revocation(signed)); - } - } - } - - Ok(signed_messages) -} - -/// Write the signed delegation to an output json file -fn write_to_file(out: &str, messages: &Vec) -> Result<()> { +/// Write some serializable data to an output json file +fn write_to_file(out: &str, data: &T) -> Result<()> { let out_path = PathBuf::from(out); let out_file = fs::File::create(out_path)?; - serde_json::to_writer_pretty(out_file, &messages)?; + serde_json::to_writer_pretty(out_file, data)?; Ok(()) } - -#[cfg(test)] -mod tests { - use ethereum_consensus::crypto::PublicKey as BlsPublicKey; - - use crate::{ - config::{Action, Chain}, - generate_from_keystore, - types::SignedMessage, - utils::{parse_public_key, verify_commit_boost_root, KeystoreSecret}, - }; - - #[test] - fn test_delegation_keystore_signer_lighthouse() -> eyre::Result<()> { - // Read the keystore from test_data - let keys_path = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/lighthouse/validators"; - let secrets_path = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/lighthouse/secrets"; - - let keystore_secret = KeystoreSecret::from_directory(secrets_path)?; - - let delegatee_pubkey = "0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93"; - let delegatee_pubkey = parse_public_key(delegatee_pubkey)?; - let chain = Chain::Mainnet; - - let signed_delegations = generate_from_keystore( - &keys_path, - keystore_secret, - delegatee_pubkey.clone(), - chain, - Action::Delegate, - )?; - - let signed_message = signed_delegations.first().expect("to get signed delegation"); - - verify_delegation_signature(signed_message, delegatee_pubkey, chain); - - Ok(()) - } - - fn verify_delegation_signature( - message: &SignedMessage, - delegatee_pubkey: BlsPublicKey, - chain: Chain, - ) { - match message { - SignedMessage::Delegation(signed_delegation) => { - let output_delegatee_pubkey = signed_delegation.message.delegatee_pubkey.clone(); - let signer_pubkey = signed_delegation.message.validator_pubkey.clone(); - let digest = signed_delegation.message.digest(); - assert_eq!(output_delegatee_pubkey, delegatee_pubkey); - - let blst_sig = - blst::min_pk::Signature::from_bytes(signed_delegation.signature.as_ref()) - .expect("Failed to convert delegation signature"); - - // Verify the signature - assert!(verify_commit_boost_root(signer_pubkey, digest, &blst_sig, &chain).is_ok()); - } - _ => panic!("Expected a delegation message"), - } - } -} diff --git a/bolt-cli/src/types.rs b/bolt-cli/src/types.rs index 9fa5b917..3e47fa97 100644 --- a/bolt-cli/src/types.rs +++ b/bolt-cli/src/types.rs @@ -2,18 +2,6 @@ use alloy::signers::k256::sha2::{Digest, Sha256}; use ethereum_consensus::crypto::{PublicKey as BlsPublicKey, Signature as BlsSignature}; use serde::Serialize; -#[derive(Debug, thiserror::Error)] -pub enum KeystoreError { - #[error("failed to read keystore directory: {0}")] - ReadFromDirectory(#[from] std::io::Error), - #[error("Failed to read or decrypt keystore: {0:?}")] - Eth2Keystore(lighthouse_eth2_keystore::Error), - #[error("Failed to get public key from keypair: {0}")] - UnknownPublicKey(String), - #[error("Missing password for keypair")] - MissingPassword, -} - /// Event types that can be emitted by the validator pubkey to /// signal some action on the Bolt protocol. #[derive(Debug, Clone, Copy)] diff --git a/bolt-cli/src/utils.rs b/bolt-cli/src/utils/keystore.rs similarity index 55% rename from bolt-cli/src/utils.rs rename to bolt-cli/src/utils/keystore.rs index d38c18bf..02f35cc9 100644 --- a/bolt-cli/src/utils.rs +++ b/bolt-cli/src/utils/keystore.rs @@ -1,28 +1,27 @@ use std::{ collections::HashMap, ffi::OsString, - fs::{self, read_dir, DirEntry}, + fs::{self, DirEntry}, io, path::{Path, PathBuf}, }; -use alloy::primitives::FixedBytes; -use blst::{min_pk::Signature, BLST_ERROR}; -use ethereum_consensus::{ - crypto::PublicKey as BlsPublicKey, - deneb::{compute_fork_data_root, compute_signing_root, Root}, -}; use eyre::{Context, Result}; -use crate::{config::Chain, types::KeystoreError}; - -// Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases -pub const KEYSTORE_PASSWORD: &str = r#"𝔱𝔢𝔰𝔱𝔭𝔞𝔰𝔰𝔴𝔬𝔯𝔡🔑"#; - -pub const COMMIT_BOOST_DOMAIN_MASK: [u8; 4] = [109, 109, 111, 67]; - -/// The BLS Domain Separator used in Ethereum 2.0. -pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; +/// Default password used for keystores in the test vectors. +/// +/// Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases +pub const DEFAULT_KEYSTORE_PASSWORD: &str = r#"𝔱𝔢𝔰𝔱𝔭𝔞𝔰𝔰𝔴𝔬𝔯𝔡🔑"#; + +#[derive(Debug, thiserror::Error)] +pub enum KeystoreError { + #[error("failed to read keystore directory: {0}")] + ReadFromDirectory(#[from] std::io::Error), + #[error("Failed to read or decrypt keystore: {0:?}")] + Eth2Keystore(lighthouse_eth2_keystore::Error), + #[error("Missing password for keypair")] + MissingPassword, +} pub enum KeystoreSecret { /// When using a unique password for all validators in the keystore @@ -85,13 +84,6 @@ impl Drop for KeystoreSecret { } } -/// Parse the delegated public key from a string -pub fn parse_public_key(delegatee_pubkey: &str) -> Result { - let hex_pk = delegatee_pubkey.strip_prefix("0x").unwrap_or(delegatee_pubkey); - BlsPublicKey::try_from(hex::decode(hex_pk).expect("Failed to decode pubkey").as_slice()) - .map_err(|e| eyre::eyre!("Failed to parse public key '{}': {}", hex_pk, e)) -} - /// Returns the paths of all the keystore files provided in `keys_path`. /// /// We're expecting a directory structure like: @@ -125,54 +117,6 @@ fn read_path(entry: io::Result) -> Result { Ok(entry.map_err(KeystoreError::ReadFromDirectory)?.path()) } -/// Helper function to compute the signing root for a message -pub fn compute_commit_boost_signing_root( - message: [u8; 32], - chain: &Chain, -) -> Result> { - compute_signing_root(&message, compute_domain_from_mask(chain.fork_version())) - .map_err(|e| eyre::eyre!("Failed to compute signing root: {}", e)) -} - -/// Compute the commit boost domain from the fork version -pub fn compute_domain_from_mask(fork_version: [u8; 4]) -> [u8; 32] { - let mut domain = [0; 32]; - - // Note: the application builder domain specs require the genesis_validators_root - // to be 0x00 for any out-of-protocol message. The commit-boost domain follows the - // same rule. - let root = Root::default(); - let fork_data_root = compute_fork_data_root(fork_version, root).expect("valid fork data"); - - domain[..4].copy_from_slice(&COMMIT_BOOST_DOMAIN_MASK); - domain[4..].copy_from_slice(&fork_data_root[..28]); - domain -} - -/// Verify the signature with the public key of the signer using the Commit Boost domain. -pub fn verify_commit_boost_root( - pubkey: BlsPublicKey, - root: [u8; 32], - signature: &Signature, - chain: &Chain, -) -> Result<()> { - verify_root(pubkey, root, signature, compute_domain_from_mask(chain.fork_version())) -} - -/// Verify the signature of the object with the given public key. -pub fn verify_root( - pubkey: BlsPublicKey, - root: [u8; 32], - signature: &Signature, - domain: [u8; 32], -) -> Result<()> { - let signing_root = compute_signing_root(&root, domain)?; - let pk = blst::min_pk::PublicKey::from_bytes(pubkey.as_ref()).unwrap(); - - let res = signature.verify(true, signing_root.as_ref(), BLS_DST_PREFIX, &[], &pk, true); - if res == BLST_ERROR::BLST_SUCCESS { - Ok(()) - } else { - Err(eyre::eyre!("bls verification failed")) - } +fn read_dir(path: PathBuf) -> Result { + fs::read_dir(path).wrap_err("Failed to read directory") } diff --git a/bolt-cli/src/utils/mod.rs b/bolt-cli/src/utils/mod.rs new file mode 100644 index 00000000..6fa96f1d --- /dev/null +++ b/bolt-cli/src/utils/mod.rs @@ -0,0 +1,15 @@ +use ethereum_consensus::crypto::PublicKey as BlsPublicKey; +use eyre::{Context, Result}; + +/// Utilities and types for EIP-2335 keystore files. +pub mod keystore; + +/// Utilities for signing and verifying messages. +pub mod signing; + +/// Parse a BLS public key from a string +pub fn parse_public_key(delegatee_pubkey: &str) -> Result { + let hex_pk = delegatee_pubkey.strip_prefix("0x").unwrap_or(delegatee_pubkey); + BlsPublicKey::try_from(hex::decode(hex_pk).wrap_err("Failed to hex-decode pubkey")?.as_slice()) + .map_err(|e| eyre::eyre!("Failed to parse public key '{}': {}", hex_pk, e)) +} diff --git a/bolt-cli/src/utils/signing.rs b/bolt-cli/src/utils/signing.rs new file mode 100644 index 00000000..80e898c3 --- /dev/null +++ b/bolt-cli/src/utils/signing.rs @@ -0,0 +1,65 @@ +use alloy::primitives::B256; +use blst::{min_pk::Signature, BLST_ERROR}; +use ethereum_consensus::{ + crypto::PublicKey as BlsPublicKey, + deneb::{compute_fork_data_root, compute_signing_root, Root}, +}; +use eyre::Result; + +use crate::config::Chain; + +/// The domain mask for the Commit Boost domain. +pub const COMMIT_BOOST_DOMAIN_MASK: [u8; 4] = [109, 109, 111, 67]; + +/// The BLS Domain Separator used in Ethereum 2.0. +pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + +/// Helper function to compute the signing root for a message +pub fn compute_commit_boost_signing_root(message: [u8; 32], chain: &Chain) -> Result { + compute_signing_root(&message, compute_domain_from_mask(chain.fork_version())) + .map_err(|e| eyre::eyre!("Failed to compute signing root: {}", e)) +} + +/// Compute the commit boost domain from the fork version +pub fn compute_domain_from_mask(fork_version: [u8; 4]) -> [u8; 32] { + let mut domain = [0; 32]; + + // Note: the application builder domain specs require the genesis_validators_root + // to be 0x00 for any out-of-protocol message. The commit-boost domain follows the + // same rule. + let root = Root::default(); + let fork_data_root = compute_fork_data_root(fork_version, root).expect("valid fork data"); + + domain[..4].copy_from_slice(&COMMIT_BOOST_DOMAIN_MASK); + domain[4..].copy_from_slice(&fork_data_root[..28]); + domain +} + +/// Verify the signature with the public key of the signer using the Commit Boost domain. +#[allow(dead_code)] +pub fn verify_commit_boost_root( + pubkey: BlsPublicKey, + root: [u8; 32], + signature: &Signature, + chain: &Chain, +) -> Result<()> { + verify_root(pubkey, root, signature, compute_domain_from_mask(chain.fork_version())) +} + +/// Verify the signature of the object with the given public key. +pub fn verify_root( + pubkey: BlsPublicKey, + root: [u8; 32], + signature: &Signature, + domain: [u8; 32], +) -> Result<()> { + let signing_root = compute_signing_root(&root, domain)?; + let pk = blst::min_pk::PublicKey::from_bytes(pubkey.as_ref()).unwrap(); + + let res = signature.verify(true, signing_root.as_ref(), BLS_DST_PREFIX, &[], &pk, true); + if res == BLST_ERROR::BLST_SUCCESS { + Ok(()) + } else { + Err(eyre::eyre!("bls verification failed")) + } +} diff --git a/bolt-cli/test_data/README.md b/bolt-cli/test_data/README.md index 7aa1be7f..fc94ba75 100644 --- a/bolt-cli/test_data/README.md +++ b/bolt-cli/test_data/README.md @@ -1,4 +1,4 @@ -# test data for the delegation cli tool +# test data for the bolt cli tool - `lighthouse`: A lighthouse-format keystore according to the [specs][lh-specs]. It contains two directories: `validators` for the voting-keystores, and `secrets` for the passwords From eb21c4b9ba80c7ca01844d3b381daa01c68756fa Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:49:33 +0200 Subject: [PATCH 03/16] chore: refactor --- bolt-cli/src/{config.rs => cli.rs} | 4 +- bolt-cli/src/delegation.rs | 110 ++++++++++++++++++++++++++--- bolt-cli/src/main.rs | 26 ++----- bolt-cli/src/types.rs | 96 ------------------------- bolt-cli/src/utils/mod.rs | 13 +++- bolt-cli/src/utils/signing.rs | 2 +- 6 files changed, 123 insertions(+), 128 deletions(-) rename bolt-cli/src/{config.rs => cli.rs} (97%) delete mode 100644 bolt-cli/src/types.rs diff --git a/bolt-cli/src/config.rs b/bolt-cli/src/cli.rs similarity index 97% rename from bolt-cli/src/config.rs rename to bolt-cli/src/cli.rs index 7609d51d..4d71ee79 100644 --- a/bolt-cli/src/config.rs +++ b/bolt-cli/src/cli.rs @@ -14,8 +14,8 @@ pub struct Opts { #[derive(Subcommand, Debug, Clone, Deserialize)] pub enum Commands { - /// Generate delegation messages. - Generate { + /// Generate BLS delegation or revocation messages. + Delegate { /// The BLS public key to which the delegation message should be signed. #[clap(long, env = "DELEGATEE_PUBKEY")] delegatee_pubkey: String, diff --git a/bolt-cli/src/delegation.rs b/bolt-cli/src/delegation.rs index a3e31dc1..b83a4c87 100644 --- a/bolt-cli/src/delegation.rs +++ b/bolt-cli/src/delegation.rs @@ -1,14 +1,13 @@ +use alloy::signers::k256::sha2::{Digest, Sha256}; use ethereum_consensus::crypto::{ PublicKey as BlsPublicKey, SecretKey as BlsSecretKey, Signature as BlsSignature, }; use eyre::Result; use lighthouse_eth2_keystore::Keystore; +use serde::Serialize; use crate::{ - config::{Action, Chain}, - types::{ - DelegationMessage, RevocationMessage, SignedDelegation, SignedMessage, SignedRevocation, - }, + cli::{Action, Chain}, utils::{ keystore::{keystore_paths, KeystoreError, KeystoreSecret}, signing::compute_commit_boost_signing_root, @@ -100,17 +99,110 @@ pub fn generate_from_keystore( Ok(signed_messages) } +/// Event types that can be emitted by the validator pubkey to +/// signal some action on the Bolt protocol. +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +enum SignedMessageAction { + /// Signal delegation of a validator pubkey to a delegatee pubkey. + Delegation, + /// Signal revocation of a previously delegated pubkey. + Revocation, +} + +/// Transparent serialization of signed messages. +/// This is used to serialize and deserialize signed messages +/// +/// e.g. serde_json::to_string(&signed_message): +/// ``` +/// { +/// "message": { +/// "action": 0, +/// "validator_pubkey": "0x...", +/// "delegatee_pubkey": "0x..." +/// }, +/// "signature": "0x..." +/// }, +/// ``` +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] +#[serde(untagged)] +pub enum SignedMessage { + Delegation(SignedDelegation), + Revocation(SignedRevocation), +} + +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] +pub struct SignedDelegation { + pub message: DelegationMessage, + pub signature: BlsSignature, +} + +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] +pub struct DelegationMessage { + action: u8, + pub validator_pubkey: BlsPublicKey, + pub delegatee_pubkey: BlsPublicKey, +} + +impl DelegationMessage { + /// Create a new delegation message. + pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { + Self { action: SignedMessageAction::Delegation as u8, validator_pubkey, delegatee_pubkey } + } + + /// Compute the digest of the delegation message. + pub fn digest(&self) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update([self.action]); + hasher.update(self.validator_pubkey.to_vec()); + hasher.update(self.delegatee_pubkey.to_vec()); + + hasher.finalize().into() + } +} + +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] +pub struct SignedRevocation { + pub message: RevocationMessage, + pub signature: BlsSignature, +} + +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] +pub struct RevocationMessage { + action: u8, + pub validator_pubkey: BlsPublicKey, + pub delegatee_pubkey: BlsPublicKey, +} + +impl RevocationMessage { + /// Create a new revocation message. + pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { + Self { action: SignedMessageAction::Revocation as u8, validator_pubkey, delegatee_pubkey } + } + + /// Compute the digest of the revocation message. + pub fn digest(&self) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update([self.action]); + hasher.update(self.validator_pubkey.to_vec()); + hasher.update(self.delegatee_pubkey.to_vec()); + + hasher.finalize().into() + } +} + #[cfg(test)] mod tests { use ethereum_consensus::crypto::PublicKey as BlsPublicKey; use crate::{ - config::{Action, Chain}, - types::SignedMessage, - utils::{keystore::KeystoreSecret, parse_public_key, signing::verify_commit_boost_root}, + cli::{Action, Chain}, + utils::{ + keystore::KeystoreSecret, parse_bls_public_key, signing::verify_commit_boost_root, + }, }; - use super::generate_from_keystore; + use super::{generate_from_keystore, SignedMessage}; #[test] fn test_delegation_keystore_signer_lighthouse() -> eyre::Result<()> { @@ -121,7 +213,7 @@ mod tests { let keystore_secret = KeystoreSecret::from_directory(secrets_path)?; let delegatee_pubkey = "0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93"; - let delegatee_pubkey = parse_public_key(delegatee_pubkey)?; + let delegatee_pubkey = parse_bls_public_key(delegatee_pubkey)?; let chain = Chain::Mainnet; let signed_delegations = generate_from_keystore( diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index 49eff94b..d4ef0a72 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -1,19 +1,14 @@ -use std::{fs, path::PathBuf}; - use clap::Parser; use eyre::{bail, Result}; -use serde::Serialize; -mod config; -use config::{Commands, KeySource, Opts}; +mod cli; +use cli::{Commands, KeySource, Opts}; mod delegation; use delegation::{generate_from_keystore, generate_from_local_keys}; -use utils::{keystore::KeystoreSecret, parse_public_key}; - -mod types; mod utils; +use utils::{keystore::KeystoreSecret, parse_bls_public_key, write_to_file}; fn main() -> Result<()> { let _ = dotenvy::dotenv(); @@ -21,9 +16,9 @@ fn main() -> Result<()> { let cli = Opts::parse(); match cli.command { - Commands::Generate { delegatee_pubkey, out, chain, source, action } => match source { + Commands::Delegate { delegatee_pubkey, out, chain, source, action } => match source { KeySource::Local { secret_keys } => { - let delegatee = parse_public_key(&delegatee_pubkey)?; + let delegatee = parse_bls_public_key(&delegatee_pubkey)?; let messages = generate_from_local_keys(&secret_keys, delegatee, &chain, action)?; write_to_file(&out, &messages)?; @@ -35,10 +30,11 @@ fn main() -> Result<()> { } else if let Some(password) = password { KeystoreSecret::from_unique_password(password) } else { + // This case is prevented upstream by clap's validation. bail!("Either `password_path` or `password` must be provided") }; - let delegatee = parse_public_key(&delegatee_pubkey)?; + let delegatee = parse_bls_public_key(&delegatee_pubkey)?; let messages = generate_from_keystore(&path, passwords, delegatee, chain, action)?; write_to_file(&out, &messages)?; @@ -48,11 +44,3 @@ fn main() -> Result<()> { } Ok(()) } - -/// Write some serializable data to an output json file -fn write_to_file(out: &str, data: &T) -> Result<()> { - let out_path = PathBuf::from(out); - let out_file = fs::File::create(out_path)?; - serde_json::to_writer_pretty(out_file, data)?; - Ok(()) -} diff --git a/bolt-cli/src/types.rs b/bolt-cli/src/types.rs deleted file mode 100644 index 3e47fa97..00000000 --- a/bolt-cli/src/types.rs +++ /dev/null @@ -1,96 +0,0 @@ -use alloy::signers::k256::sha2::{Digest, Sha256}; -use ethereum_consensus::crypto::{PublicKey as BlsPublicKey, Signature as BlsSignature}; -use serde::Serialize; - -/// Event types that can be emitted by the validator pubkey to -/// signal some action on the Bolt protocol. -#[derive(Debug, Clone, Copy)] -#[repr(u8)] -#[allow(dead_code)] -enum SignedMessageAction { - /// Signal delegation of a validator pubkey to a delegatee pubkey. - Delegation, - /// Signal revocation of a previously delegated pubkey. - Revocation, -} - -/// Transparent serialization of signed messages. -/// This is used to serialize and deserialize signed messages -/// -/// e.g. serde_json::to_string(&signed_message): -/// ``` -/// { -/// "message": { -/// "action": 0, -/// "validator_pubkey": "0x...", -/// "delegatee_pubkey": "0x..." -/// }, -/// "signature": "0x..." -/// }, -/// ``` -#[derive(Debug, Clone, Serialize, PartialEq, Eq)] -#[serde(untagged)] -pub enum SignedMessage { - Delegation(SignedDelegation), - Revocation(SignedRevocation), -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq)] -pub struct SignedDelegation { - pub message: DelegationMessage, - pub signature: BlsSignature, -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq)] -pub struct DelegationMessage { - action: u8, - pub validator_pubkey: BlsPublicKey, - pub delegatee_pubkey: BlsPublicKey, -} - -impl DelegationMessage { - /// Create a new delegation message. - pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { - Self { action: SignedMessageAction::Delegation as u8, validator_pubkey, delegatee_pubkey } - } - - /// Compute the digest of the delegation message. - pub fn digest(&self) -> [u8; 32] { - let mut hasher = Sha256::new(); - hasher.update([self.action]); - hasher.update(self.validator_pubkey.to_vec()); - hasher.update(self.delegatee_pubkey.to_vec()); - - hasher.finalize().into() - } -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq)] -pub struct SignedRevocation { - pub message: RevocationMessage, - pub signature: BlsSignature, -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq)] -pub struct RevocationMessage { - action: u8, - pub validator_pubkey: BlsPublicKey, - pub delegatee_pubkey: BlsPublicKey, -} - -impl RevocationMessage { - /// Create a new revocation message. - pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { - Self { action: SignedMessageAction::Revocation as u8, validator_pubkey, delegatee_pubkey } - } - - /// Compute the digest of the revocation message. - pub fn digest(&self) -> [u8; 32] { - let mut hasher = Sha256::new(); - hasher.update([self.action]); - hasher.update(self.validator_pubkey.to_vec()); - hasher.update(self.delegatee_pubkey.to_vec()); - - hasher.finalize().into() - } -} diff --git a/bolt-cli/src/utils/mod.rs b/bolt-cli/src/utils/mod.rs index 6fa96f1d..e90260c5 100644 --- a/bolt-cli/src/utils/mod.rs +++ b/bolt-cli/src/utils/mod.rs @@ -1,5 +1,8 @@ +use std::{fs, path::PathBuf}; + use ethereum_consensus::crypto::PublicKey as BlsPublicKey; use eyre::{Context, Result}; +use serde::Serialize; /// Utilities and types for EIP-2335 keystore files. pub mod keystore; @@ -8,8 +11,16 @@ pub mod keystore; pub mod signing; /// Parse a BLS public key from a string -pub fn parse_public_key(delegatee_pubkey: &str) -> Result { +pub fn parse_bls_public_key(delegatee_pubkey: &str) -> Result { let hex_pk = delegatee_pubkey.strip_prefix("0x").unwrap_or(delegatee_pubkey); BlsPublicKey::try_from(hex::decode(hex_pk).wrap_err("Failed to hex-decode pubkey")?.as_slice()) .map_err(|e| eyre::eyre!("Failed to parse public key '{}': {}", hex_pk, e)) } + +/// Write some serializable data to an output json file +pub fn write_to_file(out: &str, data: &T) -> Result<()> { + let out_path = PathBuf::from(out); + let out_file = fs::File::create(out_path)?; + serde_json::to_writer_pretty(out_file, data)?; + Ok(()) +} diff --git a/bolt-cli/src/utils/signing.rs b/bolt-cli/src/utils/signing.rs index 80e898c3..dd84e787 100644 --- a/bolt-cli/src/utils/signing.rs +++ b/bolt-cli/src/utils/signing.rs @@ -6,7 +6,7 @@ use ethereum_consensus::{ }; use eyre::Result; -use crate::config::Chain; +use crate::cli::Chain; /// The domain mask for the Commit Boost domain. pub const COMMIT_BOOST_DOMAIN_MASK: [u8; 4] = [109, 109, 111, 67]; From 753826fa41fa7e630fbd8ff8d0326cdff7ad5787 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Tue, 22 Oct 2024 17:25:46 +0200 Subject: [PATCH 04/16] wip: added proto definitions --- bolt-cli/Cargo.lock | 151 +- bolt-cli/Cargo.toml | 6 +- bolt-cli/build.rs | 7 + bolt-cli/proto/README.md | 7 + .../eth2-signer-api/accountmanager.proto | 65 + bolt-cli/proto/eth2-signer-api/dkg.proto | 70 + bolt-cli/proto/eth2-signer-api/endpoint.proto | 16 + bolt-cli/proto/eth2-signer-api/eth2.proto | 34 + .../google/api/annotations.proto | 31 + .../eth2-signer-api/google/api/http.proto | 318 ++++ .../google/protobuf/descriptor.proto | 1293 +++++++++++++++++ bolt-cli/proto/eth2-signer-api/lister.proto | 47 + .../proto/eth2-signer-api/responsestate.proto | 21 + bolt-cli/proto/eth2-signer-api/signer.proto | 86 ++ .../proto/eth2-signer-api/walletmanager.proto | 43 + bolt-cli/src/cli.rs | 63 +- bolt-cli/src/main.rs | 32 +- 17 files changed, 2227 insertions(+), 63 deletions(-) create mode 100644 bolt-cli/build.rs create mode 100644 bolt-cli/proto/README.md create mode 100644 bolt-cli/proto/eth2-signer-api/accountmanager.proto create mode 100644 bolt-cli/proto/eth2-signer-api/dkg.proto create mode 100644 bolt-cli/proto/eth2-signer-api/endpoint.proto create mode 100644 bolt-cli/proto/eth2-signer-api/eth2.proto create mode 100644 bolt-cli/proto/eth2-signer-api/google/api/annotations.proto create mode 100644 bolt-cli/proto/eth2-signer-api/google/api/http.proto create mode 100644 bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto create mode 100644 bolt-cli/proto/eth2-signer-api/lister.proto create mode 100644 bolt-cli/proto/eth2-signer-api/responsestate.proto create mode 100644 bolt-cli/proto/eth2-signer-api/signer.proto create mode 100644 bolt-cli/proto/eth2-signer-api/walletmanager.proto diff --git a/bolt-cli/Cargo.lock b/bolt-cli/Cargo.lock index 502dd91d..8c55be52 100644 --- a/bolt-cli/Cargo.lock +++ b/bolt-cli/Cargo.lock @@ -418,7 +418,7 @@ checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -577,7 +577,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -594,7 +594,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "syn-solidity", "tiny-keccak", ] @@ -612,7 +612,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.79", + "syn 2.0.82", "syn-solidity", ] @@ -965,7 +965,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -976,7 +976,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -998,7 +998,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1189,6 +1189,8 @@ dependencies = [ "ethereum-consensus", "eyre", "hex", + "prost", + "prost-build", "serde", "serde_json", "tempfile", @@ -1368,7 +1370,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1627,7 +1629,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1675,7 +1677,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1697,7 +1699,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1819,7 +1821,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1832,7 +1834,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1852,7 +1854,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "unicode-xid", ] @@ -2487,6 +2489,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.34" @@ -2612,7 +2620,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -3862,6 +3870,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "multistream-select" version = "0.13.0" @@ -3994,7 +4008,7 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4041,7 +4055,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4243,6 +4257,16 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.6.0", +] + [[package]] name = "pharos" version = "0.5.3" @@ -4270,7 +4294,7 @@ checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -4347,6 +4371,16 @@ dependencies = [ "sensitive_url", ] +[[package]] +name = "prettyplease" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "910d41a655dac3b764f1ade94821093d3610248694320cd072303a8eedcf221d" +dependencies = [ + "proc-macro2", + "syn 2.0.82", +] + [[package]] name = "primitive-types" version = "0.10.1" @@ -4460,6 +4494,59 @@ dependencies = [ "unarray", ] +[[package]] +name = "prost" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +dependencies = [ + "bytes", + "heck", + "itertools 0.13.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.82", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +dependencies = [ + "anyhow", + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.82", +] + +[[package]] +name = "prost-types" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +dependencies = [ + "prost", +] + [[package]] name = "protobuf" version = "2.28.0" @@ -5168,7 +5255,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5191,7 +5278,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5233,7 +5320,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5636,7 +5723,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5681,9 +5768,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -5699,7 +5786,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5822,7 +5909,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -5944,7 +6031,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6105,7 +6192,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6498,7 +6585,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-shared", ] @@ -6532,7 +6619,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6904,7 +6991,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -6924,7 +7011,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] diff --git a/bolt-cli/Cargo.toml b/bolt-cli/Cargo.toml index 968a94ef..bc7de173 100644 --- a/bolt-cli/Cargo.toml +++ b/bolt-cli/Cargo.toml @@ -15,6 +15,7 @@ alloy = { version = "0.2.0", features = [ "rpc-types-engine", ] } blst = "0.3.12" +prost = "0.13.3" # utils dotenvy = "0.15.7" @@ -27,4 +28,7 @@ lighthouse_eth2_keystore = { package = "eth2_keystore", git = "https://github.co lighthouse_account_utils = { package = "account_utils", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } [dev-dependencies] -tempfile = "3.13.0" \ No newline at end of file +tempfile = "3.13.0" + +[build-dependencies] +prost-build = "0.13.3" diff --git a/bolt-cli/build.rs b/bolt-cli/build.rs new file mode 100644 index 00000000..8fd98951 --- /dev/null +++ b/bolt-cli/build.rs @@ -0,0 +1,7 @@ +// Perform the code generation for the protobuf files. +fn main() -> std::io::Result<()> { + let mut proto_build = prost_build::Config::new(); + + proto_build.out_dir("src/pb"); + proto_build.compile_protos(&["proto/eth2-signer-api/lister.proto"], &["proto/eth2-signer-api"]) +} diff --git a/bolt-cli/proto/README.md b/bolt-cli/proto/README.md new file mode 100644 index 00000000..450eae72 --- /dev/null +++ b/bolt-cli/proto/README.md @@ -0,0 +1,7 @@ +# Protobuf definitions + +## Eth2 signer API + +The definitions in this folder are taken from the [eth2-signer-api][eth2-signer-api] package. + +[eth2-signer-api]: https://github.com/wealdtech/eth2-signer-api/tree/4aaf36e54f4e62d0cf4edc1b794e9a6354cf4f95/pb/v1 diff --git a/bolt-cli/proto/eth2-signer-api/accountmanager.proto b/bolt-cli/proto/eth2-signer-api/accountmanager.proto new file mode 100644 index 00000000..6ca3abb8 --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/accountmanager.proto @@ -0,0 +1,65 @@ +syntax = "proto3"; + +package v1; + +import "google/api/annotations.proto"; +import "responsestate.proto"; +import "endpoint.proto"; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option java_multiple_files = true; +option java_outer_classname = "AccountManagerProto"; + +service AccountManager { + rpc Unlock(UnlockAccountRequest) returns (UnlockAccountResponse) { + option (google.api.http) = { + get: "/v1/accountmanager/unlock" + }; + } + + rpc Lock(LockAccountRequest) returns (LockAccountResponse) { + option (google.api.http) = { + get: "/v1/accountmanager/lock" + }; + } + + rpc Generate(GenerateRequest) returns (GenerateResponse) { + option (google.api.http) = { + post: "/v1/accountmanager/generate" + }; + } +} + +message UnlockAccountRequest { + string account = 1; + bytes passphrase = 2; +} + +message LockAccountRequest { + string account = 1; +} + +message UnlockAccountResponse { + ResponseState state = 1; +} + +message LockAccountResponse { + ResponseState state = 1; +} + +message GenerateRequest { + string account = 1; + bytes passphrase = 2; + uint32 participants = 3; + uint32 signing_threshold = 4; +} + +message GenerateResponse { + ResponseState state = 1; + string message = 2; + bytes public_key = 3; + repeated Endpoint participants = 4; +} diff --git a/bolt-cli/proto/eth2-signer-api/dkg.proto b/bolt-cli/proto/eth2-signer-api/dkg.proto new file mode 100644 index 00000000..e335a4b7 --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/dkg.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; + +package v1; + +import "google/protobuf/empty.proto"; +import "endpoint.proto"; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option java_multiple_files = true; +option java_outer_classname = "DKGProto"; + +// DKG is the internal protocol that runs between distributed key generators. +service DKG { + rpc Prepare(PrepareRequest) returns (google.protobuf.Empty) { } + rpc Execute(ExecuteRequest) returns (google.protobuf.Empty) { } + rpc Commit(CommitRequest) returns (CommitResponse) { } + rpc Abort(AbortRequest) returns (google.protobuf.Empty) { } + rpc Contribute(ContributeRequest) returns (ContributeResponse) { } +} + +message PrepareRequest { + // account is the name of the account. + string account = 1; + // threshold is the number of participants required to generate a valid signature. + uint32 threshold = 2; + // participants contains the endpoints of all participants. + repeated Endpoint participants = 3; + // passphrase is the passphrase of the account. + bytes passphrase = 4; +} + +message ExecuteRequest { + // account is the name of the account. + string account = 1; +} + +message CommitRequest { + // account is the name of the account. + string account = 1; + // confirmation data is data used to generate the confirmation signature. + bytes confirmation_data = 2; +} + +message CommitResponse { + // public_key is the key generated by the process. + bytes public_key = 1; + // confirmation_signature is the signature generated by the individual secret key. + bytes confirmation_signature = 2; +} + +message AbortRequest { + // account is the name of the account. + string account = 1; +} + +// ContributeRequest is sent by each part to all other parties with a contribution. +message ContributeRequest { + string account = 1; + bytes secret = 2; + repeated bytes verification_vector = 3; +} + +// ContributeResponse receives the contribution from a participant. +message ContributeResponse { + bytes secret = 1; + repeated bytes verification_vector = 2; +} diff --git a/bolt-cli/proto/eth2-signer-api/endpoint.proto b/bolt-cli/proto/eth2-signer-api/endpoint.proto new file mode 100644 index 00000000..e61f84ae --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/endpoint.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package v1; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option java_multiple_files = true; +option java_outer_classname = "EndpointProto"; + +message Endpoint { + uint64 id = 1; + string name = 2; + uint32 port = 3; +} diff --git a/bolt-cli/proto/eth2-signer-api/eth2.proto b/bolt-cli/proto/eth2-signer-api/eth2.proto new file mode 100644 index 00000000..615ba814 --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/eth2.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package v1; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option java_multiple_files = true; +option java_outer_classname = "Eth2Proto"; + +// AttestationData is defined at https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#attestationdata +message AttestationData { + uint64 slot = 1; + uint64 committee_index = 2; + bytes beacon_block_root = 3; + Checkpoint source = 4; + Checkpoint target = 5; +} + +// Checkpoint is defined at https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#checkpoint +message Checkpoint { + uint64 epoch = 1; + bytes root = 2; +} + +// BeaconBlockheader is defined at https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader +message BeaconBlockHeader { + uint64 slot = 1; + uint64 proposer_index = 2; + bytes parent_root = 3; + bytes state_root = 4; + bytes body_root = 5; +} diff --git a/bolt-cli/proto/eth2-signer-api/google/api/annotations.proto b/bolt-cli/proto/eth2-signer-api/google/api/annotations.proto new file mode 100644 index 00000000..85c361b4 --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright (c) 2015, Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/bolt-cli/proto/eth2-signer-api/google/api/http.proto b/bolt-cli/proto/eth2-signer-api/google/api/http.proto new file mode 100644 index 00000000..2bd3a19b --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/google/api/http.proto @@ -0,0 +1,318 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parmeters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// `HttpRule` defines the mapping of an RPC method to one or more HTTP +// REST API methods. The mapping specifies how different portions of the RPC +// request message are mapped to URL path, URL query parameters, and +// HTTP request body. The mapping is typically specified as an +// `google.api.http` annotation on the RPC method, +// see "google/api/annotations.proto" for details. +// +// The mapping consists of a field specifying the path template and +// method kind. The path template can refer to fields in the request +// message, as in the example below which describes a REST GET +// operation on a resource collection of messages: +// +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // mapped to the URL +// SubMessage sub = 2; // `sub.subfield` is url-mapped +// } +// message Message { +// string text = 1; // content of the resource +// } +// +// The same http annotation can alternatively be expressed inside the +// `GRPC API Configuration` YAML file. +// +// http: +// rules: +// - selector: .Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// This definition enables an automatic, bidrectional mapping of HTTP +// JSON to RPC. Example: +// +// HTTP | RPC +// -----|----- +// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` +// +// In general, not only fields but also field paths can be referenced +// from a path pattern. Fields mapped to the path pattern cannot be +// repeated and must have a primitive (non-message) type. +// +// Any fields in the request message which are not bound by the path +// pattern automatically become (optional) HTTP query +// parameters. Assume the following definition of the request message: +// +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http).get = "/v1/messages/{message_id}"; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // mapped to the URL +// int64 revision = 2; // becomes a parameter +// SubMessage sub = 3; // `sub.subfield` becomes a parameter +// } +// +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | RPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` +// +// Note that fields which are mapped to HTTP parameters must have a +// primitive type or a repeated primitive type. Message types are not +// allowed. In the case of a repeated type, the parameter can be +// repeated in the URL, as in `...?param=A¶m=B`. +// +// For HTTP method kinds which allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// put: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | RPC +// -----|----- +// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// put: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | RPC +// -----|----- +// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice of +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// +// This enables the following two alternative HTTP JSON to RPC +// mappings: +// +// HTTP | RPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` +// +// # Rules for HTTP mapping +// +// The rules for mapping HTTP path, query parameters, and body fields +// to the request message are as follows: +// +// 1. The `body` field specifies either `*` or a field path, or is +// omitted. If omitted, it indicates there is no HTTP request body. +// 2. Leaf fields (recursive expansion of nested messages in the +// request) can be classified into three types: +// (a) Matched in the URL template. +// (b) Covered by body (if body is `*`, everything except (a) fields; +// else everything under the body field) +// (c) All other fields. +// 3. URL query parameters found in the HTTP request are mapped to (c) fields. +// 4. Any body sent with an HTTP request can contain only (b) fields. +// +// The syntax of the path template is as follows: +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single path segment. The syntax `**` matches zero +// or more path segments, which must be the last part of the path except the +// `Verb`. The syntax `LITERAL` matches literal text in the path. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path, all characters +// except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the +// Discovery Document as `{var}`. +// +// If a variable contains one or more path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path, all +// characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables +// show up in the Discovery Document as `{+var}`. +// +// NOTE: While the single segment variable matches the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 +// Simple String Expansion, the multi segment variable **does not** match +// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. +// +// NOTE: the field paths in variables and in the `body` must not refer to +// repeated fields or map fields. +message HttpRule { + // Selects methods to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Used for listing and getting information about resources. + string get = 2; + + // Used for updating a resource. + string put = 3; + + // Used for creating a resource. + string post = 4; + + // Used for deleting a resource. + string delete = 5; + + // Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP body, or + // `*` for mapping all fields not captured by the path pattern to the HTTP + // body. NOTE: the referred field must not be a repeated field and must be + // present at the top-level of request message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // body of response. Other response fields are ignored. When + // not set, the response message will be used as HTTP body of response. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} diff --git a/bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto b/bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto new file mode 100644 index 00000000..196fb21b --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto @@ -0,0 +1,1293 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + +syntax = "proto2"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; +option csharp_namespace = "Google.Protobuf.Reflection"; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// The full set of known editions. +enum Edition { + // A placeholder for an unknown edition value. + EDITION_UNKNOWN = 0; + + // A placeholder edition for specifying default behaviors *before* a feature + // was first introduced. This is effectively an "infinite past". + EDITION_LEGACY = 900; + + // Legacy syntax "editions". These pre-date editions, but behave much like + // distinct editions. These can't be used to specify the edition of proto + // files, but feature definitions must supply proto2/proto3 defaults for + // backwards compatibility. + EDITION_PROTO2 = 998; + EDITION_PROTO3 = 999; + + // Editions that have been released. The specific values are arbitrary and + // should not be depended on, but they will always be time-ordered for easy + // comparison. + EDITION_2023 = 1000; + EDITION_2024 = 1001; + + // Placeholder editions for testing feature resolution. These should not be + // used or relied on outside of tests. + EDITION_1_TEST_ONLY = 1; + EDITION_2_TEST_ONLY = 2; + EDITION_99997_TEST_ONLY = 99997; + EDITION_99998_TEST_ONLY = 99998; + EDITION_99999_TEST_ONLY = 99999; + + // Placeholder for specifying unbounded edition support. This should only + // ever be used by plugins that can expect to never require any changes to + // support a new edition. + EDITION_MAX = 0x7FFFFFFF; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2", "proto3", and "editions". + // + // If `edition` is present, this value must be "editions". + optional string syntax = 12; + + // The edition of the proto file. + optional Edition edition = 14; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + + optional ExtensionRangeOptions options = 3; + } + repeated ExtensionRange extension_range = 5; + + repeated OneofDescriptorProto oneof_decl = 8; + + optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; +} + +message ExtensionRangeOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + message Declaration { + // The extension number declared within the extension range. + optional int32 number = 1; + + // The fully-qualified name of the extension field. There must be a leading + // dot in front of the full name. + optional string full_name = 2; + + // The fully-qualified type name of the extension field. Unlike + // Metadata.type, Declaration.type must have a leading dot for messages + // and enums. + optional string type = 3; + + // If true, indicates that the number is reserved in the extension range, + // and any extension field with the number will fail to compile. Set this + // when a declared extension field is deleted. + optional bool reserved = 5; + + // If true, indicates that the extension must be defined as repeated. + // Otherwise the extension must be defined as optional. + optional bool repeated = 6; + + reserved 4; // removed is_repeated + } + + // For external users: DO NOT USE. We are in the process of open sourcing + // extension declaration and executing internal cleanups before it can be + // used externally. + repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; + + // Any features defined in the specific edition. + optional FeatureSet features = 50; + + // The verification state of the extension range. + enum VerificationState { + // All the extensions of the range must be declared. + DECLARATION = 0; + UNVERIFIED = 1; + } + + // The verification state of the range. + // TODO: flip the default to DECLARATION once all empty ranges + // are marked as UNVERIFIED. + optional VerificationState verification = 3 + [default = UNVERIFIED, retention = RETENTION_SOURCE]; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + // Tag-delimited aggregate. + // Group type is deprecated and not supported after google.protobuf. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. In Editions, the group wire format + // can be enabled via the `message_encoding` feature. + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + } + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REPEATED = 3; + // The required label is only allowed in google.protobuf. In proto3 and Editions + // it's explicitly prohibited. In Editions, the `field_presence` feature + // can be used to get this behavior. + LABEL_REQUIRED = 2; + } + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; + + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must belong to a oneof to signal + // to old proto3 clients that presence is tracked for this field. This oneof + // is known as a "synthetic" oneof, and this field must be its sole member + // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs + // exist in the descriptor only, and do not generate any API. Synthetic oneofs + // must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + optional bool proto3_optional = 17; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default = false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default = false]; +} + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + // Controls the name of the wrapper Java class generated for the .proto file. + // That class will always contain the .proto file's getDescriptor() method as + // well as any top-level extensions defined in the .proto file. + // If java_multiple_files is disabled, then all the other classes from the + // .proto file will be nested inside the single wrapper outer class. + optional string java_outer_classname = 8; + + // If enabled, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the wrapper class + // named by java_outer_classname. However, the wrapper class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default = false]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // A proto2 file can set this to true to opt in to UTF-8 checking for Java, + // which will throw an exception if invalid UTF-8 is parsed from the wire or + // assigned to a string field. + // + // TODO: clarify exactly what kinds of field types this option + // applies to, and update these docs accordingly. + // + // Proto3 files already perform these checks. Setting the option explicitly to + // false has no effect: it cannot be used to opt proto3 files out of UTF-8 + // checks. + optional bool java_string_check_utf8 = 27 [default = false]; + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default = SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + reserved 42; // removed php_generic_services + reserved "php_generic_services"; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default = false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default = true]; + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be + // used for determining the namespace. + optional string php_metadata_namespace = 44; + + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + optional string ruby_package = 45; + + // Any features defined in the specific edition. + optional FeatureSet features = 50; + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default = false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default = false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default = false]; + + reserved 4, 5, 6; + + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementations still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // + // This should only be used as a temporary measure against broken builds due + // to the change in behavior for JSON field name conflicts. + // + // TODO This is legacy behavior we plan to remove once downstream + // teams have had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 12; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is only implemented to support use of + // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of + // type "bytes" in the open source release. + // TODO: make ctype actually deprecated. + optional CType ctype = 1 [/*deprecated = true,*/ default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + // The option [ctype=CORD] may be applied to a non-repeated field of type + // "bytes". It indicates that in C++, the data should be stored in a Cord + // instead of a string. For very large strings, this may reduce memory + // fragmentation. It may also allow better performance when parsing from a + // Cord, or when parsing with aliasing enabled, as the parsed Cord may then + // alias the original buffer. + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. This option is prohibited in + // Editions, but the `repeated_field_encoding` feature can be used to control + // the behavior. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // Note that lazy message fields are still eagerly verified to check + // ill-formed wireformat or missing required fields. Calling IsInitialized() + // on the outer message would fail if the inner message has missing required + // fields. Failed verification would result in parsing failure (except when + // uninitialized messages are acceptable). + optional bool lazy = 5 [default = false]; + + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default = false]; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default = false]; + + // Indicate that the field value should not be printed out when using debug + // formats, e.g. when the field contains sensitive credentials. + optional bool debug_redact = 16 [default = false]; + + // If set to RETENTION_SOURCE, the option will be omitted from the binary. + enum OptionRetention { + RETENTION_UNKNOWN = 0; + RETENTION_RUNTIME = 1; + RETENTION_SOURCE = 2; + } + + optional OptionRetention retention = 17; + + // This indicates the types of entities that the field may apply to when used + // as an option. If it is unset, then the field may be freely used as an + // option on any kind of entity. + enum OptionTargetType { + TARGET_TYPE_UNKNOWN = 0; + TARGET_TYPE_FILE = 1; + TARGET_TYPE_EXTENSION_RANGE = 2; + TARGET_TYPE_MESSAGE = 3; + TARGET_TYPE_FIELD = 4; + TARGET_TYPE_ONEOF = 5; + TARGET_TYPE_ENUM = 6; + TARGET_TYPE_ENUM_ENTRY = 7; + TARGET_TYPE_SERVICE = 8; + TARGET_TYPE_METHOD = 9; + } + + repeated OptionTargetType targets = 19; + + message EditionDefault { + optional Edition edition = 3; + optional string value = 2; // Textproto value. + } + repeated EditionDefault edition_defaults = 20; + + // Any features defined in the specific edition. + optional FeatureSet features = 21; + + // Information about the support window of a feature. + message FeatureSupport { + // The edition that this feature was first available in. In editions + // earlier than this one, the default assigned to EDITION_LEGACY will be + // used, and proto files will not be able to override it. + optional Edition edition_introduced = 1; + + // The edition this feature becomes deprecated in. Using this after this + // edition may trigger warnings. + optional Edition edition_deprecated = 2; + + // The deprecation warning text if this feature is used after the edition it + // was marked deprecated in. + optional string deprecation_warning = 3; + + // The edition this feature is no longer available in. In editions after + // this one, the last default assigned will be used, and proto files will + // not be able to override it. + optional Edition edition_removed = 4; + } + optional FeatureSupport feature_support = 22; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype + reserved 18; // reserve target, target_obsolete_do_not_use +} + +message OneofOptions { + // Any features defined in the specific edition. + optional FeatureSet features = 1; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default = false]; + + reserved 5; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // TODO Remove this legacy behavior once downstream teams have + // had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 7; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default = false]; + + // Any features defined in the specific edition. + optional FeatureSet features = 2; + + // Indicate that fields annotated with this enum value should not be printed + // out when using debug formats, e.g. when the field contains sensitive + // credentials. + optional bool debug_redact = 3 [default = false]; + + // Information about the support window of a feature value. + optional FieldOptions.FeatureSupport feature_support = 4; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Any features defined in the specific edition. + optional FeatureSet features = 34; + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default = false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = 34 + [default = IDEMPOTENCY_UNKNOWN]; + + // Any features defined in the specific edition. + optional FeatureSet features = 35; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents + // "foo.(bar.baz).moo". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Features + +// TODO Enums in C++ gencode (and potentially other languages) are +// not well scoped. This means that each of the feature enums below can clash +// with each other. The short names we've chosen maximize call-site +// readability, but leave us very open to this scenario. A future feature will +// be designed and implemented to handle this, hopefully before we ever hit a +// conflict here. +message FeatureSet { + enum FieldPresence { + FIELD_PRESENCE_UNKNOWN = 0; + EXPLICIT = 1; + IMPLICIT = 2; + LEGACY_REQUIRED = 3; + } + optional FieldPresence field_presence = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "EXPLICIT" }, + edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" }, + edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" } + ]; + + enum EnumType { + ENUM_TYPE_UNKNOWN = 0; + OPEN = 1; + CLOSED = 2; + } + optional EnumType enum_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "CLOSED" }, + edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" } + ]; + + enum RepeatedFieldEncoding { + REPEATED_FIELD_ENCODING_UNKNOWN = 0; + PACKED = 1; + EXPANDED = 2; + } + optional RepeatedFieldEncoding repeated_field_encoding = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "EXPANDED" }, + edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" } + ]; + + enum Utf8Validation { + UTF8_VALIDATION_UNKNOWN = 0; + VERIFY = 2; + NONE = 3; + reserved 1; + } + optional Utf8Validation utf8_validation = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "NONE" }, + edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" } + ]; + + enum MessageEncoding { + MESSAGE_ENCODING_UNKNOWN = 0; + LENGTH_PREFIXED = 1; + DELIMITED = 2; + } + optional MessageEncoding message_encoding = 5 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "LENGTH_PREFIXED" } + ]; + + enum JsonFormat { + JSON_FORMAT_UNKNOWN = 0; + ALLOW = 1; + LEGACY_BEST_EFFORT = 2; + } + optional JsonFormat json_format = 6 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY_BEST_EFFORT" }, + edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" } + ]; + + reserved 999; + + extensions 1000 to 9994 [ + declaration = { + number: 1000, + full_name: ".pb.cpp", + type: ".pb.CppFeatures" + }, + declaration = { + number: 1001, + full_name: ".pb.java", + type: ".pb.JavaFeatures" + }, + declaration = { number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures" }, + declaration = { + number: 9990, + full_name: ".pb.proto1", + type: ".pb.Proto1Features" + } + ]; + + extensions 9995 to 9999; // For internal testing + extensions 10000; // for https://github.com/bufbuild/protobuf-es +} + +// A compiled specification for the defaults of a set of features. These +// messages are generated from FeatureSet extensions and can be used to seed +// feature resolution. The resolution with this object becomes a simple search +// for the closest matching edition, followed by proto merges. +message FeatureSetDefaults { + // A map from every known edition with a unique set of defaults to its + // defaults. Not all editions may be contained here. For a given edition, + // the defaults at the closest matching edition ordered at or before it should + // be used. This field must be in strict ascending order by edition. + message FeatureSetEditionDefault { + optional Edition edition = 3; + + // Defaults of features that can be overridden in this edition. + optional FeatureSet overridable_features = 4; + + // Defaults of features that can't be overridden in this edition. + optional FeatureSet fixed_features = 5; + + reserved 1, 2; + reserved "features"; + } + repeated FeatureSetEditionDefault defaults = 1; + + // The minimum supported edition (inclusive) when this was constructed. + // Editions before this will not have defaults. + optional Edition minimum_edition = 4; + + // The maximum known edition (inclusive) when this was constructed. Editions + // after this will not have reliable defaults. + optional Edition maximum_edition = 5; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendant. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition appears. + // For example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed = true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed = true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to moo. + // // + // // Another line attached to moo. + // optional double moo = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to moo or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed = true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified object. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + + // Represents the identified object's effect on the element in the original + // .proto file. + enum Semantic { + // There is no effect or the effect is indescribable. + NONE = 0; + // The element is set or otherwise mutated. + SET = 1; + // An alias to the element is returned. + ALIAS = 2; + } + optional Semantic semantic = 5; + } +} \ No newline at end of file diff --git a/bolt-cli/proto/eth2-signer-api/lister.proto b/bolt-cli/proto/eth2-signer-api/lister.proto new file mode 100644 index 00000000..46640d5c --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/lister.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; + +package v1; + +import "google/api/annotations.proto"; +import "endpoint.proto"; +import "responsestate.proto"; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option java_multiple_files = true; +option java_outer_classname = "ListerProto"; + +service Lister { + rpc ListAccounts(ListAccountsRequest) returns (ListAccountsResponse) { + option (google.api.http) = { + get: "/v1/lister/listaccounts" + }; + } +} + +message ListAccountsRequest { + repeated string paths = 1; +} + +message ListAccountsResponse { + ResponseState state = 1; + repeated Account Accounts = 2; + repeated DistributedAccount DistributedAccounts = 3; +} + +message Account { + string name = 1; + bytes public_key = 2; + bytes uuid = 3; +} + +message DistributedAccount { + string name = 1; + bytes public_key = 2; + repeated Endpoint participants = 3; + uint32 signing_threshold = 4; + bytes uuid = 5; + bytes composite_public_key = 6; +} diff --git a/bolt-cli/proto/eth2-signer-api/responsestate.proto b/bolt-cli/proto/eth2-signer-api/responsestate.proto new file mode 100644 index 00000000..8eb57d9e --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/responsestate.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package v1; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option java_multiple_files = true; +option java_outer_classname = "ResponseStateProto"; + +enum ResponseState { + // UNKNOWN occurs when no information about the response is available. + UNKNOWN = 0; + // SUCCEEDED occurs when a request was successful. + SUCCEEDED = 1; + // DENIED occurs when a request was denied. + DENIED = 2; + // FAILED occurs when a request failed to complete. + FAILED = 3; +} diff --git a/bolt-cli/proto/eth2-signer-api/signer.proto b/bolt-cli/proto/eth2-signer-api/signer.proto new file mode 100644 index 00000000..02612063 --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/signer.proto @@ -0,0 +1,86 @@ +syntax = "proto3"; + +package v1; + +import "google/api/annotations.proto"; +import "eth2.proto"; +import "responsestate.proto"; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option java_multiple_files = true; +option java_outer_classname = "SignerProto"; + +service Signer { + rpc Sign(SignRequest) returns (SignResponse) { + option (google.api.http) = { + get: "/v1/signer/sign" + }; + } + rpc Multisign(MultisignRequest) returns (MultisignResponse) { + option (google.api.http) = { + get: "/v1/signer/multisign" + }; + } + rpc SignBeaconAttestation(SignBeaconAttestationRequest) returns (SignResponse) { + option (google.api.http) = { + get: "/v1/signer/signbeaconattestation" + }; + } + rpc SignBeaconAttestations(SignBeaconAttestationsRequest) returns (MultisignResponse) { + option (google.api.http) = { + get: "/v1/signer/signbeaconattestations" + }; + } + rpc SignBeaconProposal(SignBeaconProposalRequest) returns (SignResponse) { + option (google.api.http) = { + get: "/v1/signer/signbeaconproposal" + }; + } +} + +message SignRequest { + oneof id { + bytes public_key = 1; + string account = 2; + } + bytes data = 3; + bytes domain = 4; +} + +message MultisignRequest { + repeated SignRequest requests = 1; +} + +message SignBeaconAttestationRequest { + oneof id { + bytes public_key = 1; + string account = 2; + } + bytes domain = 3; + AttestationData data = 4; +} + +message SignBeaconAttestationsRequest { + repeated SignBeaconAttestationRequest requests = 1; +} + +message SignBeaconProposalRequest { + oneof id { + bytes public_key = 1; + string account = 2; + } + bytes domain = 3; + BeaconBlockHeader data = 4; +} + +message SignResponse { + ResponseState state = 1; + bytes signature = 2; +} + +message MultisignResponse { + repeated SignResponse responses = 1; +} diff --git a/bolt-cli/proto/eth2-signer-api/walletmanager.proto b/bolt-cli/proto/eth2-signer-api/walletmanager.proto new file mode 100644 index 00000000..98a5d8a0 --- /dev/null +++ b/bolt-cli/proto/eth2-signer-api/walletmanager.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +package v1; + +import "google/api/annotations.proto"; +import "responsestate.proto"; + +option csharp_namespace = "Eth2Signer.v1"; +option php_namespace = "Eth2Signer\\v1"; +option java_package = "com.wealdtech.eth2signerapi.v1"; +option go_package = "github.com/wealdtech/eth2-signer-api/pb/v1"; +option java_multiple_files = true; +option java_outer_classname = "WalletManagerProto"; + +service WalletManager { + rpc Unlock(UnlockWalletRequest) returns (UnlockWalletResponse) { + option (google.api.http) = { + get: "/v1/walletmanager/unlock" + }; + } + rpc Lock(LockWalletRequest) returns (LockWalletResponse) { + option (google.api.http) = { + get: "/v1/walletmanager/lock" + }; + } +} + +message UnlockWalletRequest { + string wallet = 1; + bytes passphrase = 2; +} + +message LockWalletRequest { + string wallet = 1; +} + +message UnlockWalletResponse { + ResponseState state = 1; +} + +message LockWalletResponse { + ResponseState state = 1; +} diff --git a/bolt-cli/src/cli.rs b/bolt-cli/src/cli.rs index 4d71ee79..9dfcabd0 100644 --- a/bolt-cli/src/cli.rs +++ b/bolt-cli/src/cli.rs @@ -37,6 +37,17 @@ pub enum Commands { #[clap(subcommand)] source: KeySource, }, + + /// Output a list of pubkeys from a keystore + Pubkeys { + /// The options for reading the keystore file. + #[clap(flatten)] + keystore_opts: KeystoreOpts, + + /// The output file for the pubkeys. + #[clap(long, env = "OUTPUT_FILE_PATH", default_value = "pubkeys.json")] + out: String, + }, } /// The action to perform. @@ -60,31 +71,39 @@ pub enum KeySource { /// Use an EIP-2335 keystore folder to generate the signed messages. Keystore { - /// Path to the keystore file. - #[clap(long, env = "KEYSTORE_PATH", default_value = "validators")] - path: String, - - /// The password for the keystore files in the path. - /// Assumes all keystore files have the same password. - #[clap( - long, - env = "KEYSTORE_PASSWORD", - hide_env_values = true, - default_value = DEFAULT_KEYSTORE_PASSWORD, - conflicts_with = "password_path" - )] - password: Option, - - #[clap( - long, - env = "KEYSTORE_PASSWORD_PATH", - default_value = "secrets", - conflicts_with = "password" - )] - password_path: Option, + /// The options for reading the keystore file. + #[clap(flatten)] + opts: KeystoreOpts, }, } +/// Options for reading a keystore folder. +#[derive(Debug, Clone, Deserialize, Parser)] +pub struct KeystoreOpts { + /// The path to the keystore file. + #[clap(long, env = "KEYSTORE_PATH", default_value = "validators")] + pub path: String, + + /// The password for the keystore files in the path. + /// Assumes all keystore files have the same password. + #[clap( + long, + env = "KEYSTORE_PASSWORD", + hide_env_values = true, + default_value = DEFAULT_KEYSTORE_PASSWORD, + conflicts_with = "password_path" + )] + pub password: Option, + + #[clap( + long, + env = "KEYSTORE_PASSWORD_PATH", + default_value = "secrets", + conflicts_with = "password" + )] + pub password_path: Option, +} + /// Supported chains for the CLI #[derive(Debug, Clone, Copy, ValueEnum, Deserialize)] #[clap(rename_all = "kebab_case")] diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index d4ef0a72..e465c0b1 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -5,7 +5,6 @@ mod cli; use cli::{Commands, KeySource, Opts}; mod delegation; -use delegation::{generate_from_keystore, generate_from_local_keys}; mod utils; use utils::{keystore::KeystoreSecret, parse_bls_public_key, write_to_file}; @@ -19,15 +18,16 @@ fn main() -> Result<()> { Commands::Delegate { delegatee_pubkey, out, chain, source, action } => match source { KeySource::Local { secret_keys } => { let delegatee = parse_bls_public_key(&delegatee_pubkey)?; - let messages = generate_from_local_keys(&secret_keys, delegatee, &chain, action)?; + let signed_messages = + delegation::generate_from_local_keys(&secret_keys, delegatee, &chain, action)?; - write_to_file(&out, &messages)?; + write_to_file(&out, &signed_messages)?; println!("Signed delegation messages generated and saved to {}", out); } - KeySource::Keystore { path, password, password_path } => { - let passwords = if let Some(password_path) = password_path { + KeySource::Keystore { opts } => { + let passwords = if let Some(password_path) = opts.password_path { KeystoreSecret::from_directory(password_path)? - } else if let Some(password) = password { + } else if let Some(password) = opts.password { KeystoreSecret::from_unique_password(password) } else { // This case is prevented upstream by clap's validation. @@ -35,12 +35,28 @@ fn main() -> Result<()> { }; let delegatee = parse_bls_public_key(&delegatee_pubkey)?; - let messages = generate_from_keystore(&path, passwords, delegatee, chain, action)?; + let signed_messages = delegation::generate_from_keystore( + &opts.path, passwords, delegatee, chain, action, + )?; - write_to_file(&out, &messages)?; + write_to_file(&out, &signed_messages)?; println!("Signed delegation messages generated and saved to {}", out); } }, + + Commands::Pubkeys { keystore_opts, out } => { + let passwords = if let Some(password_path) = keystore_opts.password_path { + KeystoreSecret::from_directory(password_path)? + } else if let Some(password) = keystore_opts.password { + KeystoreSecret::from_unique_password(password) + } else { + // This case is prevented upstream by clap's validation. + bail!("Either `password_path` or `password` must be provided") + }; + + // let pubkeys = utils::keystore::read_pubkeys(); + } } + Ok(()) } From 6bd5487e5f9a845f69aae0fdca2f34fba9b1d29b Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:02:47 +0200 Subject: [PATCH 05/16] feat: test dirk remote connection --- bolt-cli/Cargo.lock | 4256 ++--------------- bolt-cli/Cargo.toml | 31 +- bolt-cli/build.rs | 17 +- .../google/protobuf/descriptor.proto | 1293 ----- .../{ => v1}/accountmanager.proto | 0 .../proto/eth2-signer-api/{ => v1}/dkg.proto | 0 .../eth2-signer-api/{ => v1}/endpoint.proto | 0 .../proto/eth2-signer-api/{ => v1}/eth2.proto | 0 .../eth2-signer-api/{ => v1}/lister.proto | 0 .../{ => v1}/responsestate.proto | 0 .../eth2-signer-api/{ => v1}/signer.proto | 0 .../{ => v1}/walletmanager.proto | 0 bolt-cli/src/cli.rs | 53 +- bolt-cli/src/delegation.rs | 6 +- bolt-cli/src/main.rs | 80 +- bolt-cli/src/pb/google.api.rs | 306 ++ bolt-cli/src/pb/mod.rs | 7 + bolt-cli/src/pb/v1.rs | 378 ++ bolt-cli/src/pubkeys.rs | 36 + bolt-cli/src/utils/dirk.rs | 106 + bolt-cli/src/utils/keystore.rs | 21 +- bolt-cli/src/utils/mod.rs | 3 + bolt-cli/src/utils/signing.rs | 4 +- bolt-cli/test_data/dirk/client1.crt | 31 + bolt-cli/test_data/dirk/client1.key | 52 + bolt-cli/test_data/dirk/security/ca.crt | 31 + .../test_data/dirk/security/localhost.crt | 31 + .../test_data/dirk/security/localhost.key | 52 + 28 files changed, 1611 insertions(+), 5183 deletions(-) delete mode 100644 bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto rename bolt-cli/proto/eth2-signer-api/{ => v1}/accountmanager.proto (100%) rename bolt-cli/proto/eth2-signer-api/{ => v1}/dkg.proto (100%) rename bolt-cli/proto/eth2-signer-api/{ => v1}/endpoint.proto (100%) rename bolt-cli/proto/eth2-signer-api/{ => v1}/eth2.proto (100%) rename bolt-cli/proto/eth2-signer-api/{ => v1}/lister.proto (100%) rename bolt-cli/proto/eth2-signer-api/{ => v1}/responsestate.proto (100%) rename bolt-cli/proto/eth2-signer-api/{ => v1}/signer.proto (100%) rename bolt-cli/proto/eth2-signer-api/{ => v1}/walletmanager.proto (100%) create mode 100644 bolt-cli/src/pb/google.api.rs create mode 100644 bolt-cli/src/pb/mod.rs create mode 100644 bolt-cli/src/pb/v1.rs create mode 100644 bolt-cli/src/pubkeys.rs create mode 100644 bolt-cli/src/utils/dirk.rs create mode 100644 bolt-cli/test_data/dirk/client1.crt create mode 100644 bolt-cli/test_data/dirk/client1.key create mode 100644 bolt-cli/test_data/dirk/security/ca.crt create mode 100644 bolt-cli/test_data/dirk/security/localhost.crt create mode 100644 bolt-cli/test_data/dirk/security/localhost.key diff --git a/bolt-cli/Cargo.lock b/bolt-cli/Cargo.lock index 8c55be52..ba8cd5d2 100644 --- a/bolt-cli/Cargo.lock +++ b/bolt-cli/Cargo.lock @@ -2,26 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "account_utils" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "directory", - "eth2_keystore", - "eth2_wallet", - "filesystem", - "rand", - "regex", - "rpassword", - "serde", - "serde_yaml 0.9.34+deprecated", - "slog", - "types", - "validator_dir", - "zeroize", -] - [[package]] name = "addr2line" version = "0.24.2" @@ -37,21 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array", -] - [[package]] name = "aes" version = "0.7.5" @@ -59,49 +24,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher", "cpufeatures", - "ctr 0.8.0", + "ctr", "opaque-debug", ] -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher 0.4.4", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" -dependencies = [ - "aead", - "aes 0.7.5", - "cipher 0.3.0", - "ctr 0.7.0", - "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -111,198 +39,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" - -[[package]] -name = "alloy" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4a4aaae80afd4be443a6aecd92a6b255dcdd000f97996928efb33d8a71e100" -dependencies = [ - "alloy-consensus", - "alloy-contract", - "alloy-core", - "alloy-eips", - "alloy-genesis", - "alloy-network", - "alloy-provider", - "alloy-pubsub", - "alloy-rpc-client", - "alloy-rpc-types", - "alloy-serde", - "alloy-signer", - "alloy-signer-local", - "alloy-transport", - "alloy-transport-http", - "alloy-transport-ipc", - "alloy-transport-ws", -] - -[[package]] -name = "alloy-chains" -version = "0.1.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156bfc5dcd52ef9a5f33381701fa03310317e14c65093a9430d3e3557b08dcd3" -dependencies = [ - "alloy-primitives 0.8.7", - "num_enum", - "strum", -] - -[[package]] -name = "alloy-consensus" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c309895995eaa4bfcc345f5515a39c7df9447798645cc8bf462b6c5bf1dc96" -dependencies = [ - "alloy-eips", - "alloy-primitives 0.7.7", - "alloy-rlp", - "alloy-serde", - "c-kzg", - "serde", -] - -[[package]] -name = "alloy-contract" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4e0ef72b0876ae3068b2ed7dfae9ae1779ce13cfaec2ee1f08f5bd0348dc57" -dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-network", - "alloy-network-primitives", - "alloy-primitives 0.7.7", - "alloy-provider", - "alloy-pubsub", - "alloy-rpc-types-eth", - "alloy-sol-types", - "alloy-transport", - "futures", - "futures-util", - "thiserror", -] - -[[package]] -name = "alloy-core" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529fc6310dc1126c8de51c376cbc59c79c7f662bd742be7dc67055d5421a81b4" -dependencies = [ - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-primitives 0.7.7", - "alloy-sol-types", -] - -[[package]] -name = "alloy-dyn-abi" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413902aa18a97569e60f679c23f46a18db1656d87ab4d4e49d0e1e52042f66df" -dependencies = [ - "alloy-json-abi", - "alloy-primitives 0.7.7", - "alloy-sol-type-parser", - "alloy-sol-types", - "const-hex", - "itoa", - "serde", - "serde_json", - "winnow", -] - -[[package]] -name = "alloy-eips" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9431c99a3b3fe606ede4b3d4043bdfbcb780c45b8d8d226c3804e2b75cfbe68" -dependencies = [ - "alloy-primitives 0.7.7", - "alloy-rlp", - "alloy-serde", - "c-kzg", - "derive_more 0.99.18", - "k256 0.13.4", - "once_cell", - "serde", - "sha2 0.10.8", -] - -[[package]] -name = "alloy-genesis" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79614dfe86144328da11098edcc7bc1a3f25ad8d3134a9eb9e857e06f0d9840d" -dependencies = [ - "alloy-primitives 0.7.7", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-json-abi" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc05b04ac331a9f07e3a4036ef7926e49a8bf84a99a1ccfc7e2ab55a5fcbb372" -dependencies = [ - "alloy-primitives 0.7.7", - "alloy-sol-type-parser", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-json-rpc" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e2865c4c3bb4cdad3f0d9ec1ab5c0c657ba69a375651bd35e32fb6c180ccc2" -dependencies = [ - "alloy-primitives 0.7.7", - "alloy-sol-types", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "alloy-network" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e701fc87ef9a3139154b0b4ccb935b565d27ffd9de020fe541bf2dec5ae4ede" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network-primitives", - "alloy-primitives 0.7.7", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-signer", - "alloy-sol-types", - "async-trait", - "auto_impl", - "futures-utils-wasm", - "thiserror", -] - -[[package]] -name = "alloy-network-primitives" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9d5a0f9170b10988b6774498a022845e13eda94318440d17709d50687f67f9" -dependencies = [ - "alloy-primitives 0.7.7", - "alloy-serde", - "serde", -] - [[package]] name = "alloy-primitives" version = "0.7.7" @@ -312,417 +48,69 @@ dependencies = [ "alloy-rlp", "bytes", "cfg-if", - "const-hex", - "derive_more 0.99.18", - "hex-literal", - "itoa", - "k256 0.13.4", - "keccak-asm", - "proptest", - "rand", - "ruint", - "serde", - "tiny-keccak", -] - -[[package]] -name = "alloy-primitives" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb848c43f6b06ae3de2e4a67496cbbabd78ae87db0f1248934f15d76192c6a" -dependencies = [ - "bytes", - "cfg-if", - "const-hex", - "derive_more 1.0.0", - "hex-literal", - "itoa", - "paste", - "ruint", - "tiny-keccak", -] - -[[package]] -name = "alloy-provider" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9c0ab10b93de601a6396fc7ff2ea10d3b28c46f079338fa562107ebf9857c8" -dependencies = [ - "alloy-chains", - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network", - "alloy-network-primitives", - "alloy-primitives 0.7.7", - "alloy-pubsub", - "alloy-rpc-client", - "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-rpc-types-trace", - "alloy-transport", - "alloy-transport-http", - "alloy-transport-ipc", - "alloy-transport-ws", - "async-stream", - "async-trait", - "auto_impl", - "dashmap", - "futures", - "futures-utils-wasm", - "lru", - "pin-project", - "reqwest 0.12.8", - "serde", - "serde_json", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "alloy-pubsub" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f5da2c55cbaf229bad3c5f8b00b5ab66c74ef093e5f3a753d874cfecf7d2281" -dependencies = [ - "alloy-json-rpc", - "alloy-primitives 0.7.7", - "alloy-transport", - "bimap", - "futures", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", -] - -[[package]] -name = "alloy-rlp" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" -dependencies = [ - "alloy-rlp-derive", - "arrayvec", - "bytes", -] - -[[package]] -name = "alloy-rlp-derive" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.82", -] - -[[package]] -name = "alloy-rpc-client" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b38e3ffdb285df5d9f60cb988d336d9b8e3505acb78750c3bc60336a7af41d3" -dependencies = [ - "alloy-json-rpc", - "alloy-primitives 0.7.7", - "alloy-pubsub", - "alloy-transport", - "alloy-transport-http", - "alloy-transport-ipc", - "alloy-transport-ws", - "futures", - "pin-project", - "reqwest 0.12.8", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", - "url", -] - -[[package]] -name = "alloy-rpc-types" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c31a3750b8f5a350d17354e46a52b0f2f19ec5f2006d816935af599dedc521" -dependencies = [ - "alloy-rpc-types-beacon", - "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-rpc-types-trace", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-rpc-types-beacon" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8a24bcff4f9691d7a4971b43e5da46aa7b4ce22ed7789796612dc1eed220983" -dependencies = [ - "alloy-eips", - "alloy-primitives 0.7.7", - "alloy-rpc-types-engine", - "serde", - "serde_with", - "thiserror", -] - -[[package]] -name = "alloy-rpc-types-engine" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff63f51b2fb2f547df5218527fd0653afb1947bf7fead5b3ce58c75d170b30f7" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives 0.7.7", - "alloy-rlp", - "alloy-rpc-types-eth", - "alloy-serde", - "jsonwebtoken", - "rand", - "serde", - "thiserror", -] - -[[package]] -name = "alloy-rpc-types-eth" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81e18424d962d7700a882fe423714bd5b9dde74c7a7589d4255ea64068773aef" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-network-primitives", - "alloy-primitives 0.7.7", - "alloy-rlp", - "alloy-serde", - "alloy-sol-types", - "itertools 0.13.0", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "alloy-rpc-types-trace" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86eeb49ea0cc79f249faa1d35c20541bb1c317a59b5962cb07b1890355b0064" -dependencies = [ - "alloy-primitives 0.7.7", - "alloy-rpc-types-eth", - "alloy-serde", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "alloy-serde" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33feda6a53e6079895aed1d08dcb98a1377b000d80d16370fbbdb8155d547ef" -dependencies = [ - "alloy-primitives 0.7.7", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-signer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740a25b92e849ed7b0fa013951fe2f64be9af1ad5abe805037b44fb7770c5c47" -dependencies = [ - "alloy-primitives 0.7.7", - "async-trait", - "auto_impl", - "elliptic-curve 0.13.8", - "k256 0.13.4", - "thiserror", -] - -[[package]] -name = "alloy-signer-local" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0707d4f63e4356a110b30ef3add8732ab6d181dd7be4607bf79b8777105cee" -dependencies = [ - "alloy-consensus", - "alloy-network", - "alloy-primitives 0.7.7", - "alloy-signer", - "async-trait", - "k256 0.13.4", - "rand", - "thiserror", -] - -[[package]] -name = "alloy-sol-macro" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" -dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.82", -] - -[[package]] -name = "alloy-sol-macro-expander" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" -dependencies = [ - "alloy-json-abi", - "alloy-sol-macro-input", - "const-hex", - "heck", - "indexmap 2.6.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.82", - "syn-solidity", - "tiny-keccak", -] - -[[package]] -name = "alloy-sol-macro-input" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" -dependencies = [ - "alloy-json-abi", - "const-hex", - "dunce", - "heck", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.82", - "syn-solidity", -] - -[[package]] -name = "alloy-sol-type-parser" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" -dependencies = [ - "serde", - "winnow", -] - -[[package]] -name = "alloy-sol-types" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" -dependencies = [ - "alloy-json-abi", - "alloy-primitives 0.7.7", - "alloy-sol-macro", - "const-hex", - "serde", -] - -[[package]] -name = "alloy-transport" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0590afbdacf2f8cca49d025a2466f3b6584a016a8b28f532f29f8da1007bae" -dependencies = [ - "alloy-json-rpc", - "base64 0.22.1", - "futures-util", - "futures-utils-wasm", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - -[[package]] -name = "alloy-transport-http" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2437d145d80ea1aecde8574d2058cceb8b3c9cba05f6aea8e67907c660d46698" -dependencies = [ - "alloy-json-rpc", - "alloy-transport", - "reqwest 0.12.8", - "serde_json", - "tower", - "tracing", - "url", + "const-hex", + "derive_more 0.99.18", + "hex-literal", + "itoa", + "k256 0.13.4", + "keccak-asm", + "proptest", + "rand", + "ruint", + "serde", + "tiny-keccak", ] [[package]] -name = "alloy-transport-ipc" -version = "0.2.1" +name = "alloy-primitives" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804494366e20468776db4e18f9eb5db7db0fe14f1271eb6dbf155d867233405c" +checksum = "c71738eb20c42c5fb149571e76536a0f309d142f3957c28791662b96baf77a3d" dependencies = [ - "alloy-json-rpc", - "alloy-pubsub", - "alloy-transport", + "alloy-rlp", "bytes", - "futures", - "interprocess", - "pin-project", - "serde_json", - "tokio", - "tokio-util", - "tracing", + "cfg-if", + "const-hex", + "derive_more 1.0.0", + "foldhash", + "hashbrown 0.15.0", + "hex-literal", + "indexmap 2.6.0", + "itoa", + "k256 0.13.4", + "keccak-asm", + "paste", + "proptest", + "rand", + "ruint", + "rustc-hash 2.0.0", + "serde", + "sha3", + "tiny-keccak", ] [[package]] -name = "alloy-transport-ws" -version = "0.2.1" +name = "alloy-rlp" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af855163e7df008799941aa6dd324a43ef2bf264b08ba4b22d44aad6ced65300" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" dependencies = [ - "alloy-pubsub", - "alloy-transport", - "futures", - "http 1.1.0", - "rustls 0.23.14", - "serde_json", - "tokio", - "tokio-tungstenite", - "tracing", - "ws_stream_wasm", + "arrayvec", + "bytes", ] [[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" +name = "alloy-signer" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "67eca011160d18a7dc6d8cdc1e8dc13e2e86c908f8e41b02aa76e429d6fe7085" dependencies = [ - "libc", + "alloy-primitives 0.8.9", + "async-trait", + "auto_impl", + "elliptic-curve 0.13.8", + "k256 0.13.4", + "thiserror", ] [[package]] @@ -789,21 +177,6 @@ dependencies = [ "derive_arbitrary", ] -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - -[[package]] -name = "archery" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a8da9bc4c4053ee067669762bcaeea6e241841295a2b6c948312dad6ef4cc02" -dependencies = [ - "static_assertions", -] - [[package]] name = "ark-ff" version = "0.3.0" @@ -940,12 +313,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "asn1_der" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" - [[package]] name = "async-stream" version = "0.3.6" @@ -980,15 +347,10 @@ dependencies = [ ] [[package]] -name = "async_io_stream" -version = "0.3.3" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version 0.4.1", -] +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "auto_impl" @@ -1007,6 +369,80 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "aws-lc-rs" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd82dba44d209fddb11c190e0a94b78651f95299598e472215667417a03ff1d" +dependencies = [ + "aws-lc-sys", + "mirai-annotations", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df7a4168111d7eb622a31b214057b8509c0a7e1794f44c546d742330dc793972" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "libc", + "paste", +] + +[[package]] +name = "axum" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.1", + "tower 0.5.1", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.1", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -1019,15 +455,9 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base16ct" version = "0.1.1" @@ -1046,12 +476,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -1065,10 +489,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] -name = "bimap" -version = "0.6.3" +name = "bindgen" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.10.5", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.82", + "which", +] [[package]] name = "bit-set" @@ -1085,40 +526,22 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty 1.1.0", - "radium 0.6.2", - "tap", - "wyz 0.2.0", -] - [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "funty 2.0.0", - "radium 0.7.0", + "funty", + "radium", "tap", - "wyz 0.5.1", + "wyz", ] [[package]] @@ -1127,7 +550,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", "generic-array", ] @@ -1140,12 +562,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "bls" version = "0.2.0" @@ -1153,7 +569,7 @@ source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff dependencies = [ "arbitrary", "blst", - "ethereum-types 0.14.1", + "ethereum-types", "ethereum_hashing", "ethereum_serde_utils", "ethereum_ssz", @@ -1180,8 +596,8 @@ dependencies = [ name = "bolt-cli" version = "0.1.0" dependencies = [ - "account_utils", - "alloy", + "alloy-primitives 0.8.9", + "alloy-signer", "blst", "clap", "dotenvy", @@ -1190,11 +606,14 @@ dependencies = [ "eyre", "hex", "prost", - "prost-build", + "rustls", "serde", "serde_json", "tempfile", "thiserror", + "tokio", + "tonic", + "tonic-build", ] [[package]] @@ -1203,15 +622,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -1239,27 +649,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "c-kzg" version = "1.0.3" @@ -1275,20 +664,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cached_tree_hash" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "ethereum-types 0.14.1", - "ethereum_hashing", - "ethereum_ssz", - "ethereum_ssz_derive", - "smallvec", - "ssz_types", - "tree_hash", -] - [[package]] name = "cc" version = "1.1.30" @@ -1301,23 +676,19 @@ dependencies = [ ] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] [[package]] -name = "chrono" -version = "0.4.38" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-targets 0.52.6", -] +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cipher" @@ -1329,13 +700,14 @@ dependencies = [ ] [[package]] -name = "cipher" -version = "0.4.4" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ - "crypto-common", - "inout", + "glob", + "libc", + "libloading", ] [[package]] @@ -1357,8 +729,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.1", - "terminal_size", + "strsim", ] [[package]] @@ -1380,20 +751,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] -name = "clap_utils" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" +name = "cmake" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" dependencies = [ - "clap", - "dirs", - "eth2_network_config", - "ethereum-types 0.14.1", - "ethereum_ssz", - "hex", - "serde", - "serde_json", - "serde_yaml 0.9.34+deprecated", - "types", + "cc", ] [[package]] @@ -1402,23 +765,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" -[[package]] -name = "compare_fields" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "itertools 0.10.5", -] - -[[package]] -name = "compare_fields_derive" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "const-hex" version = "1.13.1" @@ -1436,35 +782,13 @@ dependencies = [ name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core2" @@ -1484,49 +808,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - [[package]] name = "crunchy" version = "0.2.2" @@ -1567,16 +848,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.0" @@ -1587,138 +858,13 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctr" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" -dependencies = [ - "cipher 0.3.0", -] - [[package]] name = "ctr" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.3.0", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto", - "rustc_version 0.4.1", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.82", -] - -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.11.1", - "syn 2.0.82", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core 0.20.10", - "quote", - "syn 2.0.82", -] - -[[package]] -name = "dary_heap" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core 0.9.10", + "cipher", ] [[package]] @@ -1727,51 +873,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" -[[package]] -name = "data-encoding-macro" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" -dependencies = [ - "data-encoding", - "data-encoding-macro-internal", -] - -[[package]] -name = "data-encoding-macro-internal" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" -dependencies = [ - "data-encoding", - "syn 1.0.109", -] - -[[package]] -name = "delay_map" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4355c25cbf99edcb6b4a0e906f6bdc6956eda149e84455bea49696429b2f8e8" -dependencies = [ - "futures", - "tokio-util", -] - -[[package]] -name = "deposit_contract" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "ethabi", - "ethereum_ssz", - "hex", - "reqwest 0.11.27", - "serde_json", - "sha2 0.9.9", - "tree_hash", - "types", -] - [[package]] name = "der" version = "0.6.1" @@ -1792,16 +893,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - [[package]] name = "derivative" version = "2.2.0" @@ -1879,94 +970,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "directory" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "clap", - "clap_utils", - "eth2_network_config", -] - -[[package]] -name = "dirs" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "discv5" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac33cb3f99889a57e56a8c6ccb77aaf0cfc7787602b7af09783f736d77314e1" -dependencies = [ - "aes 0.7.5", - "aes-gcm", - "arrayvec", - "delay_map", - "enr 0.10.0", - "fnv", - "futures", - "hashlink", - "hex", - "hkdf", - "lazy_static", - "libp2p", - "lru", - "more-asserts", - "parking_lot 0.11.2", - "rand", - "rlp", - "smallvec", - "socket2 0.4.10", - "tokio", - "tracing", - "uint", - "zeroize", -] - -[[package]] -name = "doctest-file" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" - [[package]] name = "dotenvy" version = "0.15.7" @@ -2005,31 +1008,6 @@ dependencies = [ "spki 0.7.3", ] -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8 0.10.2", - "signature 2.2.0", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", - "serde", - "sha2 0.10.8", - "subtle", - "zeroize", -] - [[package]] name = "either" version = "1.13.0" @@ -2075,50 +1053,22 @@ dependencies = [ "zeroize", ] -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enr" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fa0a0be8915790626d5759eb51fe47435a8eac92c2f212bd2da9aa7f30ea56" -dependencies = [ - "base64 0.13.1", - "bs58 0.4.0", - "bytes", - "hex", - "k256 0.11.6", - "log", - "rand", - "rlp", - "serde", - "sha3 0.10.8", - "zeroize", -] - [[package]] name = "enr" -version = "0.10.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +checksum = "26fa0a0be8915790626d5759eb51fe47435a8eac92c2f212bd2da9aa7f30ea56" dependencies = [ - "base64 0.21.7", + "base64 0.13.1", + "bs58", "bytes", - "ed25519-dalek", "hex", - "k256 0.13.4", + "k256 0.11.6", "log", "rand", "rlp", "serde", - "sha3 0.10.8", + "sha3", "zeroize", ] @@ -2128,15 +1078,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "erased-serde" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" -dependencies = [ - "serde", -] - [[package]] name = "errno" version = "0.3.9" @@ -2147,29 +1088,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "eth2_config" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "paste", - "types", -] - -[[package]] -name = "eth2_interop_keypairs" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "bls", - "ethereum_hashing", - "hex", - "lazy_static", - "num-bigint", - "serde", - "serde_yaml 0.9.34+deprecated", -] - [[package]] name = "eth2_key_derivation" version = "0.1.0" @@ -2187,12 +1105,12 @@ name = "eth2_keystore" version = "0.1.0" source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ - "aes 0.7.5", + "aes", "bls", "eth2_key_derivation", "hex", "hmac 0.11.0", - "pbkdf2 0.8.0", + "pbkdf2", "rand", "scrypt", "serde", @@ -2204,69 +1122,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "eth2_network_config" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "bytes", - "discv5", - "eth2_config", - "logging", - "pretty_reqwest_error", - "reqwest 0.11.27", - "sensitive_url", - "serde_yaml 0.9.34+deprecated", - "sha2 0.9.9", - "slog", - "types", - "url", - "zip", -] - -[[package]] -name = "eth2_wallet" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "eth2_key_derivation", - "eth2_keystore", - "rand", - "serde", - "serde_json", - "serde_repr", - "tiny-bip39", - "uuid", -] - -[[package]] -name = "ethabi" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c98847055d934070b90e806e12d3936b787d0a115068981c1d8dfd5dfef5a5" -dependencies = [ - "ethereum-types 0.12.1", - "hex", - "serde", - "serde_json", - "sha3 0.9.1", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" -dependencies = [ - "crunchy", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "tiny-keccak", -] - [[package]] name = "ethbloom" version = "0.13.0" @@ -2274,9 +1129,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", - "fixed-hash 0.8.0", + "fixed-hash", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "tiny-keccak", ] @@ -2286,17 +1141,17 @@ version = "0.1.1" source = "git+https://github.com/ralexstokes/ethereum-consensus?rev=cf3c404#cf3c404043230559660810bc0c9d6d5a8498d819" dependencies = [ "blst", - "bs58 0.4.0", + "bs58", "c-kzg", - "enr 0.6.2", + "enr", "hex", "integer-sqrt", - "multiaddr 0.14.0", - "multihash 0.16.3", + "multiaddr", + "multihash", "rand", "serde", "serde_json", - "serde_yaml 0.8.26", + "serde_yaml", "sha2 0.10.8", "ssz_rs", "thiserror", @@ -2304,31 +1159,17 @@ dependencies = [ "tokio-stream", ] -[[package]] -name = "ethereum-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" -dependencies = [ - "ethbloom 0.11.1", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "primitive-types 0.10.1", - "uint", -] - [[package]] name = "ethereum-types" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ - "ethbloom 0.13.0", - "fixed-hash 0.8.0", + "ethbloom", + "fixed-hash", "impl-rlp", - "impl-serde 0.4.0", - "primitive-types 0.12.2", + "impl-serde", + "primitive-types", "uint", ] @@ -2350,7 +1191,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de4d5951468846963c24e8744c133d44f39dff2cd3a233f6be22b370d08a524f" dependencies = [ - "ethereum-types 0.14.1", + "ethereum-types", "hex", "serde", "serde_derive", @@ -2363,23 +1204,11 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d3627f83d8b87b432a5fad9934b4565260722a141a2c40f371f8080adec9425" dependencies = [ - "ethereum-types 0.14.1", + "ethereum-types", "itertools 0.10.5", "smallvec", ] -[[package]] -name = "ethereum_ssz_derive" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eccd5378ec34a07edd3d9b48088cbc63309d0367d14ba10b0cdb1d1791080ea" -dependencies = [ - "darling 0.13.4", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "eyre" version = "0.6.12" @@ -2390,18 +1219,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - [[package]] name = "fastrand" version = "2.1.1" @@ -2439,50 +1256,12 @@ dependencies = [ "subtle", ] -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version 0.4.1", -] - -[[package]] -name = "filesystem" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "winapi", - "windows-acl", -] - -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - [[package]] name = "fixed-hash" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ - "arbitrary", "byteorder", "rand", "rustc-hex", @@ -2495,16 +1274,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flate2" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -2517,21 +1286,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2542,20 +1296,10 @@ dependencies = [ ] [[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "funty" -version = "1.1.0" +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "funty" @@ -2563,21 +1307,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -2585,7 +1314,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -2594,35 +1322,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.82", -] - [[package]] name = "futures-sink" version = "0.3.31" @@ -2635,36 +1334,18 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", ] -[[package]] -name = "futures-utils-wasm" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" - [[package]] name = "generic-array" version = "0.14.7" @@ -2683,20 +1364,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" -dependencies = [ - "opaque-debug", - "polyval", ] [[package]] @@ -2735,16 +1404,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", - "http 0.2.12", + "http", "indexmap 2.6.0", "slab", "tokio", @@ -2758,36 +1427,15 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] - [[package]] name = "hashbrown" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" dependencies = [ - "allocator-api2", - "equivalent", "foldhash", ] -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "heck" version = "0.5.0" @@ -2800,12 +1448,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - [[package]] name = "hex" version = "0.4.3" @@ -2821,32 +1463,13 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac 0.12.1", -] - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.11.0", + "crypto-mac", "digest 0.9.0", ] @@ -2860,25 +1483,12 @@ dependencies = [ ] [[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", -] - -[[package]] -name = "http" -version = "0.2.12" +name = "home" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "bytes", - "fnv", - "itoa", + "windows-sys 0.52.0", ] [[package]] @@ -2892,17 +1502,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -2910,7 +1509,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -2921,8 +1520,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -2940,87 +1539,35 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.30" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", - "http 0.2.12", - "http-body 0.4.6", + "http", + "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.7", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "httparse", - "itoa", - "pin-project-lite", "smallvec", "tokio", "want", ] [[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.30", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper 0.14.30", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" +name = "hyper-timeout" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" dependencies = [ - "bytes", - "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", - "native-tls", + "pin-project-lite", "tokio", - "tokio-native-tls", "tower-service", ] @@ -3033,45 +1580,16 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", + "http", + "http-body", + "hyper", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", "tower-service", "tracing", ] -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.5.0" @@ -3082,22 +1600,13 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "impl-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" -dependencies = [ - "parity-scale-codec 2.3.1", -] - [[package]] name = "impl-codec" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec 3.6.12", + "parity-scale-codec", ] [[package]] @@ -3109,15 +1618,6 @@ dependencies = [ "rlp", ] -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - [[package]] name = "impl-serde" version = "0.4.0" @@ -3152,7 +1652,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -3163,33 +1662,6 @@ checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown 0.15.0", - "serde", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "int_to_bytes" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "bytes", ] [[package]] @@ -3201,38 +1673,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "interprocess" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f4e4a06d42fab3e85ab1b419ad32b09eab58b901d40c57935ff92db3287a13" -dependencies = [ - "doctest-file", - "futures-core", - "libc", - "recvmsg", - "tokio", - "widestring 1.1.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "ipnet" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" - -[[package]] -name = "is-terminal" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" -dependencies = [ - "hermit-abi 0.4.0", - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -3281,21 +1721,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonwebtoken" -version = "9.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" -dependencies = [ - "base64 0.21.7", - "js-sys", - "pem", - "ring 0.17.8", - "serde", - "serde_json", - "simple_asn1", -] - [[package]] name = "k256" version = "0.11.6" @@ -3309,293 +1734,73 @@ dependencies = [ ] [[package]] -name = "k256" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" -dependencies = [ - "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", - "once_cell", - "sha2 0.10.8", - "signature 2.2.0", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "keccak-asm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" -dependencies = [ - "digest 0.10.7", - "sha3-asm", -] - -[[package]] -name = "kzg" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "arbitrary", - "c-kzg", - "derivative", - "ethereum_hashing", - "ethereum_serde_utils", - "ethereum_ssz", - "ethereum_ssz_derive", - "hex", - "serde", - "tree_hash", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin 0.9.8", -] - -[[package]] -name = "libc" -version = "0.2.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" - -[[package]] -name = "libflate" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e" -dependencies = [ - "adler32", - "core2", - "crc32fast", - "dary_heap", - "libflate_lz77", -] - -[[package]] -name = "libflate_lz77" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" -dependencies = [ - "core2", - "hashbrown 0.14.5", - "rle-decode-fast", -] - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "libp2p" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681fb3f183edfbedd7a57d32ebe5dcdc0b9f94061185acf3c30249349cc6fc99" -dependencies = [ - "bytes", - "either", - "futures", - "futures-timer", - "getrandom", - "instant", - "libp2p-allow-block-list", - "libp2p-connection-limits", - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "multiaddr 0.18.2", - "pin-project", - "rw-stream-sink", - "thiserror", -] - -[[package]] -name = "libp2p-allow-block-list" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "107b238b794cb83ab53b74ad5dcf7cca3200899b72fe662840cfb52f5b0a32e6" -dependencies = [ - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "void", -] - -[[package]] -name = "libp2p-connection-limits" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7cd50a78ccfada14de94cbacd3ce4b0138157f376870f13d3a8422cd075b4fd" -dependencies = [ - "libp2p-core", - "libp2p-identity", - "libp2p-swarm", - "void", -] - -[[package]] -name = "libp2p-core" -version = "0.41.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a8920cbd8540059a01950c1e5c96ea8d89eb50c51cd366fc18bdf540a6e48f" -dependencies = [ - "either", - "fnv", - "futures", - "futures-timer", - "libp2p-identity", - "multiaddr 0.18.2", - "multihash 0.19.1", - "multistream-select", - "once_cell", - "parking_lot 0.12.3", - "pin-project", - "quick-protobuf", - "rand", - "rw-stream-sink", - "smallvec", - "thiserror", - "tracing", - "unsigned-varint 0.8.0", - "void", - "web-time", -] - -[[package]] -name = "libp2p-identity" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" -dependencies = [ - "asn1_der", - "bs58 0.5.1", - "ed25519-dalek", - "hkdf", - "libsecp256k1", - "multihash 0.19.1", - "quick-protobuf", - "rand", - "sha2 0.10.8", - "thiserror", - "tracing", - "zeroize", -] - -[[package]] -name = "libp2p-swarm" -version = "0.44.2" +name = "k256" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80cae6cb75f89dbca53862f9ebe0b9f463aa7b302762fcfaafb9e51dcc9b0f7e" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "either", - "fnv", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-identity", - "lru", - "multistream-select", + "cfg-if", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", "once_cell", - "rand", - "smallvec", - "tracing", - "void", + "sha2 0.10.8", ] [[package]] -name = "libredox" -version = "0.1.3" +name = "keccak" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ - "bitflags 2.6.0", - "libc", + "cpufeatures", ] [[package]] -name = "libsecp256k1" -version = "0.7.1" +name = "keccak-asm" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" dependencies = [ - "arrayref", - "base64 0.13.1", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand", - "serde", - "sha2 0.9.9", - "typenum", + "digest 0.10.7", + "sha3-asm", ] [[package]] -name = "libsecp256k1-core" -version = "0.3.0" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", + "spin 0.9.8", ] [[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" +name = "lazycell" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" -dependencies = [ - "libsecp256k1-core", -] +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" +name = "libc" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" -dependencies = [ - "libsecp256k1-core", -] +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] -name = "libsqlite3-sys" -version = "0.25.2" +name = "libloading" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ - "cc", - "pkg-config", - "vcpkg", + "cfg-if", + "windows-targets", ] [[package]] -name = "lighthouse_metrics" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "prometheus", -] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linked-hash-map" @@ -3619,14 +1824,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfile" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "fs2", -] - [[package]] name = "log" version = "0.4.22" @@ -3634,51 +1831,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] -name = "logging" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "chrono", - "lazy_static", - "lighthouse_metrics", - "parking_lot 0.12.3", - "serde", - "serde_json", - "slog", - "slog-term", - "sloggers", - "take_mut", - "tokio", - "tracing", - "tracing-appender", - "tracing-core", - "tracing-log", - "tracing-subscriber", -] - -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.0", -] - -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "matchers" -version = "0.1.0" +name = "matchit" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" @@ -3686,78 +1842,18 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "merkle_proof" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "ethereum-types 0.14.1", - "ethereum_hashing", - "lazy_static", - "safe_arith", -] - -[[package]] -name = "metastruct" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00a5ba4a0f3453c31c397b214e1675d95b697c33763aa58add57ea833424384" -dependencies = [ - "metastruct_macro", -] - -[[package]] -name = "metastruct_macro" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a991d4536c933306e52f0e8ab303757185ec13a09d1f3e1cbde5a0d8410bf" -dependencies = [ - "darling 0.13.4", - "itertools 0.10.5", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "milhouse" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3826d3602a3674b07e080ce1982350e454ec253d73f156bd927ac1b652293f4d" -dependencies = [ - "arbitrary", - "derivative", - "ethereum-types 0.14.1", - "ethereum_hashing", - "ethereum_ssz", - "ethereum_ssz_derive", - "itertools 0.10.5", - "parking_lot 0.12.3", - "rayon", - "serde", - "smallvec", - "tree_hash", - "triomphe", - "typenum", - "vec_map", -] - [[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -3773,17 +1869,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", ] [[package]] -name = "more-asserts" -version = "0.3.1" +name = "mirai-annotations" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" +checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" [[package]] name = "multiaddr" @@ -3792,47 +1888,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261" dependencies = [ "arrayref", - "bs58 0.4.0", - "byteorder", - "data-encoding", - "multihash 0.16.3", - "percent-encoding", - "serde", - "static_assertions", - "unsigned-varint 0.7.2", - "url", -] - -[[package]] -name = "multiaddr" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" -dependencies = [ - "arrayref", + "bs58", "byteorder", "data-encoding", - "libp2p-identity", - "multibase", - "multihash 0.19.1", + "multihash", "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.8.0", + "unsigned-varint", "url", ] -[[package]] -name = "multibase" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" -dependencies = [ - "base-x", - "data-encoding", - "data-encoding-macro", -] - [[package]] name = "multihash" version = "0.16.3" @@ -3843,17 +1909,7 @@ dependencies = [ "digest 0.10.7", "multihash-derive", "sha2 0.10.8", - "unsigned-varint 0.7.2", -] - -[[package]] -name = "multihash" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" -dependencies = [ - "core2", - "unsigned-varint 0.7.2", + "unsigned-varint", ] [[package]] @@ -3877,44 +1933,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] -name = "multistream-select" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" -dependencies = [ - "bytes", - "futures", - "log", - "pin-project", - "smallvec", - "unsigned-varint 0.7.2", -] - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "overload", - "winapi", + "memchr", + "minimal-lexical", ] [[package]] @@ -3945,12 +1970,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-integer" version = "0.1.46" @@ -3987,30 +2006,10 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.82", -] - [[package]] name = "object" version = "0.36.5" @@ -4024,87 +2023,13 @@ dependencies = [ name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "openssl" -version = "0.10.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.82", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.3.2+3.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "parity-scale-codec" -version = "2.3.1" +name = "opaque-debug" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", - "serde", -] +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "parity-scale-codec" @@ -4113,25 +2038,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", - "bitvec 1.0.1", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.6.12", + "parity-scale-codec-derive", "serde", ] -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "parity-scale-codec-derive" version = "3.6.12" @@ -4144,17 +2057,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -4162,21 +2064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -4187,20 +2075,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall", "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", + "windows-targets", ] [[package]] @@ -4215,29 +2092,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" dependencies = [ - "crypto-mac 0.11.0", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", - "password-hash", - "sha2 0.10.8", -] - -[[package]] -name = "pem" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" -dependencies = [ - "base64 0.22.1", - "serde", + "crypto-mac", ] [[package]] @@ -4267,16 +2122,6 @@ dependencies = [ "indexmap 2.6.0", ] -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version 0.4.1", -] - [[package]] name = "pin-project" version = "1.1.6" @@ -4329,30 +2174,6 @@ dependencies = [ "spki 0.7.3", ] -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "polyval" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.20" @@ -4362,15 +2183,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "pretty_reqwest_error" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "reqwest 0.11.27", - "sensitive_url", -] - [[package]] name = "prettyplease" version = "0.2.24" @@ -4381,29 +2193,16 @@ dependencies = [ "syn 2.0.82", ] -[[package]] -name = "primitive-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" -dependencies = [ - "fixed-hash 0.7.0", - "impl-codec 0.5.1", - "impl-rlp", - "impl-serde 0.3.2", - "uint", -] - [[package]] name = "primitive-types" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ - "fixed-hash 0.8.0", - "impl-codec 0.6.0", + "fixed-hash", + "impl-codec", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "uint", ] @@ -4459,21 +2258,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prometheus" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" -dependencies = [ - "cfg-if", - "fnv", - "lazy_static", - "memchr", - "parking_lot 0.12.3", - "protobuf", - "thiserror", -] - [[package]] name = "proptest" version = "1.5.0" @@ -4482,13 +2266,13 @@ checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.6.0", + "bitflags", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.5", + "regex-syntax", "rusty-fork", "tempfile", "unarray", @@ -4547,27 +2331,12 @@ dependencies = [ "prost", ] -[[package]] -name = "protobuf" -version = "2.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" - [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-protobuf" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" -dependencies = [ - "byteorder", -] - [[package]] name = "quote" version = "1.0.37" @@ -4577,12 +2346,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "radium" version = "0.7.0" @@ -4628,59 +2391,13 @@ dependencies = [ "rand_core", ] -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "recvmsg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", + "bitflags", ] [[package]] @@ -4691,17 +2408,8 @@ checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -4712,106 +2420,15 @@ checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "hyper-rustls", - "hyper-tls 0.5.0", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-rustls 0.24.1", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots 0.25.4", - "winreg", -] - -[[package]] -name = "reqwest" -version = "0.12.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.4.1", - "hyper-tls 0.6.0", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.2.0", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 1.0.1", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-registry", -] - [[package]] name = "rfc6979" version = "0.3.1" @@ -4863,12 +2480,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rle-decode-fast" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" - [[package]] name = "rlp" version = "0.5.2" @@ -4879,25 +2490,6 @@ dependencies = [ "rustc-hex", ] -[[package]] -name = "rpassword" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "rpds" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ef5140bcb576bfd6d56cd2de709a7d17851ac1f3805e67fe9d99e42a11821f" -dependencies = [ - "archery", -] - [[package]] name = "ruint" version = "1.12.3" @@ -4911,8 +2503,8 @@ dependencies = [ "fastrlp", "num-bigint", "num-traits", - "parity-scale-codec 3.6.12", - "primitive-types 0.12.2", + "parity-scale-codec", + "primitive-types", "proptest", "rand", "rlp", @@ -4928,20 +2520,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" -[[package]] -name = "rusqlite" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" -dependencies = [ - "bitflags 1.3.2", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -4954,6 +2532,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -4984,7 +2568,7 @@ version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -4993,39 +2577,20 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.14" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ + "aws-lc-rs", + "log", "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.8", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -5037,19 +2602,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -5057,6 +2612,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ + "aws-lc-rs", "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", @@ -5064,9 +2620,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rusty-fork" @@ -5080,44 +2636,19 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "rw-stream-sink" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" -dependencies = [ - "futures", - "pin-project", - "static_assertions", -] - [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "safe_arith" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" - [[package]] name = "salsa20" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" dependencies = [ - "cipher 0.3.0", -] - -[[package]] -name = "schannel" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" -dependencies = [ - "windows-sys 0.59.0", + "cipher", ] [[package]] @@ -5133,21 +2664,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879588d8f90906e73302547e20fffefdd240eb3e0e744e142321f5d49dea0518" dependencies = [ "hmac 0.11.0", - "pbkdf2 0.8.0", + "pbkdf2", "salsa20", "sha2 0.9.9", ] -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - [[package]] name = "sec1" version = "0.3.0" @@ -5176,29 +2697,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "0.11.0" @@ -5223,21 +2721,6 @@ dependencies = [ "pest", ] -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - -[[package]] -name = "sensitive_url" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "serde", - "url", -] - [[package]] name = "serde" version = "1.0.210" @@ -5281,48 +2764,6 @@ dependencies = [ "syn 2.0.82", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.6.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" -dependencies = [ - "darling 0.20.10", - "proc-macro2", - "quote", - "syn 2.0.82", -] - [[package]] name = "serde_yaml" version = "0.8.26" @@ -5335,30 +2776,6 @@ dependencies = [ "yaml-rust", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap 2.6.0", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.9.9" @@ -5383,18 +2800,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] - [[package]] name = "sha3" version = "0.10.8" @@ -5415,15 +2820,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" @@ -5459,18 +2855,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - [[package]] name = "slab" version = "0.4.9" @@ -5480,124 +2864,12 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slog" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" -dependencies = [ - "erased-serde", -] - -[[package]] -name = "slog-async" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84" -dependencies = [ - "crossbeam-channel", - "slog", - "take_mut", - "thread_local", -] - -[[package]] -name = "slog-json" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1e53f61af1e3c8b852eef0a9dee29008f55d6dd63794f3f12cef786cf0f219" -dependencies = [ - "serde", - "serde_json", - "slog", - "time", -] - -[[package]] -name = "slog-kvfilter" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae939ed7d169eed9699f4f5cd440f046f5dc5dfc27c19e3cd311619594c175e0" -dependencies = [ - "regex", - "slog", -] - -[[package]] -name = "slog-scope" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f95a4b4c3274cd2869549da82b57ccc930859bdbf5bcea0424bc5f140b3c786" -dependencies = [ - "arc-swap", - "lazy_static", - "slog", -] - -[[package]] -name = "slog-stdlog" -version = "4.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6706b2ace5bbae7291d3f8d2473e2bfab073ccd7d03670946197aec98471fa3e" -dependencies = [ - "log", - "slog", - "slog-scope", -] - -[[package]] -name = "slog-term" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" -dependencies = [ - "is-terminal", - "slog", - "term", - "thread_local", - "time", -] - -[[package]] -name = "sloggers" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75062c2738b82cd45ae633623caae3393f43eb00aada1dc2d3ebe88db6b0db9b" -dependencies = [ - "chrono", - "libc", - "libflate", - "once_cell", - "regex", - "serde", - "slog", - "slog-async", - "slog-json", - "slog-kvfilter", - "slog-scope", - "slog-stdlog", - "slog-term", - "trackable", - "winapi", - "windows-acl", -] - [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -5646,7 +2918,7 @@ version = "0.9.0" source = "git+https://github.com/ralexstokes/ssz-rs?rev=84ef2b71aa004f6767420badb42c902ad56b8b72#84ef2b71aa004f6767420badb42c902ad56b8b72" dependencies = [ "alloy-primitives 0.7.7", - "bitvec 1.0.1", + "bitvec", "serde", "sha2 0.9.9", "ssz_rs_derive", @@ -5659,101 +2931,26 @@ source = "git+https://github.com/ralexstokes/ssz-rs?rev=84ef2b71aa004f6767420bad dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", -] - -[[package]] -name = "ssz_types" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625b20de2d4b3891e6972f4ce5061cb11bd52b3479270c4b177c134b571194a9" -dependencies = [ - "arbitrary", - "derivative", - "ethereum_serde_utils", - "ethereum_ssz", - "itertools 0.10.5", - "serde", - "serde_derive", - "smallvec", - "tree_hash", - "typenum", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.82", + "syn 1.0.109", ] [[package]] -name = "subtle" -version = "2.6.1" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "superstruct" -version = "0.7.0" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4e1f478a7728f8855d7e620e9a152cf8932c6614f86564c886f9b8141f3201" -dependencies = [ - "darling 0.13.4", - "itertools 0.10.5", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "swap_or_not_shuffle" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "ethereum-types 0.14.1", - "ethereum_hashing", -] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -5777,18 +2974,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syn-solidity" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" -dependencies = [ - "paste", - "proc-macro2", - "quote", - "syn 2.0.82", -] - [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5800,9 +2985,6 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" -dependencies = [ - "futures-core", -] [[package]] name = "synstructure" @@ -5816,33 +2998,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "take_mut" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" - [[package]] name = "tap" version = "1.0.1" @@ -5862,36 +3017,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "terminal_size" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" -dependencies = [ - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "test_random_derive" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "thiserror" version = "1.0.64" @@ -5912,16 +3037,6 @@ dependencies = [ "syn 2.0.82", ] -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - [[package]] name = "threadpool" version = "1.8.1" @@ -5931,56 +3046,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny-bip39" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" -dependencies = [ - "anyhow", - "hmac 0.12.1", - "once_cell", - "pbkdf2 0.11.0", - "rand", - "rustc-hash", - "sha2 0.10.8", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -6007,18 +3072,18 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", "libc", "mio", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2", "tokio-macros", "windows-sys 0.52.0", ] @@ -6034,33 +3099,13 @@ dependencies = [ "syn 2.0.82", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.14", + "rustls", "rustls-pki-types", "tokio", ] @@ -6074,23 +3119,6 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" -dependencies = [ - "futures-util", - "log", - "rustls 0.23.14", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.0", - "tungstenite", - "webpki-roots 0.26.6", ] [[package]] @@ -6103,7 +3131,6 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", - "slab", "tokio", ] @@ -6133,6 +3160,52 @@ dependencies = [ "winnow", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "rustls-pemfile", + "socket2", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "prost-types", + "quote", + "syn 2.0.82", +] + [[package]] name = "tower" version = "0.4.13" @@ -6141,13 +3214,32 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", + "indexmap 1.9.3", "pin-project", "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -6166,24 +3258,11 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror", - "time", - "tracing-subscriber", -] - [[package]] name = "tracing-attributes" version = "0.1.27" @@ -6192,97 +3271,27 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "trackable" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15bd114abb99ef8cee977e517c8f37aee63f184f2d08e3e6ceca092373369ae" -dependencies = [ - "trackable_derive", -] - -[[package]] -name = "trackable_derive" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tree_hash" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134d6b24a5b829f30b5ee7de05ba7384557f5f6b00e29409cdf2392f93201bfa" -dependencies = [ - "ethereum-types 0.14.1", - "ethereum_hashing", - "smallvec", + "syn 2.0.82", ] [[package]] -name = "tree_hash_derive" -version = "0.6.0" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce7bccc538359a213436af7bc95804bdbf1c2a21d80e22953cbe9e096837ff1" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "darling 0.13.4", - "quote", - "syn 1.0.109", + "once_cell", ] [[package]] -name = "triomphe" -version = "0.1.14" +name = "tree_hash" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +checksum = "134d6b24a5b829f30b5ee7de05ba7384557f5f6b00e29409cdf2392f93201bfa" dependencies = [ - "serde", - "stable_deref_trait", + "ethereum-types", + "ethereum_hashing", + "smallvec", ] [[package]] @@ -6291,81 +3300,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand", - "rustls 0.23.14", - "rustls-pki-types", - "sha1", - "thiserror", - "utf-8", -] - [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "types" -version = "0.2.1" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "arbitrary", - "bls", - "cached_tree_hash", - "compare_fields", - "compare_fields_derive", - "derivative", - "eth2_interop_keypairs", - "ethereum-types 0.14.1", - "ethereum_hashing", - "ethereum_serde_utils", - "ethereum_ssz", - "ethereum_ssz_derive", - "hex", - "int_to_bytes", - "itertools 0.10.5", - "kzg", - "lazy_static", - "log", - "maplit", - "merkle_proof", - "metastruct", - "milhouse", - "parking_lot 0.12.3", - "rand", - "rand_xorshift", - "rayon", - "regex", - "rpds", - "rusqlite", - "safe_arith", - "serde", - "serde_json", - "serde_yaml 0.9.34+deprecated", - "slog", - "smallvec", - "ssz_types", - "superstruct", - "swap_or_not_shuffle", - "tempfile", - "test_random_derive", - "tree_hash", - "tree_hash_derive", -] - [[package]] name = "ucd-trie" version = "0.1.7" @@ -6378,7 +3318,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ - "arbitrary", "byteorder", "crunchy", "hex", @@ -6418,34 +3357,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "universal-hash" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "unsigned-varint" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" -[[package]] -name = "unsigned-varint" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" - [[package]] name = "untrusted" version = "0.7.1" @@ -6469,12 +3386,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8parse" version = "0.2.2" @@ -6491,54 +3402,18 @@ dependencies = [ "serde", ] -[[package]] -name = "validator_dir" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" -dependencies = [ - "bls", - "deposit_contract", - "derivative", - "directory", - "eth2_keystore", - "filesystem", - "hex", - "lockfile", - "rand", - "tree_hash", - "types", -] - [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "wait-timeout" version = "0.2.0" @@ -6589,18 +3464,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.95" @@ -6630,19 +3493,6 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" -[[package]] -name = "wasm-streams" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.72" @@ -6654,42 +3504,17 @@ dependencies = [ ] [[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - -[[package]] -name = "webpki-roots" -version = "0.26.6" +name = "which" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ - "rustls-pki-types", + "either", + "home", + "once_cell", + "rustix", ] -[[package]] -name = "widestring" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" - -[[package]] -name = "widestring" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" - [[package]] name = "winapi" version = "0.3.9" @@ -6712,73 +3537,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-acl" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177b1723986bcb4c606058e77f6e8614b51c7f9ad2face6f6fd63dd5c8b3cec3" -dependencies = [ - "field-offset", - "libc", - "widestring 0.4.3", - "winapi", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-registry" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" -dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -6787,22 +3552,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -6811,46 +3561,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -6863,48 +3595,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -6920,41 +3628,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version 0.4.1", - "send_wrapper", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "wyz" version = "0.5.1" @@ -7013,52 +3686,3 @@ dependencies = [ "quote", "syn 2.0.82", ] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes 0.8.4", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac 0.12.1", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/bolt-cli/Cargo.toml b/bolt-cli/Cargo.toml index bc7de173..df182221 100644 --- a/bolt-cli/Cargo.toml +++ b/bolt-cli/Cargo.toml @@ -4,18 +4,27 @@ version = "0.1.0" edition = "2021" [dependencies] +# async +tokio = { version = "1.41.0", features = ["full"] } + +# cli clap = { version = "4.5.4", features = ["derive", "env"] } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" -ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "cf3c404" } -alloy = { version = "0.2.0", features = [ - "full", - "provider-trace-api", - "rpc-types-beacon", - "rpc-types-engine", -] } -blst = "0.3.12" + +# grpc +tonic = { version = "0.12.3", features = ["tls"] } prost = "0.13.3" +rustls = "0.23.15" + +# crypto +blst = "0.3.12" + +# ethereum +ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "cf3c404" } +lighthouse_eth2_keystore = { package = "eth2_keystore", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } +alloy-primitives = "0.8.9" +alloy-signer = "0.5.2" # utils dotenvy = "0.15.7" @@ -23,12 +32,8 @@ eyre = "0.6.12" thiserror = "1.0" hex = "0.4.3" -# lighthouse -lighthouse_eth2_keystore = { package = "eth2_keystore", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } -lighthouse_account_utils = { package = "account_utils", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } - [dev-dependencies] tempfile = "3.13.0" [build-dependencies] -prost-build = "0.13.3" +tonic-build = "0.12.3" diff --git a/bolt-cli/build.rs b/bolt-cli/build.rs index 8fd98951..1028e01e 100644 --- a/bolt-cli/build.rs +++ b/bolt-cli/build.rs @@ -1,7 +1,16 @@ +use std::{fs, io, path::Path}; + +const PB_OUT_DIR: &str = "src/pb"; + // Perform the code generation for the protobuf files. -fn main() -> std::io::Result<()> { - let mut proto_build = prost_build::Config::new(); +fn main() -> io::Result<()> { + // create the /src/pb directory if it doesn't exist + if !Path::new(PB_OUT_DIR).exists() { + fs::create_dir(PB_OUT_DIR)?; + } - proto_build.out_dir("src/pb"); - proto_build.compile_protos(&["proto/eth2-signer-api/lister.proto"], &["proto/eth2-signer-api"]) + tonic_build::configure().build_client(true).out_dir(PB_OUT_DIR).compile_protos( + &["proto/eth2-signer-api/v1/lister.proto"], + &["proto/eth2-signer-api/v1/", "proto/eth2-signer-api/"], + ) } diff --git a/bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto b/bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto deleted file mode 100644 index 196fb21b..00000000 --- a/bolt-cli/proto/eth2-signer-api/google/protobuf/descriptor.proto +++ /dev/null @@ -1,1293 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// The messages in this file describe the definitions found in .proto files. -// A valid .proto file can be translated directly to a FileDescriptorProto -// without any other information (e.g. without reading its imports). - -syntax = "proto2"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/descriptorpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; -option objc_class_prefix = "GPB"; -option cc_enable_arenas = true; - -// descriptor.proto must be optimized for speed because reflection-based -// algorithms don't work during bootstrapping. -option optimize_for = SPEED; - -// The protocol compiler can output a FileDescriptorSet containing the .proto -// files it parses. -message FileDescriptorSet { - repeated FileDescriptorProto file = 1; -} - -// The full set of known editions. -enum Edition { - // A placeholder for an unknown edition value. - EDITION_UNKNOWN = 0; - - // A placeholder edition for specifying default behaviors *before* a feature - // was first introduced. This is effectively an "infinite past". - EDITION_LEGACY = 900; - - // Legacy syntax "editions". These pre-date editions, but behave much like - // distinct editions. These can't be used to specify the edition of proto - // files, but feature definitions must supply proto2/proto3 defaults for - // backwards compatibility. - EDITION_PROTO2 = 998; - EDITION_PROTO3 = 999; - - // Editions that have been released. The specific values are arbitrary and - // should not be depended on, but they will always be time-ordered for easy - // comparison. - EDITION_2023 = 1000; - EDITION_2024 = 1001; - - // Placeholder editions for testing feature resolution. These should not be - // used or relied on outside of tests. - EDITION_1_TEST_ONLY = 1; - EDITION_2_TEST_ONLY = 2; - EDITION_99997_TEST_ONLY = 99997; - EDITION_99998_TEST_ONLY = 99998; - EDITION_99999_TEST_ONLY = 99999; - - // Placeholder for specifying unbounded edition support. This should only - // ever be used by plugins that can expect to never require any changes to - // support a new edition. - EDITION_MAX = 0x7FFFFFFF; -} - -// Describes a complete .proto file. -message FileDescriptorProto { - optional string name = 1; // file name, relative to root of source tree - optional string package = 2; // e.g. "foo", "foo.bar", etc. - - // Names of files imported by this file. - repeated string dependency = 3; - // Indexes of the public imported files in the dependency list above. - repeated int32 public_dependency = 10; - // Indexes of the weak imported files in the dependency list. - // For Google-internal migration only. Do not use. - repeated int32 weak_dependency = 11; - - // All top-level definitions in this file. - repeated DescriptorProto message_type = 4; - repeated EnumDescriptorProto enum_type = 5; - repeated ServiceDescriptorProto service = 6; - repeated FieldDescriptorProto extension = 7; - - optional FileOptions options = 8; - - // This field contains optional information about the original source code. - // You may safely remove this entire field without harming runtime - // functionality of the descriptors -- the information is needed only by - // development tools. - optional SourceCodeInfo source_code_info = 9; - - // The syntax of the proto file. - // The supported values are "proto2", "proto3", and "editions". - // - // If `edition` is present, this value must be "editions". - optional string syntax = 12; - - // The edition of the proto file. - optional Edition edition = 14; -} - -// Describes a message type. -message DescriptorProto { - optional string name = 1; - - repeated FieldDescriptorProto field = 2; - repeated FieldDescriptorProto extension = 6; - - repeated DescriptorProto nested_type = 3; - repeated EnumDescriptorProto enum_type = 4; - - message ExtensionRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - - optional ExtensionRangeOptions options = 3; - } - repeated ExtensionRange extension_range = 5; - - repeated OneofDescriptorProto oneof_decl = 8; - - optional MessageOptions options = 7; - - // Range of reserved tag numbers. Reserved tag numbers may not be used by - // fields or extension ranges in the same message. Reserved ranges may - // not overlap. - message ReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - } - repeated ReservedRange reserved_range = 9; - // Reserved field names, which may not be used by fields in the same message. - // A given name may only be reserved once. - repeated string reserved_name = 10; -} - -message ExtensionRangeOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - message Declaration { - // The extension number declared within the extension range. - optional int32 number = 1; - - // The fully-qualified name of the extension field. There must be a leading - // dot in front of the full name. - optional string full_name = 2; - - // The fully-qualified type name of the extension field. Unlike - // Metadata.type, Declaration.type must have a leading dot for messages - // and enums. - optional string type = 3; - - // If true, indicates that the number is reserved in the extension range, - // and any extension field with the number will fail to compile. Set this - // when a declared extension field is deleted. - optional bool reserved = 5; - - // If true, indicates that the extension must be defined as repeated. - // Otherwise the extension must be defined as optional. - optional bool repeated = 6; - - reserved 4; // removed is_repeated - } - - // For external users: DO NOT USE. We are in the process of open sourcing - // extension declaration and executing internal cleanups before it can be - // used externally. - repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; - - // Any features defined in the specific edition. - optional FeatureSet features = 50; - - // The verification state of the extension range. - enum VerificationState { - // All the extensions of the range must be declared. - DECLARATION = 0; - UNVERIFIED = 1; - } - - // The verification state of the range. - // TODO: flip the default to DECLARATION once all empty ranges - // are marked as UNVERIFIED. - optional VerificationState verification = 3 - [default = UNVERIFIED, retention = RETENTION_SOURCE]; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// Describes a field within a message. -message FieldDescriptorProto { - enum Type { - // 0 is reserved for errors. - // Order is weird for historical reasons. - TYPE_DOUBLE = 1; - TYPE_FLOAT = 2; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - // negative values are likely. - TYPE_INT64 = 3; - TYPE_UINT64 = 4; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - // negative values are likely. - TYPE_INT32 = 5; - TYPE_FIXED64 = 6; - TYPE_FIXED32 = 7; - TYPE_BOOL = 8; - TYPE_STRING = 9; - // Tag-delimited aggregate. - // Group type is deprecated and not supported after google.protobuf. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. In Editions, the group wire format - // can be enabled via the `message_encoding` feature. - TYPE_GROUP = 10; - TYPE_MESSAGE = 11; // Length-delimited aggregate. - - // New in version 2. - TYPE_BYTES = 12; - TYPE_UINT32 = 13; - TYPE_ENUM = 14; - TYPE_SFIXED32 = 15; - TYPE_SFIXED64 = 16; - TYPE_SINT32 = 17; // Uses ZigZag encoding. - TYPE_SINT64 = 18; // Uses ZigZag encoding. - } - - enum Label { - // 0 is reserved for errors - LABEL_OPTIONAL = 1; - LABEL_REPEATED = 3; - // The required label is only allowed in google.protobuf. In proto3 and Editions - // it's explicitly prohibited. In Editions, the `field_presence` feature - // can be used to get this behavior. - LABEL_REQUIRED = 2; - } - - optional string name = 1; - optional int32 number = 3; - optional Label label = 4; - - // If type_name is set, this need not be set. If both this and type_name - // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - optional Type type = 5; - - // For message and enum types, this is the name of the type. If the name - // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - // rules are used to find the type (i.e. first the nested types within this - // message are searched, then within the parent, on up to the root - // namespace). - optional string type_name = 6; - - // For extensions, this is the name of the type being extended. It is - // resolved in the same manner as type_name. - optional string extendee = 2; - - // For numeric types, contains the original text representation of the value. - // For booleans, "true" or "false". - // For strings, contains the default text contents (not escaped in any way). - // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - optional string default_value = 7; - - // If set, gives the index of a oneof in the containing type's oneof_decl - // list. This field is a member of that oneof. - optional int32 oneof_index = 9; - - // JSON name of this field. The value is set by protocol compiler. If the - // user has set a "json_name" option on this field, that option's value - // will be used. Otherwise, it's deduced from the field's name by converting - // it to camelCase. - optional string json_name = 10; - - optional FieldOptions options = 8; - - // If true, this is a proto3 "optional". When a proto3 field is optional, it - // tracks presence regardless of field type. - // - // When proto3_optional is true, this field must belong to a oneof to signal - // to old proto3 clients that presence is tracked for this field. This oneof - // is known as a "synthetic" oneof, and this field must be its sole member - // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs - // exist in the descriptor only, and do not generate any API. Synthetic oneofs - // must be ordered after all "real" oneofs. - // - // For message fields, proto3_optional doesn't create any semantic change, - // since non-repeated message fields always track presence. However it still - // indicates the semantic detail of whether the user wrote "optional" or not. - // This can be useful for round-tripping the .proto file. For consistency we - // give message fields a synthetic oneof also, even though it is not required - // to track presence. This is especially important because the parser can't - // tell if a field is a message or an enum, so it must always create a - // synthetic oneof. - // - // Proto2 optional fields do not set this flag, because they already indicate - // optional with `LABEL_OPTIONAL`. - optional bool proto3_optional = 17; -} - -// Describes a oneof. -message OneofDescriptorProto { - optional string name = 1; - optional OneofOptions options = 2; -} - -// Describes an enum type. -message EnumDescriptorProto { - optional string name = 1; - - repeated EnumValueDescriptorProto value = 2; - - optional EnumOptions options = 3; - - // Range of reserved numeric values. Reserved values may not be used by - // entries in the same enum. Reserved ranges may not overlap. - // - // Note that this is distinct from DescriptorProto.ReservedRange in that it - // is inclusive such that it can appropriately represent the entire int32 - // domain. - message EnumReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Inclusive. - } - - // Range of reserved numeric values. Reserved numeric values may not be used - // by enum values in the same enum declaration. Reserved ranges may not - // overlap. - repeated EnumReservedRange reserved_range = 4; - - // Reserved enum value names, which may not be reused. A given name may only - // be reserved once. - repeated string reserved_name = 5; -} - -// Describes a value within an enum. -message EnumValueDescriptorProto { - optional string name = 1; - optional int32 number = 2; - - optional EnumValueOptions options = 3; -} - -// Describes a service. -message ServiceDescriptorProto { - optional string name = 1; - repeated MethodDescriptorProto method = 2; - - optional ServiceOptions options = 3; -} - -// Describes a method of a service. -message MethodDescriptorProto { - optional string name = 1; - - // Input and output type names. These are resolved in the same way as - // FieldDescriptorProto.type_name, but must refer to a message type. - optional string input_type = 2; - optional string output_type = 3; - - optional MethodOptions options = 4; - - // Identifies if client streams multiple client messages - optional bool client_streaming = 5 [default = false]; - // Identifies if server streams multiple server messages - optional bool server_streaming = 6 [default = false]; -} - -// =================================================================== -// Options - -// Each of the definitions above may have "options" attached. These are -// just annotations which may cause code to be generated slightly differently -// or may contain hints for code that manipulates protocol messages. -// -// Clients may define custom options as extensions of the *Options messages. -// These extensions may not yet be known at parsing time, so the parser cannot -// store the values in them. Instead it stores them in a field in the *Options -// message called uninterpreted_option. This field must have the same name -// across all *Options messages. We then use this field to populate the -// extensions when we build a descriptor, at which point all protos have been -// parsed and so all extensions are known. -// -// Extension numbers for custom options may be chosen as follows: -// * For options which will only be used within a single application or -// organization, or for experimental options, use field numbers 50000 -// through 99999. It is up to you to ensure that you do not use the -// same number for multiple options. -// * For options which will be published and used publicly by multiple -// independent entities, e-mail protobuf-global-extension-registry@google.com -// to reserve extension numbers. Simply provide your project name (e.g. -// Objective-C plugin) and your project website (if available) -- there's no -// need to explain how you intend to use them. Usually you only need one -// extension number. You can declare multiple options with only one extension -// number by putting them in a sub-message. See the Custom Options section of -// the docs for examples: -// https://developers.google.com/protocol-buffers/docs/proto#options -// If this turns out to be popular, a web service will be set up -// to automatically assign option numbers. - -message FileOptions { - - // Sets the Java package where classes generated from this .proto will be - // placed. By default, the proto package is used, but this is often - // inappropriate because proto packages do not normally start with backwards - // domain names. - optional string java_package = 1; - - // Controls the name of the wrapper Java class generated for the .proto file. - // That class will always contain the .proto file's getDescriptor() method as - // well as any top-level extensions defined in the .proto file. - // If java_multiple_files is disabled, then all the other classes from the - // .proto file will be nested inside the single wrapper outer class. - optional string java_outer_classname = 8; - - // If enabled, then the Java code generator will generate a separate .java - // file for each top-level message, enum, and service defined in the .proto - // file. Thus, these types will *not* be nested inside the wrapper class - // named by java_outer_classname. However, the wrapper class will still be - // generated to contain the file's getDescriptor() method as well as any - // top-level extensions defined in the file. - optional bool java_multiple_files = 10 [default = false]; - - // This option does nothing. - optional bool java_generate_equals_and_hash = 20 [deprecated=true]; - - // A proto2 file can set this to true to opt in to UTF-8 checking for Java, - // which will throw an exception if invalid UTF-8 is parsed from the wire or - // assigned to a string field. - // - // TODO: clarify exactly what kinds of field types this option - // applies to, and update these docs accordingly. - // - // Proto3 files already perform these checks. Setting the option explicitly to - // false has no effect: it cannot be used to opt proto3 files out of UTF-8 - // checks. - optional bool java_string_check_utf8 = 27 [default = false]; - - // Generated classes can be optimized for speed or code size. - enum OptimizeMode { - SPEED = 1; // Generate complete code for parsing, serialization, - // etc. - CODE_SIZE = 2; // Use ReflectionOps to implement these methods. - LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. - } - optional OptimizeMode optimize_for = 9 [default = SPEED]; - - // Sets the Go package where structs generated from this .proto will be - // placed. If omitted, the Go package will be derived from the following: - // - The basename of the package import path, if provided. - // - Otherwise, the package statement in the .proto file, if present. - // - Otherwise, the basename of the .proto file, without extension. - optional string go_package = 11; - - // Should generic services be generated in each language? "Generic" services - // are not specific to any particular RPC system. They are generated by the - // main code generators in each language (without additional plugins). - // Generic services were the only kind of service generation supported by - // early versions of google.protobuf. - // - // Generic services are now considered deprecated in favor of using plugins - // that generate code specific to your particular RPC system. Therefore, - // these default to false. Old code which depends on generic services should - // explicitly set them to true. - optional bool cc_generic_services = 16 [default = false]; - optional bool java_generic_services = 17 [default = false]; - optional bool py_generic_services = 18 [default = false]; - reserved 42; // removed php_generic_services - reserved "php_generic_services"; - - // Is this file deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for everything in the file, or it will be completely ignored; in the very - // least, this is a formalization for deprecating files. - optional bool deprecated = 23 [default = false]; - - // Enables the use of arenas for the proto messages in this file. This applies - // only to generated classes for C++. - optional bool cc_enable_arenas = 31 [default = true]; - - // Sets the objective c class prefix which is prepended to all objective c - // generated classes from this .proto. There is no default. - optional string objc_class_prefix = 36; - - // Namespace for generated classes; defaults to the package. - optional string csharp_namespace = 37; - - // By default Swift generators will take the proto package and CamelCase it - // replacing '.' with underscore and use that to prefix the types/symbols - // defined. When this options is provided, they will use this value instead - // to prefix the types/symbols defined. - optional string swift_prefix = 39; - - // Sets the php class prefix which is prepended to all php generated classes - // from this .proto. Default is empty. - optional string php_class_prefix = 40; - - // Use this option to change the namespace of php generated classes. Default - // is empty. When this option is empty, the package name will be used for - // determining the namespace. - optional string php_namespace = 41; - - // Use this option to change the namespace of php generated metadata classes. - // Default is empty. When this option is empty, the proto file name will be - // used for determining the namespace. - optional string php_metadata_namespace = 44; - - // Use this option to change the package of ruby generated classes. Default - // is empty. When this option is not set, the package name will be used for - // determining the ruby package. - optional string ruby_package = 45; - - // Any features defined in the specific edition. - optional FeatureSet features = 50; - - // The parser stores options it doesn't recognize here. - // See the documentation for the "Options" section above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. - // See the documentation for the "Options" section above. - extensions 1000 to max; - - reserved 38; -} - -message MessageOptions { - // Set true to use the old proto1 MessageSet wire format for extensions. - // This is provided for backwards-compatibility with the MessageSet wire - // format. You should not use this for any other reason: It's less - // efficient, has fewer features, and is more complicated. - // - // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } - // Note that the message cannot have any defined fields; MessageSets only - // have extensions. - // - // All extensions of your type must be singular messages; e.g. they cannot - // be int32s, enums, or repeated messages. - // - // Because this is an option, the above two restrictions are not enforced by - // the protocol compiler. - optional bool message_set_wire_format = 1 [default = false]; - - // Disables the generation of the standard "descriptor()" accessor, which can - // conflict with a field of the same name. This is meant to make migration - // from proto1 easier; new code should avoid fields named "descriptor". - optional bool no_standard_descriptor_accessor = 2 [default = false]; - - // Is this message deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the message, or it will be completely ignored; in the very least, - // this is a formalization for deprecating messages. - optional bool deprecated = 3 [default = false]; - - reserved 4, 5, 6; - - // Whether the message is an automatically generated map entry type for the - // maps field. - // - // For maps fields: - // map map_field = 1; - // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; - // - // Implementations may choose not to generate the map_entry=true message, but - // use a native map in the target language to hold the keys and values. - // The reflection APIs in such implementations still need to work as - // if the field is a repeated message field. - // - // NOTE: Do not set the option in .proto files. Always use the maps syntax - // instead. The option should only be implicitly set by the proto compiler - // parser. - optional bool map_entry = 7; - - reserved 8; // javalite_serializable - reserved 9; // javanano_as_lite - - // Enable the legacy handling of JSON field name conflicts. This lowercases - // and strips underscored from the fields before comparison in proto3 only. - // The new behavior takes `json_name` into account and applies to proto2 as - // well. - // - // This should only be used as a temporary measure against broken builds due - // to the change in behavior for JSON field name conflicts. - // - // TODO This is legacy behavior we plan to remove once downstream - // teams have had time to migrate. - optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; - - // Any features defined in the specific edition. - optional FeatureSet features = 12; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message FieldOptions { - // NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. - // The ctype option instructs the C++ code generator to use a different - // representation of the field than it normally would. See the specific - // options below. This option is only implemented to support use of - // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - // type "bytes" in the open source release. - // TODO: make ctype actually deprecated. - optional CType ctype = 1 [/*deprecated = true,*/ default = STRING]; - enum CType { - // Default mode. - STRING = 0; - - // The option [ctype=CORD] may be applied to a non-repeated field of type - // "bytes". It indicates that in C++, the data should be stored in a Cord - // instead of a string. For very large strings, this may reduce memory - // fragmentation. It may also allow better performance when parsing from a - // Cord, or when parsing with aliasing enabled, as the parsed Cord may then - // alias the original buffer. - CORD = 1; - - STRING_PIECE = 2; - } - // The packed option can be enabled for repeated primitive fields to enable - // a more efficient representation on the wire. Rather than repeatedly - // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. This option is prohibited in - // Editions, but the `repeated_field_encoding` feature can be used to control - // the behavior. - optional bool packed = 2; - - // The jstype option determines the JavaScript type used for values of the - // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - // is represented as JavaScript string, which avoids loss of precision that - // can happen when a large value is converted to a floating point JavaScript. - // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - // use the JavaScript "number" type. The behavior of the default option - // JS_NORMAL is implementation dependent. - // - // This option is an enum to permit additional types to be added, e.g. - // goog.math.Integer. - optional JSType jstype = 6 [default = JS_NORMAL]; - enum JSType { - // Use the default type. - JS_NORMAL = 0; - - // Use JavaScript strings. - JS_STRING = 1; - - // Use JavaScript numbers. - JS_NUMBER = 2; - } - - // Should this field be parsed lazily? Lazy applies only to message-type - // fields. It means that when the outer message is initially parsed, the - // inner message's contents will not be parsed but instead stored in encoded - // form. The inner message will actually be parsed when it is first accessed. - // - // This is only a hint. Implementations are free to choose whether to use - // eager or lazy parsing regardless of the value of this option. However, - // setting this option true suggests that the protocol author believes that - // using lazy parsing on this field is worth the additional bookkeeping - // overhead typically needed to implement it. - // - // This option does not affect the public interface of any generated code; - // all method signatures remain the same. Furthermore, thread-safety of the - // interface is not affected by this option; const methods remain safe to - // call from multiple threads concurrently, while non-const methods continue - // to require exclusive access. - // - // Note that lazy message fields are still eagerly verified to check - // ill-formed wireformat or missing required fields. Calling IsInitialized() - // on the outer message would fail if the inner message has missing required - // fields. Failed verification would result in parsing failure (except when - // uninitialized messages are acceptable). - optional bool lazy = 5 [default = false]; - - // unverified_lazy does no correctness checks on the byte stream. This should - // only be used where lazy with verification is prohibitive for performance - // reasons. - optional bool unverified_lazy = 15 [default = false]; - - // Is this field deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for accessors, or it will be completely ignored; in the very least, this - // is a formalization for deprecating fields. - optional bool deprecated = 3 [default = false]; - - // For Google-internal migration only. Do not use. - optional bool weak = 10 [default = false]; - - // Indicate that the field value should not be printed out when using debug - // formats, e.g. when the field contains sensitive credentials. - optional bool debug_redact = 16 [default = false]; - - // If set to RETENTION_SOURCE, the option will be omitted from the binary. - enum OptionRetention { - RETENTION_UNKNOWN = 0; - RETENTION_RUNTIME = 1; - RETENTION_SOURCE = 2; - } - - optional OptionRetention retention = 17; - - // This indicates the types of entities that the field may apply to when used - // as an option. If it is unset, then the field may be freely used as an - // option on any kind of entity. - enum OptionTargetType { - TARGET_TYPE_UNKNOWN = 0; - TARGET_TYPE_FILE = 1; - TARGET_TYPE_EXTENSION_RANGE = 2; - TARGET_TYPE_MESSAGE = 3; - TARGET_TYPE_FIELD = 4; - TARGET_TYPE_ONEOF = 5; - TARGET_TYPE_ENUM = 6; - TARGET_TYPE_ENUM_ENTRY = 7; - TARGET_TYPE_SERVICE = 8; - TARGET_TYPE_METHOD = 9; - } - - repeated OptionTargetType targets = 19; - - message EditionDefault { - optional Edition edition = 3; - optional string value = 2; // Textproto value. - } - repeated EditionDefault edition_defaults = 20; - - // Any features defined in the specific edition. - optional FeatureSet features = 21; - - // Information about the support window of a feature. - message FeatureSupport { - // The edition that this feature was first available in. In editions - // earlier than this one, the default assigned to EDITION_LEGACY will be - // used, and proto files will not be able to override it. - optional Edition edition_introduced = 1; - - // The edition this feature becomes deprecated in. Using this after this - // edition may trigger warnings. - optional Edition edition_deprecated = 2; - - // The deprecation warning text if this feature is used after the edition it - // was marked deprecated in. - optional string deprecation_warning = 3; - - // The edition this feature is no longer available in. In editions after - // this one, the last default assigned will be used, and proto files will - // not be able to override it. - optional Edition edition_removed = 4; - } - optional FeatureSupport feature_support = 22; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; - - reserved 4; // removed jtype - reserved 18; // reserve target, target_obsolete_do_not_use -} - -message OneofOptions { - // Any features defined in the specific edition. - optional FeatureSet features = 1; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumOptions { - - // Set this option to true to allow mapping different tag names to the same - // value. - optional bool allow_alias = 2; - - // Is this enum deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum, or it will be completely ignored; in the very least, this - // is a formalization for deprecating enums. - optional bool deprecated = 3 [default = false]; - - reserved 5; // javanano_as_lite - - // Enable the legacy handling of JSON field name conflicts. This lowercases - // and strips underscored from the fields before comparison in proto3 only. - // The new behavior takes `json_name` into account and applies to proto2 as - // well. - // TODO Remove this legacy behavior once downstream teams have - // had time to migrate. - optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; - - // Any features defined in the specific edition. - optional FeatureSet features = 7; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumValueOptions { - // Is this enum value deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum value, or it will be completely ignored; in the very least, - // this is a formalization for deprecating enum values. - optional bool deprecated = 1 [default = false]; - - // Any features defined in the specific edition. - optional FeatureSet features = 2; - - // Indicate that fields annotated with this enum value should not be printed - // out when using debug formats, e.g. when the field contains sensitive - // credentials. - optional bool debug_redact = 3 [default = false]; - - // Information about the support window of a feature value. - optional FieldOptions.FeatureSupport feature_support = 4; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message ServiceOptions { - - // Any features defined in the specific edition. - optional FeatureSet features = 34; - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this service deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the service, or it will be completely ignored; in the very least, - // this is a formalization for deprecating services. - optional bool deprecated = 33 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message MethodOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this method deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the method, or it will be completely ignored; in the very least, - // this is a formalization for deprecating methods. - optional bool deprecated = 33 [default = false]; - - // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - // or neither? HTTP based RPC implementation may choose GET verb for safe - // methods, and PUT verb for idempotent methods instead of the default POST. - enum IdempotencyLevel { - IDEMPOTENCY_UNKNOWN = 0; - NO_SIDE_EFFECTS = 1; // implies idempotent - IDEMPOTENT = 2; // idempotent, but may have side effects - } - optional IdempotencyLevel idempotency_level = 34 - [default = IDEMPOTENCY_UNKNOWN]; - - // Any features defined in the specific edition. - optional FeatureSet features = 35; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// A message representing a option the parser does not recognize. This only -// appears in options protos created by the compiler::Parser class. -// DescriptorPool resolves these when building Descriptor objects. Therefore, -// options protos in descriptor objects (e.g. returned by Descriptor::options(), -// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -// in them. -message UninterpretedOption { - // The name of the uninterpreted option. Each string represents a segment in - // a dot-separated name. is_extension is true iff a segment represents an - // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents - // "foo.(bar.baz).moo". - message NamePart { - required string name_part = 1; - required bool is_extension = 2; - } - repeated NamePart name = 2; - - // The value of the uninterpreted option, in whatever type the tokenizer - // identified it as during parsing. Exactly one of these should be set. - optional string identifier_value = 3; - optional uint64 positive_int_value = 4; - optional int64 negative_int_value = 5; - optional double double_value = 6; - optional bytes string_value = 7; - optional string aggregate_value = 8; -} - -// =================================================================== -// Features - -// TODO Enums in C++ gencode (and potentially other languages) are -// not well scoped. This means that each of the feature enums below can clash -// with each other. The short names we've chosen maximize call-site -// readability, but leave us very open to this scenario. A future feature will -// be designed and implemented to handle this, hopefully before we ever hit a -// conflict here. -message FeatureSet { - enum FieldPresence { - FIELD_PRESENCE_UNKNOWN = 0; - EXPLICIT = 1; - IMPLICIT = 2; - LEGACY_REQUIRED = 3; - } - optional FieldPresence field_presence = 1 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "EXPLICIT" }, - edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" }, - edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" } - ]; - - enum EnumType { - ENUM_TYPE_UNKNOWN = 0; - OPEN = 1; - CLOSED = 2; - } - optional EnumType enum_type = 2 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "CLOSED" }, - edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" } - ]; - - enum RepeatedFieldEncoding { - REPEATED_FIELD_ENCODING_UNKNOWN = 0; - PACKED = 1; - EXPANDED = 2; - } - optional RepeatedFieldEncoding repeated_field_encoding = 3 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "EXPANDED" }, - edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" } - ]; - - enum Utf8Validation { - UTF8_VALIDATION_UNKNOWN = 0; - VERIFY = 2; - NONE = 3; - reserved 1; - } - optional Utf8Validation utf8_validation = 4 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "NONE" }, - edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" } - ]; - - enum MessageEncoding { - MESSAGE_ENCODING_UNKNOWN = 0; - LENGTH_PREFIXED = 1; - DELIMITED = 2; - } - optional MessageEncoding message_encoding = 5 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "LENGTH_PREFIXED" } - ]; - - enum JsonFormat { - JSON_FORMAT_UNKNOWN = 0; - ALLOW = 1; - LEGACY_BEST_EFFORT = 2; - } - optional JsonFormat json_format = 6 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_MESSAGE, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY_BEST_EFFORT" }, - edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" } - ]; - - reserved 999; - - extensions 1000 to 9994 [ - declaration = { - number: 1000, - full_name: ".pb.cpp", - type: ".pb.CppFeatures" - }, - declaration = { - number: 1001, - full_name: ".pb.java", - type: ".pb.JavaFeatures" - }, - declaration = { number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures" }, - declaration = { - number: 9990, - full_name: ".pb.proto1", - type: ".pb.Proto1Features" - } - ]; - - extensions 9995 to 9999; // For internal testing - extensions 10000; // for https://github.com/bufbuild/protobuf-es -} - -// A compiled specification for the defaults of a set of features. These -// messages are generated from FeatureSet extensions and can be used to seed -// feature resolution. The resolution with this object becomes a simple search -// for the closest matching edition, followed by proto merges. -message FeatureSetDefaults { - // A map from every known edition with a unique set of defaults to its - // defaults. Not all editions may be contained here. For a given edition, - // the defaults at the closest matching edition ordered at or before it should - // be used. This field must be in strict ascending order by edition. - message FeatureSetEditionDefault { - optional Edition edition = 3; - - // Defaults of features that can be overridden in this edition. - optional FeatureSet overridable_features = 4; - - // Defaults of features that can't be overridden in this edition. - optional FeatureSet fixed_features = 5; - - reserved 1, 2; - reserved "features"; - } - repeated FeatureSetEditionDefault defaults = 1; - - // The minimum supported edition (inclusive) when this was constructed. - // Editions before this will not have defaults. - optional Edition minimum_edition = 4; - - // The maximum known edition (inclusive) when this was constructed. Editions - // after this will not have reliable defaults. - optional Edition maximum_edition = 5; -} - -// =================================================================== -// Optional source code info - -// Encapsulates information about the original source file from which a -// FileDescriptorProto was generated. -message SourceCodeInfo { - // A Location identifies a piece of source code in a .proto file which - // corresponds to a particular definition. This information is intended - // to be useful to IDEs, code indexers, documentation generators, and similar - // tools. - // - // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } - // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi - // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - // - // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendant. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. - repeated Location location = 1; - message Location { - // Identifies which part of the FileDescriptorProto was defined at this - // location. - // - // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition appears. - // For example, this path: - // [ 4, 3, 2, 7, 1 ] - // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 - // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; - // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; - // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; - // - // Thus, the above path gives the location of a field name. If we removed - // the last element: - // [ 4, 3, 2, 7 ] - // this path refers to the whole field declaration (from the beginning - // of the label to the terminating semicolon). - repeated int32 path = 1 [packed = true]; - - // Always has exactly three or four elements: start line, start column, - // end line (optional, otherwise assumed same as start line), end column. - // These are packed into a single field for efficiency. Note that line - // and column numbers are zero-based -- typically you will want to add - // 1 to each before displaying to a user. - repeated int32 span = 2 [packed = true]; - - // If this SourceCodeInfo represents a complete declaration, these are any - // comments appearing before and after the declaration which appear to be - // attached to the declaration. - // - // A series of line comments appearing on consecutive lines, with no other - // tokens appearing on those lines, will be treated as a single comment. - // - // leading_detached_comments will keep paragraphs of comments that appear - // before (but not connected to) the current element. Each paragraph, - // separated by empty lines, will be one comment element in the repeated - // field. - // - // Only the comment content is provided; comment markers (e.g. //) are - // stripped out. For block comments, leading whitespace and an asterisk - // will be stripped from the beginning of each line other than the first. - // Newlines are included in the output. - // - // Examples: - // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; - // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. - // - // // Comment attached to moo. - // // - // // Another line attached to moo. - // optional double moo = 4; - // - // // Detached comment for corge. This is not leading or trailing comments - // // to moo or corge because there are blank lines separating it from - // // both. - // - // // Detached comment for corge paragraph 2. - // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; - // - // // ignored detached comments. - optional string leading_comments = 3; - optional string trailing_comments = 4; - repeated string leading_detached_comments = 6; - } -} - -// Describes the relationship between generated code and its original source -// file. A GeneratedCodeInfo message is associated with only one generated -// source file, but may contain references to different source .proto files. -message GeneratedCodeInfo { - // An Annotation connects some span of text in generated code to an element - // of its generating .proto file. - repeated Annotation annotation = 1; - message Annotation { - // Identifies the element in the original source .proto file. This field - // is formatted the same as SourceCodeInfo.Location.path. - repeated int32 path = 1 [packed = true]; - - // Identifies the filesystem path to the original source .proto. - optional string source_file = 2; - - // Identifies the starting offset in bytes in the generated code - // that relates to the identified object. - optional int32 begin = 3; - - // Identifies the ending offset in bytes in the generated code that - // relates to the identified object. The end offset should be one past - // the last relevant byte (so the length of the text = end - begin). - optional int32 end = 4; - - // Represents the identified object's effect on the element in the original - // .proto file. - enum Semantic { - // There is no effect or the effect is indescribable. - NONE = 0; - // The element is set or otherwise mutated. - SET = 1; - // An alias to the element is returned. - ALIAS = 2; - } - optional Semantic semantic = 5; - } -} \ No newline at end of file diff --git a/bolt-cli/proto/eth2-signer-api/accountmanager.proto b/bolt-cli/proto/eth2-signer-api/v1/accountmanager.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/accountmanager.proto rename to bolt-cli/proto/eth2-signer-api/v1/accountmanager.proto diff --git a/bolt-cli/proto/eth2-signer-api/dkg.proto b/bolt-cli/proto/eth2-signer-api/v1/dkg.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/dkg.proto rename to bolt-cli/proto/eth2-signer-api/v1/dkg.proto diff --git a/bolt-cli/proto/eth2-signer-api/endpoint.proto b/bolt-cli/proto/eth2-signer-api/v1/endpoint.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/endpoint.proto rename to bolt-cli/proto/eth2-signer-api/v1/endpoint.proto diff --git a/bolt-cli/proto/eth2-signer-api/eth2.proto b/bolt-cli/proto/eth2-signer-api/v1/eth2.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/eth2.proto rename to bolt-cli/proto/eth2-signer-api/v1/eth2.proto diff --git a/bolt-cli/proto/eth2-signer-api/lister.proto b/bolt-cli/proto/eth2-signer-api/v1/lister.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/lister.proto rename to bolt-cli/proto/eth2-signer-api/v1/lister.proto diff --git a/bolt-cli/proto/eth2-signer-api/responsestate.proto b/bolt-cli/proto/eth2-signer-api/v1/responsestate.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/responsestate.proto rename to bolt-cli/proto/eth2-signer-api/v1/responsestate.proto diff --git a/bolt-cli/proto/eth2-signer-api/signer.proto b/bolt-cli/proto/eth2-signer-api/v1/signer.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/signer.proto rename to bolt-cli/proto/eth2-signer-api/v1/signer.proto diff --git a/bolt-cli/proto/eth2-signer-api/walletmanager.proto b/bolt-cli/proto/eth2-signer-api/v1/walletmanager.proto similarity index 100% rename from bolt-cli/proto/eth2-signer-api/walletmanager.proto rename to bolt-cli/proto/eth2-signer-api/v1/walletmanager.proto diff --git a/bolt-cli/src/cli.rs b/bolt-cli/src/cli.rs index 9dfcabd0..c09fe2b9 100644 --- a/bolt-cli/src/cli.rs +++ b/bolt-cli/src/cli.rs @@ -38,15 +38,15 @@ pub enum Commands { source: KeySource, }, - /// Output a list of pubkeys from a keystore + /// Output a list of pubkeys in JSON format. Pubkeys { - /// The options for reading the keystore file. - #[clap(flatten)] - keystore_opts: KeystoreOpts, - /// The output file for the pubkeys. #[clap(long, env = "OUTPUT_FILE_PATH", default_value = "pubkeys.json")] out: String, + + /// The source of the private keys from which to extract the pubkeys. + #[clap(subcommand)] + source: KeySource, }, } @@ -61,25 +61,32 @@ pub enum Action { #[derive(Debug, Clone, Parser, Deserialize)] pub enum KeySource { - /// Use local private keys to generate the signed messages. - Local { - /// The private key in hex format (required if source is local). + /// Use local secret keys to generate the signed messages. + SecretKeys { + /// The private key in hex format. /// Multiple secret keys must be seperated by commas. #[clap(long, env = "SECRET_KEYS", value_delimiter = ',', hide_env_values = true)] secret_keys: Vec, }, - /// Use an EIP-2335 keystore folder to generate the signed messages. - Keystore { - /// The options for reading the keystore file. + /// Use an EIP-2335 filesystem keystore directory to generate the signed messages. + LocalKeystore { + /// The options for reading the keystore directory. #[clap(flatten)] - opts: KeystoreOpts, + opts: LocalKeystoreOpts, + }, + + /// Use a remote DIRK keystore to generate the signed messages. + Dirk { + /// The options for connecting to the DIRK keystore. + #[clap(flatten)] + opts: DirkOpts, }, } /// Options for reading a keystore folder. #[derive(Debug, Clone, Deserialize, Parser)] -pub struct KeystoreOpts { +pub struct LocalKeystoreOpts { /// The path to the keystore file. #[clap(long, env = "KEYSTORE_PATH", default_value = "validators")] pub path: String, @@ -87,12 +94,12 @@ pub struct KeystoreOpts { /// The password for the keystore files in the path. /// Assumes all keystore files have the same password. #[clap( - long, - env = "KEYSTORE_PASSWORD", - hide_env_values = true, - default_value = DEFAULT_KEYSTORE_PASSWORD, - conflicts_with = "password_path" - )] + long, + env = "KEYSTORE_PASSWORD", + hide_env_values = true, + default_value = DEFAULT_KEYSTORE_PASSWORD, + conflicts_with = "password_path" + )] pub password: Option, #[clap( @@ -104,6 +111,14 @@ pub struct KeystoreOpts { pub password_path: Option, } +/// Options for connecting to a DIRK keystore. +#[derive(Debug, Clone, Deserialize, Parser)] +pub struct DirkOpts { + /// The URL of the DIRK keystore. + #[clap(long, env = "DIRK_URL")] + pub url: String, +} + /// Supported chains for the CLI #[derive(Debug, Clone, Copy, ValueEnum, Deserialize)] #[clap(rename_all = "kebab_case")] diff --git a/bolt-cli/src/delegation.rs b/bolt-cli/src/delegation.rs index b83a4c87..15871f63 100644 --- a/bolt-cli/src/delegation.rs +++ b/bolt-cli/src/delegation.rs @@ -1,4 +1,4 @@ -use alloy::signers::k256::sha2::{Digest, Sha256}; +use alloy_signer::k256::sha2::{Digest, Sha256}; use ethereum_consensus::crypto::{ PublicKey as BlsPublicKey, SecretKey as BlsSecretKey, Signature as BlsSignature, }; @@ -21,7 +21,7 @@ use crate::{ /// - Compute the signing roots and sign the messages /// - Return the signed messages pub fn generate_from_local_keys( - secret_keys: &Vec, + secret_keys: &[String], delegatee_pubkey: BlsPublicKey, chain: &Chain, action: Action, @@ -210,7 +210,7 @@ mod tests { let keys_path = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/lighthouse/validators"; let secrets_path = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/lighthouse/secrets"; - let keystore_secret = KeystoreSecret::from_directory(secrets_path)?; + let keystore_secret = KeystoreSecret::from_directory(&secrets_path)?; let delegatee_pubkey = "0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93"; let delegatee_pubkey = parse_bls_public_key(delegatee_pubkey)?; diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index e465c0b1..d5887403 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -1,61 +1,79 @@ use clap::Parser; -use eyre::{bail, Result}; +use eyre::Result; +/// CLI commands and options. mod cli; use cli::{Commands, KeySource, Opts}; +/// Module for generating delegation/revocation messages for BLS keys. mod delegation; +/// Module for listing BLS pubkeys from various sources. +mod pubkeys; + +/// Utility functions and helpers for the CLI. mod utils; use utils::{keystore::KeystoreSecret, parse_bls_public_key, write_to_file}; -fn main() -> Result<()> { - let _ = dotenvy::dotenv(); +/// Protocol Buffers definitions generated by `prost`. +mod pb; +#[tokio::main] +async fn main() -> Result<()> { + let _ = dotenvy::dotenv(); let cli = Opts::parse(); match cli.command { Commands::Delegate { delegatee_pubkey, out, chain, source, action } => match source { - KeySource::Local { secret_keys } => { - let delegatee = parse_bls_public_key(&delegatee_pubkey)?; - let signed_messages = - delegation::generate_from_local_keys(&secret_keys, delegatee, &chain, action)?; + KeySource::SecretKeys { secret_keys } => { + let delegatee_pubkey = parse_bls_public_key(&delegatee_pubkey)?; + let signed_messages = delegation::generate_from_local_keys( + &secret_keys, + delegatee_pubkey, + &chain, + action, + )?; write_to_file(&out, &signed_messages)?; println!("Signed delegation messages generated and saved to {}", out); } - KeySource::Keystore { opts } => { - let passwords = if let Some(password_path) = opts.password_path { - KeystoreSecret::from_directory(password_path)? - } else if let Some(password) = opts.password { - KeystoreSecret::from_unique_password(password) - } else { - // This case is prevented upstream by clap's validation. - bail!("Either `password_path` or `password` must be provided") - }; - - let delegatee = parse_bls_public_key(&delegatee_pubkey)?; + KeySource::LocalKeystore { opts } => { + let keystore_secret = KeystoreSecret::from_keystore_options(&opts)?; + let delegatee_pubkey = parse_bls_public_key(&delegatee_pubkey)?; let signed_messages = delegation::generate_from_keystore( - &opts.path, passwords, delegatee, chain, action, + &opts.path, + keystore_secret, + delegatee_pubkey, + chain, + action, )?; write_to_file(&out, &signed_messages)?; println!("Signed delegation messages generated and saved to {}", out); } + KeySource::Dirk { opts } => { + todo!("generate delegations from dirk"); + } }, - Commands::Pubkeys { keystore_opts, out } => { - let passwords = if let Some(password_path) = keystore_opts.password_path { - KeystoreSecret::from_directory(password_path)? - } else if let Some(password) = keystore_opts.password { - KeystoreSecret::from_unique_password(password) - } else { - // This case is prevented upstream by clap's validation. - bail!("Either `password_path` or `password` must be provided") - }; - - // let pubkeys = utils::keystore::read_pubkeys(); - } + Commands::Pubkeys { source, out } => match source { + KeySource::SecretKeys { secret_keys } => { + let pubkeys = pubkeys::list_from_local_keys(&secret_keys)?; + + write_to_file(&out, &pubkeys)?; + println!("Pubkeys generated and saved to {}", out); + } + KeySource::LocalKeystore { opts } => { + let keystore_secret = KeystoreSecret::from_keystore_options(&opts)?; + let pubkeys = pubkeys::list_from_keystore(&opts.path, keystore_secret)?; + + write_to_file(&out, &pubkeys)?; + println!("Pubkeys generated and saved to {}", out); + } + KeySource::Dirk { opts } => { + todo!("list pubkeys from dirk"); + } + }, } Ok(()) diff --git a/bolt-cli/src/pb/google.api.rs b/bolt-cli/src/pb/google.api.rs new file mode 100644 index 00000000..243114a3 --- /dev/null +++ b/bolt-cli/src/pb/google.api.rs @@ -0,0 +1,306 @@ +// This file is @generated by prost-build. +/// Defines the HTTP configuration for an API service. It contains a list of +/// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +/// to one or more HTTP REST API methods. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Http { + /// A list of HTTP configuration rules that apply to individual API methods. + /// + /// **NOTE:** All service configuration rules follow "last one wins" order. + #[prost(message, repeated, tag = "1")] + pub rules: ::prost::alloc::vec::Vec, + /// When set to true, URL path parmeters will be fully URI-decoded except in + /// cases of single segment matches in reserved expansion, where "%2F" will be + /// left encoded. + /// + /// The default behavior is to not decode RFC 6570 reserved characters in multi + /// segment matches. + #[prost(bool, tag = "2")] + pub fully_decode_reserved_expansion: bool, +} +/// `HttpRule` defines the mapping of an RPC method to one or more HTTP +/// REST API methods. The mapping specifies how different portions of the RPC +/// request message are mapped to URL path, URL query parameters, and +/// HTTP request body. The mapping is typically specified as an +/// `google.api.http` annotation on the RPC method, +/// see "google/api/annotations.proto" for details. +/// +/// The mapping consists of a field specifying the path template and +/// method kind. The path template can refer to fields in the request +/// message, as in the example below which describes a REST GET +/// operation on a resource collection of messages: +/// +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; +/// } +/// } +/// message GetMessageRequest { +/// message SubMessage { +/// string subfield = 1; +/// } +/// string message_id = 1; // mapped to the URL +/// SubMessage sub = 2; // `sub.subfield` is url-mapped +/// } +/// message Message { +/// string text = 1; // content of the resource +/// } +/// +/// The same http annotation can alternatively be expressed inside the +/// `GRPC API Configuration` YAML file. +/// +/// http: +/// rules: +/// - selector: .Messaging.GetMessage +/// get: /v1/messages/{message_id}/{sub.subfield} +/// +/// This definition enables an automatic, bidrectional mapping of HTTP +/// JSON to RPC. Example: +/// +/// HTTP | RPC +/// -----|----- +/// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` +/// +/// In general, not only fields but also field paths can be referenced +/// from a path pattern. Fields mapped to the path pattern cannot be +/// repeated and must have a primitive (non-message) type. +/// +/// Any fields in the request message which are not bound by the path +/// pattern automatically become (optional) HTTP query +/// parameters. Assume the following definition of the request message: +/// +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http).get = "/v1/messages/{message_id}"; +/// } +/// } +/// message GetMessageRequest { +/// message SubMessage { +/// string subfield = 1; +/// } +/// string message_id = 1; // mapped to the URL +/// int64 revision = 2; // becomes a parameter +/// SubMessage sub = 3; // `sub.subfield` becomes a parameter +/// } +/// +/// +/// This enables a HTTP JSON to RPC mapping as below: +/// +/// HTTP | RPC +/// -----|----- +/// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` +/// +/// Note that fields which are mapped to HTTP parameters must have a +/// primitive type or a repeated primitive type. Message types are not +/// allowed. In the case of a repeated type, the parameter can be +/// repeated in the URL, as in `...?param=A¶m=B`. +/// +/// For HTTP method kinds which allow a request body, the `body` field +/// specifies the mapping. Consider a REST update method on the +/// message resource collection: +/// +/// +/// service Messaging { +/// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// put: "/v1/messages/{message_id}" +/// body: "message" +/// }; +/// } +/// } +/// message UpdateMessageRequest { +/// string message_id = 1; // mapped to the URL +/// Message message = 2; // mapped to the body +/// } +/// +/// +/// The following HTTP JSON to RPC mapping is enabled, where the +/// representation of the JSON in the request body is determined by +/// protos JSON encoding: +/// +/// HTTP | RPC +/// -----|----- +/// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` +/// +/// The special name `*` can be used in the body mapping to define that +/// every field not bound by the path template should be mapped to the +/// request body. This enables the following alternative definition of +/// the update method: +/// +/// service Messaging { +/// rpc UpdateMessage(Message) returns (Message) { +/// option (google.api.http) = { +/// put: "/v1/messages/{message_id}" +/// body: "*" +/// }; +/// } +/// } +/// message Message { +/// string message_id = 1; +/// string text = 2; +/// } +/// +/// +/// The following HTTP JSON to RPC mapping is enabled: +/// +/// HTTP | RPC +/// -----|----- +/// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` +/// +/// Note that when using `*` in the body mapping, it is not possible to +/// have HTTP parameters, as all fields not bound by the path end in +/// the body. This makes this option more rarely used in practice of +/// defining REST APIs. The common usage of `*` is in custom methods +/// which don't use the URL at all for transferring data. +/// +/// It is possible to define multiple HTTP methods for one RPC by using +/// the `additional_bindings` option. Example: +/// +/// service Messaging { +/// rpc GetMessage(GetMessageRequest) returns (Message) { +/// option (google.api.http) = { +/// get: "/v1/messages/{message_id}" +/// additional_bindings { +/// get: "/v1/users/{user_id}/messages/{message_id}" +/// } +/// }; +/// } +/// } +/// message GetMessageRequest { +/// string message_id = 1; +/// string user_id = 2; +/// } +/// +/// +/// This enables the following two alternative HTTP JSON to RPC +/// mappings: +/// +/// HTTP | RPC +/// -----|----- +/// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +/// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` +/// +/// # Rules for HTTP mapping +/// +/// The rules for mapping HTTP path, query parameters, and body fields +/// to the request message are as follows: +/// +/// 1. The `body` field specifies either `*` or a field path, or is +/// omitted. If omitted, it indicates there is no HTTP request body. +/// 2. Leaf fields (recursive expansion of nested messages in the +/// request) can be classified into three types: +/// (a) Matched in the URL template. +/// (b) Covered by body (if body is `*`, everything except (a) fields; +/// else everything under the body field) +/// (c) All other fields. +/// 3. URL query parameters found in the HTTP request are mapped to (c) fields. +/// 4. Any body sent with an HTTP request can contain only (b) fields. +/// +/// The syntax of the path template is as follows: +/// +/// Template = "/" Segments \[ Verb \] ; +/// Segments = Segment { "/" Segment } ; +/// Segment = "*" | "**" | LITERAL | Variable ; +/// Variable = "{" FieldPath \[ "=" Segments \] "}" ; +/// FieldPath = IDENT { "." IDENT } ; +/// Verb = ":" LITERAL ; +/// +/// The syntax `*` matches a single path segment. The syntax `**` matches zero +/// or more path segments, which must be the last part of the path except the +/// `Verb`. The syntax `LITERAL` matches literal text in the path. +/// +/// The syntax `Variable` matches part of the URL path as specified by its +/// template. A variable template must not contain other variables. If a variable +/// matches a single path segment, its template may be omitted, e.g. `{var}` +/// is equivalent to `{var=*}`. +/// +/// If a variable contains exactly one path segment, such as `"{var}"` or +/// `"{var=*}"`, when such a variable is expanded into a URL path, all characters +/// except `\[-_.~0-9a-zA-Z\]` are percent-encoded. Such variables show up in the +/// Discovery Document as `{var}`. +/// +/// If a variable contains one or more path segments, such as `"{var=foo/*}"` +/// or `"{var=**}"`, when such a variable is expanded into a URL path, all +/// characters except `\[-_.~/0-9a-zA-Z\]` are percent-encoded. Such variables +/// show up in the Discovery Document as `{+var}`. +/// +/// NOTE: While the single segment variable matches the semantics of +/// [RFC 6570]() Section 3.2.2 +/// Simple String Expansion, the multi segment variable **does not** match +/// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion +/// does not expand special characters like `?` and `#`, which would lead +/// to invalid URLs. +/// +/// NOTE: the field paths in variables and in the `body` must not refer to +/// repeated fields or map fields. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HttpRule { + /// Selects methods to which this rule applies. + /// + /// Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + #[prost(string, tag = "1")] + pub selector: ::prost::alloc::string::String, + /// The name of the request field whose value is mapped to the HTTP body, or + /// `*` for mapping all fields not captured by the path pattern to the HTTP + /// body. NOTE: the referred field must not be a repeated field and must be + /// present at the top-level of request message type. + #[prost(string, tag = "7")] + pub body: ::prost::alloc::string::String, + /// Optional. The name of the response field whose value is mapped to the HTTP + /// body of response. Other response fields are ignored. When + /// not set, the response message will be used as HTTP body of response. + #[prost(string, tag = "12")] + pub response_body: ::prost::alloc::string::String, + /// Additional HTTP bindings for the selector. Nested bindings must + /// not contain an `additional_bindings` field themselves (that is, + /// the nesting may only be one level deep). + #[prost(message, repeated, tag = "11")] + pub additional_bindings: ::prost::alloc::vec::Vec, + /// Determines the URL pattern is matched by this rules. This pattern can be + /// used with any of the {get|put|post|delete|patch} methods. A custom method + /// can be defined using the 'custom' field. + #[prost(oneof = "http_rule::Pattern", tags = "2, 3, 4, 5, 6, 8")] + pub pattern: ::core::option::Option, +} +/// Nested message and enum types in `HttpRule`. +pub mod http_rule { + /// Determines the URL pattern is matched by this rules. This pattern can be + /// used with any of the {get|put|post|delete|patch} methods. A custom method + /// can be defined using the 'custom' field. + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Pattern { + /// Used for listing and getting information about resources. + #[prost(string, tag = "2")] + Get(::prost::alloc::string::String), + /// Used for updating a resource. + #[prost(string, tag = "3")] + Put(::prost::alloc::string::String), + /// Used for creating a resource. + #[prost(string, tag = "4")] + Post(::prost::alloc::string::String), + /// Used for deleting a resource. + #[prost(string, tag = "5")] + Delete(::prost::alloc::string::String), + /// Used for updating a resource. + #[prost(string, tag = "6")] + Patch(::prost::alloc::string::String), + /// The custom pattern is used for specifying an HTTP method that is not + /// included in the `pattern` field, such as HEAD, or "*" to leave the + /// HTTP method unspecified for this rule. The wild-card rule is useful + /// for services that provide content to Web (HTML) clients. + #[prost(message, tag = "8")] + Custom(super::CustomHttpPattern), + } +} +/// A custom pattern is used for defining custom HTTP verb. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CustomHttpPattern { + /// The name of this custom HTTP verb. + #[prost(string, tag = "1")] + pub kind: ::prost::alloc::string::String, + /// The path matched by this custom verb. + #[prost(string, tag = "2")] + pub path: ::prost::alloc::string::String, +} diff --git a/bolt-cli/src/pb/mod.rs b/bolt-cli/src/pb/mod.rs new file mode 100644 index 00000000..1522b52f --- /dev/null +++ b/bolt-cli/src/pb/mod.rs @@ -0,0 +1,7 @@ +pub mod v1; + +#[allow(unused_imports)] +pub use v1::{ + lister_client::ListerClient, Account, DistributedAccount, ListAccountsRequest, + ListAccountsResponse, ResponseState, +}; diff --git a/bolt-cli/src/pb/v1.rs b/bolt-cli/src/pb/v1.rs new file mode 100644 index 00000000..673b2958 --- /dev/null +++ b/bolt-cli/src/pb/v1.rs @@ -0,0 +1,378 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Endpoint { + #[prost(uint64, tag = "1")] + pub id: u64, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(uint32, tag = "3")] + pub port: u32, +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ResponseState { + /// UNKNOWN occurs when no information about the response is available. + Unknown = 0, + /// SUCCEEDED occurs when a request was successful. + Succeeded = 1, + /// DENIED occurs when a request was denied. + Denied = 2, + /// FAILED occurs when a request failed to complete. + Failed = 3, +} +impl ResponseState { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unknown => "UNKNOWN", + Self::Succeeded => "SUCCEEDED", + Self::Denied => "DENIED", + Self::Failed => "FAILED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNKNOWN" => Some(Self::Unknown), + "SUCCEEDED" => Some(Self::Succeeded), + "DENIED" => Some(Self::Denied), + "FAILED" => Some(Self::Failed), + _ => None, + } + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListAccountsRequest { + #[prost(string, repeated, tag = "1")] + pub paths: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListAccountsResponse { + #[prost(enumeration = "ResponseState", tag = "1")] + pub state: i32, + #[prost(message, repeated, tag = "2")] + pub accounts: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub distributed_accounts: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Account { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub public_key: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "3")] + pub uuid: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DistributedAccount { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub public_key: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub participants: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "4")] + pub signing_threshold: u32, + #[prost(bytes = "vec", tag = "5")] + pub uuid: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "6")] + pub composite_public_key: ::prost::alloc::vec::Vec, +} +/// Generated client implementations. +pub mod lister_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct ListerClient { + inner: tonic::client::Grpc, + } + impl ListerClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl ListerClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> ListerClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + ListerClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn list_accounts( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/v1.Lister/ListAccounts"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.Lister", "ListAccounts")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod lister_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with ListerServer. + #[async_trait] + pub trait Lister: std::marker::Send + std::marker::Sync + 'static { + async fn list_accounts( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct ListerServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl ListerServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for ListerServer + where + T: Lister, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/v1.Lister/ListAccounts" => { + #[allow(non_camel_case_types)] + struct ListAccountsSvc(pub Arc); + impl< + T: Lister, + > tonic::server::UnaryService + for ListAccountsSvc { + type Response = super::ListAccountsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_accounts(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListAccountsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } + } + } + } + impl Clone for ListerServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "v1.Lister"; + impl tonic::server::NamedService for ListerServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/bolt-cli/src/pubkeys.rs b/bolt-cli/src/pubkeys.rs new file mode 100644 index 00000000..54afca93 --- /dev/null +++ b/bolt-cli/src/pubkeys.rs @@ -0,0 +1,36 @@ +use ethereum_consensus::crypto::bls::{PublicKey as BlsPublicKey, SecretKey as BlsSecretKey}; +use eyre::Result; +use lighthouse_eth2_keystore::Keystore; + +use crate::utils::keystore::{keystore_paths, KeystoreError, KeystoreSecret}; + +/// Derive public keys from the provided secret keys. +pub fn list_from_local_keys(secret_keys: &[String]) -> Result> { + let mut pubkeys = Vec::with_capacity(secret_keys.len()); + + for sk in secret_keys { + let sk = BlsSecretKey::try_from(sk.trim().to_string())?; + pubkeys.push(sk.public_key()); + } + + Ok(pubkeys) +} + +/// Derive public keys from the keystore files in the provided directory. +pub fn list_from_keystore( + keys_path: &str, + keystore_secret: KeystoreSecret, +) -> Result> { + let keystores_paths = keystore_paths(keys_path)?; + let mut pubkeys = Vec::with_capacity(keystores_paths.len()); + + for path in keystores_paths { + let ks = Keystore::from_json_file(path).map_err(KeystoreError::Eth2Keystore)?; + let password = keystore_secret.get(ks.pubkey()).ok_or(KeystoreError::MissingPassword)?; + let kp = ks.decrypt_keypair(password.as_bytes()).map_err(KeystoreError::Eth2Keystore)?; + let pubkey = BlsPublicKey::try_from(kp.pk.serialize().to_vec().as_ref())?; + pubkeys.push(pubkey); + } + + Ok(pubkeys) +} diff --git a/bolt-cli/src/utils/dirk.rs b/bolt-cli/src/utils/dirk.rs new file mode 100644 index 00000000..222a77ec --- /dev/null +++ b/bolt-cli/src/utils/dirk.rs @@ -0,0 +1,106 @@ +use std::fs; + +use eyre::{Context, Result}; +use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity}; + +use crate::pb::ListerClient; + +/// A Dirk remote signer. +/// +/// Reference: https://github.com/attestantio/dirk +#[derive(Clone)] +pub struct Dirk { + conn: Channel, +} + +impl Dirk { + /// Connect to the DIRK server with the given address and TLS credentials. + pub async fn connect(addr: String, credentials: TlsCredentials) -> Result { + let addr = addr.parse()?; + let tls_config = credentials.compose()?; + let conn = Channel::builder(addr).tls_config(tls_config)?.connect().await?; + + Ok(Self { conn }) + } + + pub fn list_accounts(&self) -> Result<()> { + let lister = ListerClient::new(self.conn.clone()); + + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TlsCredentials { + client_cert_path: String, + client_key_path: String, + ca_cert_path: Option, +} + +impl TlsCredentials { + pub fn new( + client_cert_path: String, + client_key_path: String, + ca_cert_path: Option, + ) -> Self { + Self { client_cert_path, client_key_path, ca_cert_path } + } + + pub fn compose(self) -> Result { + let client_cert = fs::read(self.client_cert_path).wrap_err("Failed to read client cert")?; + let client_key = fs::read(self.client_key_path).wrap_err("Failed to read client key")?; + + let ca_cert = if let Some(ca_path) = self.ca_cert_path { + Some(fs::read(ca_path).wrap_err("Failed to read CA certificate")?) + } else { + None + }; + + create_tls_config(client_cert, client_key, ca_cert) + } +} + +// Helper function to create TLS config given the certificate, key, and CA certificate. +fn create_tls_config( + client_cert: Vec, + client_key: Vec, + ca_cert: Option>, +) -> Result { + // Create client identity (certificate + key) + let identity = Identity::from_pem(&client_cert, &client_key); + + // Configure the TLS client + let mut tls_config = ClientTlsConfig::new().identity(identity); + + // Optionally add CA certificate + if let Some(ca_cert_data) = ca_cert { + let ca_cert = Certificate::from_pem(&ca_cert_data); + tls_config = tls_config.ca_certificate(ca_cert); + } + + Ok(tls_config) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_connect_to_dirk() -> eyre::Result<()> { + let url = "http://localhost:9091".to_string(); + + let test_data_dir = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/dirk"; + + let cred = TlsCredentials { + client_cert_path: test_data_dir.clone() + "/client1.crt", + client_key_path: test_data_dir.clone() + "/client1.key", + ca_cert_path: Some(test_data_dir.clone() + "/security/ca.crt"), + }; + + dbg!(&cred); + + let dirk = Dirk::connect(url, cred).await?; + + Ok(()) + } +} diff --git a/bolt-cli/src/utils/keystore.rs b/bolt-cli/src/utils/keystore.rs index 02f35cc9..26810e11 100644 --- a/bolt-cli/src/utils/keystore.rs +++ b/bolt-cli/src/utils/keystore.rs @@ -6,7 +6,9 @@ use std::{ path::{Path, PathBuf}, }; -use eyre::{Context, Result}; +use eyre::{bail, Context, ContextCompat, Result}; + +use crate::cli::LocalKeystoreOpts; /// Default password used for keystores in the test vectors. /// @@ -23,6 +25,7 @@ pub enum KeystoreError { MissingPassword, } +/// EIP-2335 keystore secret kind. pub enum KeystoreSecret { /// When using a unique password for all validators in the keystore /// (e.g. for Prysm keystore) @@ -33,14 +36,26 @@ pub enum KeystoreSecret { } impl KeystoreSecret { + /// Create a new [`KeystoreSecret`] from the provided [`LocalKeystoreOpts`]. + pub fn from_keystore_options(opts: &LocalKeystoreOpts) -> Result { + if let Some(password_path) = &opts.password_path { + Ok(KeystoreSecret::from_directory(password_path)?) + } else if let Some(password) = &opts.password { + Ok(KeystoreSecret::from_unique_password(password.clone())) + } else { + // This case is prevented upstream by clap's validation. + bail!("Either `password_path` or `password` must be provided") + } + } + /// Load the keystore passwords from a directory containing individual password files. - pub fn from_directory(root_dir: String) -> Result { + pub fn from_directory(root_dir: &str) -> Result { let mut secrets = HashMap::new(); for entry in fs::read_dir(root_dir)? { let entry = entry.wrap_err("Failed to read secrets directory entry")?; let path = entry.path(); - let filename = path.file_name().expect("secret file name").to_string_lossy(); + let filename = path.file_name().wrap_err("Secret file name")?.to_string_lossy(); let secret = fs::read_to_string(&path).wrap_err("Failed to read secret file")?; secrets.insert(filename.trim_start_matches("0x").to_string(), secret); } diff --git a/bolt-cli/src/utils/mod.rs b/bolt-cli/src/utils/mod.rs index e90260c5..efee3e63 100644 --- a/bolt-cli/src/utils/mod.rs +++ b/bolt-cli/src/utils/mod.rs @@ -4,6 +4,9 @@ use ethereum_consensus::crypto::PublicKey as BlsPublicKey; use eyre::{Context, Result}; use serde::Serialize; +/// Utilities for working with DIRK remote keystores. +pub mod dirk; + /// Utilities and types for EIP-2335 keystore files. pub mod keystore; diff --git a/bolt-cli/src/utils/signing.rs b/bolt-cli/src/utils/signing.rs index dd84e787..daee353e 100644 --- a/bolt-cli/src/utils/signing.rs +++ b/bolt-cli/src/utils/signing.rs @@ -1,4 +1,4 @@ -use alloy::primitives::B256; +use alloy_primitives::B256; use blst::{min_pk::Signature, BLST_ERROR}; use ethereum_consensus::{ crypto::PublicKey as BlsPublicKey, @@ -17,6 +17,8 @@ pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_" /// Helper function to compute the signing root for a message pub fn compute_commit_boost_signing_root(message: [u8; 32], chain: &Chain) -> Result { compute_signing_root(&message, compute_domain_from_mask(chain.fork_version())) + // Ethereum-consensus uses a different version of alloy so we need to do this cast + .map(|r| B256::from_slice(r.to_vec().as_slice())) .map_err(|e| eyre::eyre!("Failed to compute signing root: {}", e)) } diff --git a/bolt-cli/test_data/dirk/client1.crt b/bolt-cli/test_data/dirk/client1.crt new file mode 100644 index 00000000..2af82337 --- /dev/null +++ b/bolt-cli/test_data/dirk/client1.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgIUS6WAuJjrNKU6qzOR3/cxTooU9/IwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEwMjIwOTA2MjFaFw0yOTEw +MjEwOTA2MjFaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANyTDRfa37FhTG2qEPckYPR6vP1tFcUqatK1V5mhKk7p +U38dF5YtCwuNX0FH/iG4fe7w3Xavt86aVVOpUF/Vxy3becv+RThpmUbRzCN/FlfT +ZzxsEMN/VFABRarxQK24UCbjnQ7p/yHiXOeRE5pAgBanp5uKKkSq+qEo9sb7s0w9 +c6ifgXQR/GuX68yui1XiJgE3WlkTk/hvKbbOAAhuzE0x9atndbFfBRMO1Sz7zScH +HF0cp/YI2SRx5cx7ovj9biOR0hi0Af+DuHT15vznDkfMo4sAT28CeBjtXBM1eYY9 +cm6gD7zm35+kcD2xulVkw4a/AueBLOwiszclnIKULC1t4ubuwYx6Be2uGrwBy2x3 +sJh8NoMVqGqZLfVmZ7qpah1iBMsuGhH+NjZtdiKeFtU2KhOkbpUlSVHCoL3Qn8xY +eytg7IqyfXZ0YSVnE3YsAJDCOjh1vQXTK0FMkt4z4uaM8UepG5ucurhQpGcEbcSj +DLxLbHMlR4dMFNlR825OPBBVpNLxXyfsHNuftJmX0OziSS2glVjYERqRWpkglgh2 +EHL2P2R63LRMNr9qKJBdZbHzschURvcZLuNr8dqkCS83vtOhHhCH9Hyl+QZC9w+F +MgIgdbxyE0iSUwVu2gwWqoPLC9gf0rssLxySkaKXUEizpbcuyb9qnT/JlNxahaDd +AgMBAAGjcDBuMB8GA1UdIwQYMBaAFO3Lnl1Id4OcqYwhtgbFXrx6min4MAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgTwMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDAdBgNVHQ4E +FgQUWlWshAUj6JXYhYHPlSKkBCx2A9swDQYJKoZIhvcNAQELBQADggIBACuvuqA1 +aL+iiyZw8DUnPgBFHoFRbViLKLxg6Qiqv/ldvoLYKYzE5rlCuSoSRoh2cd7Du3i8 +66cRrp8eh70XiHM5P7034BdYzIo7oCHfEmVPJpo1+G85+WbNzTf2ZLNFGoeudOGw +Kvwkxb4gr2xX03EOms/w2EyVycdQ0u7Y0yaDluDhXQF2ynJYnXDGx5oIrwp9YQWF +neGSyCTP4A67QybKYaA1p1Jibhv3i4QPcFHFOSOFOidqWn01zY/TS0kxQvFpX9cB +7LjMTujHiTdZGZVHFAf9gAlMXQ1jvYdUf9r1qOXvnBOLI/aqV5fLKqgXXmqt5WFZ +bhtbUVhEu4OEavgboPOt3WUpbXSnHyVR7t/f/wtycOnfTcYcQb2dZAGRyLP/cVQt +nDBElrpUHizysNuNMa1rfd/3WC0FvC0/M2OwNK1ad9itctGKel0UrTvCU59/GO3C +P6Q2EFxyQc1wAgekkBZQX5se9RcTo8VJlV16ZMlo4tm3l57YtHwipKCVVf7EUgxu +Bsj21nBY5nOIHzaYAqF5Bz7/Lg/9IFuVx/sPatcMYmUcYkPSvm/1uRB17lr30sQp +bOKGbxzv00JFBwF0t6ZO/XnpLQiHLBtbwgGKMUak0/wZiFiZPmcdaljHLqq08fPV +S3zuTPjwU2aaQsAqAu9F/B1Cn2/gFiJEL/Mg +-----END CERTIFICATE----- diff --git a/bolt-cli/test_data/dirk/client1.key b/bolt-cli/test_data/dirk/client1.key new file mode 100644 index 00000000..7d7601a2 --- /dev/null +++ b/bolt-cli/test_data/dirk/client1.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDckw0X2t+xYUxt +qhD3JGD0erz9bRXFKmrStVeZoSpO6VN/HReWLQsLjV9BR/4huH3u8N12r7fOmlVT +qVBf1cct23nL/kU4aZlG0cwjfxZX02c8bBDDf1RQAUWq8UCtuFAm450O6f8h4lzn +kROaQIAWp6ebiipEqvqhKPbG+7NMPXOon4F0Efxrl+vMrotV4iYBN1pZE5P4bym2 +zgAIbsxNMfWrZ3WxXwUTDtUs+80nBxxdHKf2CNkkceXMe6L4/W4jkdIYtAH/g7h0 +9eb85w5HzKOLAE9vAngY7VwTNXmGPXJuoA+85t+fpHA9sbpVZMOGvwLngSzsIrM3 +JZyClCwtbeLm7sGMegXtrhq8Actsd7CYfDaDFahqmS31Zme6qWodYgTLLhoR/jY2 +bXYinhbVNioTpG6VJUlRwqC90J/MWHsrYOyKsn12dGElZxN2LACQwjo4db0F0ytB +TJLeM+LmjPFHqRubnLq4UKRnBG3Eowy8S2xzJUeHTBTZUfNuTjwQVaTS8V8n7Bzb +n7SZl9Ds4kktoJVY2BEakVqZIJYIdhBy9j9kety0TDa/aiiQXWWx87HIVEb3GS7j +a/HapAkvN77ToR4Qh/R8pfkGQvcPhTICIHW8chNIklMFbtoMFqqDywvYH9K7LC8c +kpGil1BIs6W3Lsm/ap0/yZTcWoWg3QIDAQABAoICACF+sx5MPmvROqnsiWb+Pzrg +6JITXpryNgaJQyQxNRuGkwdag5pqfKLkdPKU3CKCwZznNrovNNpK1Wo+69WhwP1V +tskjc599aak3cqhxRBNSJvsl7eXCECuWBd5PhGLc+k7tgYwiPHwIw9LmVPO3l7vY ++brE4GZNEIIollDhJ/kL2+RfVGkr0gkEqOoMF1yTWvIUVcPxFSdEujDoV1jwelW+ +oG/G5jhpFXwvZG/QTPcAPW5mS5sw/MhsA1lp7PWihncgTacyrpr+haQ9MzZ0X9bH +XI5fHbDdzx757GF+XVXlPttNsxYceRjk/6Zets0A4DA2EVrWYtv46P4W2A18Mrjr +BtEWBy/ggTrGoEc/r4WdVYz7V1vLaYOk8bDkhpsCv5WznCzg8DrzY+CFjk+BEV/S +Ib1e8iNai5JYv9Ng0X9mPkop2FHXwJnj7jt/+Hdyf4TCoOYtM0AfZDPpS2fglXi/ +9Pp9wusY01khm339yPEdPJOYjKuYa4NuQlwy4iOo+KEJIRCXvLwSxV6Eb2AZZaU1 +/1ddKU2u/wi1EdyeiNbZASOjiIC6gMhRgPX0DVCn3cPTSekV3Y82vyM8kNKyDMIc +j8qIPPFxRnqUs+/0cI64M+EPiybdtqVSCb7Qp4raMMLeFtntdqlNEkBmKZ6PRDbY +8+eMLEXcD3Kp7UQtRuCBAoIBAQD9C+WIlW7pxx88oGl0xX+BhUwO1T2Ul8zF7dfp +B0QqN62B9AIgELYJ8rcdprBDtVcFehSOgWGYMYA0tVSauqnIip0x9bsMhiO2NtX6 ++7ci9jEQw/UGfXg6EUBioG9PpgGovDo2vGMEGK1KrIEfvilhqOP04oqD8OltQQ4p +FDIC2+FFsV0mshDcuGSbWMbV/ogyg+t1NdKZT6AT7q89PHY3oMAVPRemtoLc+bfY +LPIfooDqAPTUJ/6w/hcUoGJNF1YwYXewNzNPwlqNqssfBsOIgDwCQnL+v8vo/6hj +VSHKZSFgTRj25Eo5sy4M8DFji2qlv4OZs1Hv9/lBtIdjCZA3AoIBAQDfJiDCkGNV +XI+uhKqhBCSa7HlEHFrVtoF3VPSVd4XlaCLUFON4TCPjAfTHm96dCJHbCiTu1urJ +n06P6+wTMoFv5W6xyACfuseDgzmnq0+gu5N/GqrJ9sXqe3ZG+wvOFLsuwsb/MosF +VDR3CF8Rx+rxMTMqFOolRW/vJDGB0Kl83DjlF9cb00TB+qgnZZWeR1ELBfGXMFNo +aMqkP9TjNaAwphzx+5rzY9tbPnvqzJPRjwhDx/e5khSx57FJob8OhX8QyC+yJmjK +GfTyETKxgenOh/drQyxpgybUkKqQtMYI4q6WiJ/E50U5Y7a+K5wwZ7GtUGAH0aRq +dSdr5BW5dsWLAoH/B+hXQ+1nieavEzXwFbYWRfXkapI/WmVkAMtt89pGRwt2YJk/ +d8EN70Gmd0a+O19vWLx35/wjEJ57YypHeo5av+mU//qt3bZTZ15PUYiMMIuA/QUi +oxFIsIfZezuIPvTxGFTJfOxmK7qZr7u0TUmkAWlFtmFd8sGUidV+m8oFxhEY+RSR +1KO74ynf+vrLO+S4XNvCf+curZvPZNAQqdk52IMtfXxrQMpzTHSBSkAdUN/DJ4zg +GcEmNGG8VuisKbyQ9PIWy2ruL4/jRIoRzuZnNdzMA0YQUeWseZuDp5cBd1GxuVCv +dwerSiJPThgzcujobEWP1z3DUbxuDZ+Wm4GxAoIBAQDa6ce3t/iLFIwsVCAkaDEU +/yoUJJEEGdA25lQvkZr8rEWGs5tYN7H5EME3VXV1rqOQNAp5eMPK2osy6+qkBqcu +w/DtXd0m1hDGtuTH1Wr/ryUKy3mDOqF84HPvPHefS306aYDZeJcjujDiGYdSpUKa +LX8ZKH1v5QfjniknRjIPuOfj75hqxr8sYZ+3TpQSO7qIyuLwREt/IVay/Z/26nPl +ZgD9b6zaWzsl702X0eyt59jezfz7wxCkWzz0lEYfk91M9Ga+KaohoodHNpH5zA44 +O/EA/FxEgpKEdAuwfHfO3bsTGKNMgunJXEY5mATZA9Etyqz63rKicZ4j3RVm5drz +AoIBAQCzvTWkOKNhp3MIrAp/uTbsmx76rrac1z1x6vjYteZgEtQAqlajy0AEIToi +/5Ds2psTumJ4DsHole1gi6wvYbsTOutHeSKl5pTw96+6JJfifWENZDsNvNoEk8kp +99X9cn8BBY/wrKE5hHDmfwyV7ZurZqxLsaRVBpOYoZsBxK8QzCu/7OnENI62RBaJ +ICPhHA0XnJ/tK06WhTlG4nYdLA50Q0sUqEAB/RD/kCAxIsFnHjP9ooT7STSGgmo+ +M/olWJN3eUkBLSD9uD++n7xj2gcONro6N+7dKpENzslzWNPsXEczF4R9lG+75ea4 +nJqYM6m13Q+F0Wu8krDMA65Wi5nA +-----END PRIVATE KEY----- diff --git a/bolt-cli/test_data/dirk/security/ca.crt b/bolt-cli/test_data/dirk/security/ca.crt new file mode 100644 index 00000000..b5e0e858 --- /dev/null +++ b/bolt-cli/test_data/dirk/security/ca.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUajRZTClnGXJo8F4++mVh3BuvA0wwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEwMjIwOTA0MjNaFw0yOTEw +MjEwOTA0MjNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC4Svtmk0sKkTk4hlrnWEVgJ14vVeUbb9vA0mpGDUaX +SeZiMiYGJjug6mSt1AiVSzbOWXH1Dit37q7KP44USgCg42kLKqEAgud+bg2SNAw8 +Doat+yA6xyZMl1T63oZHZN3qy5SY/m6BJECYAjij9Uw0wNpX86tBTPyNCWdDGOR7 +XN44QhDqgaRWT1j6zZJ1ilDM/v0c116JZybK74YSDI7kBw9ZRJBdpNi7aEs5oI8a +IU2KAGQxp+GE96M68m9ny+VqMR9Ihm8OuHwtHa4TxxGmVVS9K0WlQH+UbOeVON+k +yIbJRLzED1o91Qp2JzmIDE0bh3/DewYgMvKIDaGoB5v/6+TuXPD4HOBVWOeIqaq1 +myUJb73KvQG6o4FrwcdN10/3595/7tf/R/YKIEQ5HJVlFfRSIf2svqz0op0kHkaP +TVhg1IoXPm6vIs1YElVLyXwMnGrjp2HX6BHXMpoUTyTXvZ2l7keki953LdfuJ6he +NGZvkrQVlXxJf50J6XVqfdG7wpjAKxK5QMCEtveeEcrr36i3uLxEsnOstU13WMmL +xoFSIaQfwML1uZifN+PcN4jVxSPvtSXrrJdtBgojPcr5CHjnY6iyrqgi1mndXi3y +fO7dtW/gJ552uyCdWlVV/dTNTej9uhDIRJl5QMl7olODZ6O/iYkRbaOnQMP4ZACF +AwIDAQABo1MwUTAdBgNVHQ4EFgQU7cueXUh3g5ypjCG2BsVevHqaKfgwHwYDVR0j +BBgwFoAU7cueXUh3g5ypjCG2BsVevHqaKfgwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAiZeQIdvj9jWbYRBfKADAKMIQDKGhZ+fnEh+WT4EpLUyo +MrCFx1tS12iACwjo/8QoDlljriQvWeEVNxICuE8L3mwuwKc1KuzxcRV7O6tvP6Ox +vDRoy0+uPBn5Cg9Cae0SOEDN0kYqQ2YGO9cioLFfkxquzAiuh70xsJ/j523QedXw +Y234FC/EDk3dd9BvTefqxfrzwl5UIcn7uXjhorB6bw3u4eraRKlUSyICCNs6LO+X +I9xiOdjrDrwJQtjVRvpGIOOVoyGEfoj+P0hVcsuRc0AGDaFaHn1/Jpylxcrhduuw +hFXOIvx9vAGQpzSPOvUO/rFu4ofAj7mEwiHX1RN87WdhEkKVD3nddfJyeLfUObuR +kKsPucU0I0uEVJ7ymL3R7ClAFZ89sH1yStiocsxAYlhOchxbcgLvmczbvkLtQpHE +vvynNohxJThSWRhM36i5BSi8nOtVqPeXWO45eE3jEg4j/BbYZwmwDxpJjBViHS2S +XhBpJlhEMZ9jBbdq0LivGfoR5AP7HcFwm1pxR7DcJbIOBAbdHNaZF+wqSxJyMpoH ++1QJUW1ArseG45zfKNRzNO1AxDqEnRD6hurYVhOuyoh4nsTUmTa+aCRbCgtLLzwf +7z1tWIPMeUYlwLyVcDBOt1m8NLbIYfkP9tcjDJGufQ02Y3l+0/5Tv5xUXW6zuAI= +-----END CERTIFICATE----- diff --git a/bolt-cli/test_data/dirk/security/localhost.crt b/bolt-cli/test_data/dirk/security/localhost.crt new file mode 100644 index 00000000..2847974a --- /dev/null +++ b/bolt-cli/test_data/dirk/security/localhost.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgIUS6WAuJjrNKU6qzOR3/cxTooU9/EwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEwMjIwOTA1MjlaFw0yOTEw +MjEwOTA1MjlaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBALrlmq0IifUnHe8mv1uGDHkudYfZhv2ttsfGVTU3CQNN +WHsVu0Tm2JS7ressCyB9wDa0HsUKEE/b0Lfsdwk/v4A00khStTNYuCdY7cfIoloz +LzF2THDAAEGHJ3oFLy4XyxvtClIj8fZqt2ygSqiUCQh8FoJntdE46G3z7Yf/PMWF +5zpeasUbThvl4Ljwys2jj8L6e7fiWa4ir+gv5OIqkpwvdwM2CWudeF3TXC5V1c3Z +QxxPqD9ESyltfCLjy0G/Y+2326hrI7YU/44IBZ2CEbCEfcOitBjCY2jOifEorv2T +XOGH7wvt17pSRKnnvRjLWlLdONKWNJCDaMgzwEtm7N8BZXITojHWM7f5N3c386fD +e+LP9riD5W0Y84VLy/nUD0214IRcmcekVzi24RJ9vlmtMgPYCsULDXO/ZLQ9VVxq +Di3NfuEJEWtVOH5Izch0/Koq702r9/PTrAqQv3i/ph5FGizJacX8FsgzHtlPJPix +5MRTppdin/IcYkI41gBaxGvzMKAMfzALsiac7FLUbzP7HY+GbLN+GluheDBEn0CB +DRE9U1rbku9N/Rkf/I3a8UnfHGtW/JSF15o28z5+W7dehguVSOmbP4KaWgNm2cTX +QSEdvJKr23w8r+aW1gCGKlXwkxZS6GHvgmjWHhB5mJBsYujjxmg2cEPl2CjqGLTF +AgMBAAGjcDBuMB8GA1UdIwQYMBaAFO3Lnl1Id4OcqYwhtgbFXrx6min4MAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgTwMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDAdBgNVHQ4E +FgQUkjkxOfOFwdfEqOs8Sokmno68mD8wDQYJKoZIhvcNAQELBQADggIBAKo2RgA3 +2hb1ejZqbizUW8no4rX4Ok9ZYRcw/iviawWP24PzVuJIQSsHPsLOah+QWvGW/p0C +ZxsnUPhbjawF7f27BKSCrynhjsl9FwfEva3RY71iNvYO6I2JIUndcSTqA0QCLkIt +s/p7Bj+eWJ3PdoKh6kUerAZIjlmNA0XX1BFFf5QEcsESHq4JSv9KLgwPHQRbdYAa +A99oB9p/Rxeum39Bx6A+FQH5M0uhd+EMmMfa5ZsVNgLQAUcnt88q0D5o+vQVWcp4 +/6I3SmExTCCBmGmSJ4d0uzec02Pm5HjBeKo89tdVZZRtpMJe3bkVD+03jbdcXBSv +KeFqyeyCS5xXzpXZwD+5kommsOe27WgDj9XHAYMQvKoqWnM3NfS5Qsbop4KAfECZ +cmqn70p/3eT8o22G1U9uw0LMB97W660bW6bJN7K7Q1K288NABu6yqGlI32iTiJRd +6PeOhJsERik38SmgfoPNlZmi0VXuDycl/lI4MuUw+8tJ4Wggc2KA00y4J05jWf5Z +ag/dRcq6knqVykHJ9P8zVZnaHyLBT4jZItiem9iaogO5RzoGr9o1Yj+20MVUglcJ +b2i4z0BynVF+0RI38jL6reJ+UnREAEUz9yOEkHkg9ocoTKCYOY/mj1X+t7TyuQz5 +dT/migcmX+PolDOKVvY7Mn3bH1Lb+IbtydDx +-----END CERTIFICATE----- diff --git a/bolt-cli/test_data/dirk/security/localhost.key b/bolt-cli/test_data/dirk/security/localhost.key new file mode 100644 index 00000000..90413bf8 --- /dev/null +++ b/bolt-cli/test_data/dirk/security/localhost.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC65ZqtCIn1Jx3v +Jr9bhgx5LnWH2Yb9rbbHxlU1NwkDTVh7FbtE5tiUu63rLAsgfcA2tB7FChBP29C3 +7HcJP7+ANNJIUrUzWLgnWO3HyKJaMy8xdkxwwABBhyd6BS8uF8sb7QpSI/H2ards +oEqolAkIfBaCZ7XROOht8+2H/zzFhec6XmrFG04b5eC48MrNo4/C+nu34lmuIq/o +L+TiKpKcL3cDNglrnXhd01wuVdXN2UMcT6g/REspbXwi48tBv2Ptt9uoayO2FP+O +CAWdghGwhH3DorQYwmNozonxKK79k1zhh+8L7de6UkSp570Yy1pS3TjSljSQg2jI +M8BLZuzfAWVyE6Ix1jO3+Td3N/Onw3viz/a4g+VtGPOFS8v51A9NteCEXJnHpFc4 +tuESfb5ZrTID2ArFCw1zv2S0PVVcag4tzX7hCRFrVTh+SM3IdPyqKu9Nq/fz06wK +kL94v6YeRRosyWnF/BbIMx7ZTyT4seTEU6aXYp/yHGJCONYAWsRr8zCgDH8wC7Im +nOxS1G8z+x2PhmyzfhpboXgwRJ9AgQ0RPVNa25LvTf0ZH/yN2vFJ3xxrVvyUhdea +NvM+flu3XoYLlUjpmz+CmloDZtnE10EhHbySq9t8PK/mltYAhipV8JMWUuhh74Jo +1h4QeZiQbGLo48ZoNnBD5dgo6hi0xQIDAQABAoICAC5v2RgwHHMElpvysS4Q5u1/ +HSW1ZySFsnn9rfMsavlekOL4OdD7WInP/f0GMveONyGAbHrBrt7gu4HPZ54tMCwv +M6ZTooERBKSGJIJ0t94YhJvSDFkhY47kgWsAecIGmGkmYt+Y3cg/qLZ9Nz+elIX+ +qusY0KSc8qdLKdQWF2fuhs7KYdX6nFQzMDxTW9hvUMt9yBqey3CIXtOefsyxDj9v +Ta9HEF0kQaFyYB+FJTvhxRp2MlQR6GjxMpxKpBiAcNhCS/oTMMrPedW06YxCopmM +ueDPftb+CYwjcUOxu5T2tee1ijAZFvZM9ZGPqjzMXfNj0vgD6SiU9gZ0UU2K08SC +VUg9DdBlFE+FR4/L9jzu8UCZTG995b2FkADVy0Y7nHkDMqmrfj5Z0aLTYhcuBk1R +uzxxNNa1rngG4j/YldiR0dtvYdSgc52jFptpkE0cxIjMF3T33WurSsd0xzUoNiIZ +J75e3QK098ksv0wyAnkzPwnj+64encb6o91U5vT2tWM5WSPKhWa9rlybGfL6BPLG +C9lMXcaqiOwxP6UBs9SxR/jVUDPP97n2ALf10S76CdAsZN9HD14beX/7pnQc/6Y+ +q/tY0Q+cXFGHTj1I+sPmruFOG55DQc7aTSjezv1GH4NhZwUk78BKrCJ3UTDBb38S +4XTD01gJVYEAU53aO9HbAoIBAQDcmwwVmgA9FUEQBth8r/lziIuZEWKeNT86KYyp +ayGvcbxKzHVVzRvnzSz151MnrbDVT4N4InyOBTcrlCj/IiASmYnKXj/nC3su9eK8 +VhGHXbnmg34YWjggFPvAGDjGHWADz1DarI08H5KRCAtdrJLTE6sZZRpHpj0poA+k +DRmcp8t0jLhivAwVNFKIiH8Fh3bZClf08YU+Vni3JOTtUrh9p2tGBeb1HTz+BKcc +jtMsx0HNhfzQipF7k+Rjtte8uDZHiqJxToosFrim+2F07B4Hbbmv5xtYBDicHLSi +XYt0QEyH0N4mEwGBx4/IxPMR2teyhyy/erILV/+qLfbBOvmTAoIBAQDY4gjSYW/x +clg6pjUTQbel44w/+XRUJLMq5WIWyTPpLWjMnIPVmcJp5lQWfFwv6NDmp3j8iR1h +QehOEer7M0HBSyHPttT2SEf5Wx4Ir+x9dDbq3CfAyx7WafL8uc1d4ysC64wpC0EB +A2It6Hlrg15B+93W6TQPFXIgKBy7aGW830ZsQZS02ch4fY6BSJq/bbxg6WaGW2o8 +uMCFodOj8YmLWnv6OeayCztqWSYD8fcoPpN7rtovx1ZbuzWlWpsiE+SZ9i7bQo0R +IWrRfFpAeMnG8FLjoL8O+tkQzWCh5Vm8itPjDKbe1U9pUDUJ/TbNHee6KBVzaYOE +2Qudb0Dilq9HAoIBAFzTAKq2OhN5tf7AYqdUhGoQsmyd3Bkl3ozinsVKxsnD2a6/ +iT+pJmzK8Hgn9d1kQFwBMRiDqlU37JbxqK5x9XzeDhSQw+K7+gEwhU8qCAYlceuE +uLIWhDc7nRKfHoR+J8Byo1rf8C20Oz+7Wsz3qHAYfo4Y9I3hbSrupqYovPYlxH4u +GAeziIIDmhbJGGmDLob0yz3NwnsQd4rYg1s4y1hT8dds9Fl/DAL2gjqJ/mGBFjcc +gdxd8glFmXw7m1tVR8Gim+eBXLJgfSIF9GP2VkxZ5yAU5nSKkideDMOlCODJjWo4 +gMEUjjXFesLH3F9O7iO4rSOExRXw2SsKXCHCZvECggEBANVSdlTfq+izjF6bjobT +U9xiFVfzd90vf98IYdOBsYJ/vJ3MsMtPAm+BMmIvjck92QOV5CWYhAJefi0T6KmN +v/ZsfOQ+s/dOHyT/32myCA1ZWo7lXmB+KWXCLlMwOfRH9c1Ye7L/M7/YYSBAkfUS +8Io8PvYcyKyxbmB8s84NoEwG3NCsLKU5tLn23U0CadsyB2DXEZXDopn5KrwF8RJH +B/++T0VO4D9tVtKCvyaQP4chDZVQ5aCrE6EEYX6zwPTi1i4te+cD7ZbU5KkKBAd4 +Bxea2By2xlXom8qwB4UV/o65ijHABv4Ul5hBYPnjSpyz9nIe7QJo3Qi1J3yBqjN0 +/Q8CggEAFTiOan7pnfp4LVQHKQp9xFubsOikVHGpcaE2CbQ5Pr9qdAbJ1NcdsYwI +5Dk8j495cB8lWnRhX5hzP2Z/KxBSJk4VZgF0ugHpTI59XEoz4B1CuI6CpgDZhaSA +i5Kz8ol2tTWB5bEVlbz8EIqBZAtmBy2bPmvNKNohwI3NyPkFx2eWb4n/JFJKkrb2 +MVGVY+MOO1WX+crOYSEVpB9ue9gfRURooi5SApcKnZHDKLBYPGEAO6Jj/p2QaltK +OO1sn3SAkYS38CZex2SreNRxOvaNDONP8QyqSvn30r5Oz3zmxGa6aGXilmc785P3 +kkYwJXvS1QdFkYaVFutGpEVVGf6uCw== +-----END PRIVATE KEY----- From e22118fde15a1809a18df03947cf198db4735f9c Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:02:57 +0200 Subject: [PATCH 06/16] feat: list accounts from dirk --- bolt-cli/Cargo.lock | 316 +++++++++++++++++++++++++++++++++++++ bolt-cli/Cargo.toml | 3 +- bolt-cli/src/cli.rs | 22 +++ bolt-cli/src/main.rs | 14 +- bolt-cli/src/pubkeys.rs | 17 +- bolt-cli/src/utils/dirk.rs | 77 ++++----- 6 files changed, 398 insertions(+), 51 deletions(-) diff --git a/bolt-cli/Cargo.lock b/bolt-cli/Cargo.lock index ba8cd5d2..38db5ad0 100644 --- a/bolt-cli/Cargo.lock +++ b/bolt-cli/Cargo.lock @@ -606,6 +606,7 @@ dependencies = [ "eyre", "hex", "prost", + "reqwest", "rustls", "serde", "serde_json", @@ -790,6 +791,22 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "core2" version = "0.4.0" @@ -1053,6 +1070,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + [[package]] name = "enr" version = "0.6.2" @@ -1286,6 +1312,21 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1558,6 +1599,23 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.5.1" @@ -1571,6 +1629,22 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.9" @@ -1673,6 +1747,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1932,6 +2012,23 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nom" version = "7.1.3" @@ -2031,6 +2128,50 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "parity-scale-codec" version = "3.6.12" @@ -2174,6 +2315,12 @@ dependencies = [ "spki 0.7.3", ] +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -2429,6 +2576,49 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "rfc6979" version = "0.3.1" @@ -2651,6 +2841,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "schannel" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2697,6 +2896,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.11.0" @@ -2764,6 +2986,18 @@ dependencies = [ "syn 2.0.82", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_yaml" version = "0.8.26" @@ -2985,6 +3219,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -2998,6 +3235,27 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -3099,6 +3357,16 @@ dependencies = [ "syn 2.0.82", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" @@ -3408,6 +3676,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -3464,6 +3738,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.95" @@ -3537,6 +3823,36 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/bolt-cli/Cargo.toml b/bolt-cli/Cargo.toml index df182221..6d630822 100644 --- a/bolt-cli/Cargo.toml +++ b/bolt-cli/Cargo.toml @@ -13,9 +13,9 @@ serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" # grpc +rustls = { version = "0.23.15", features = ["ring"] } tonic = { version = "0.12.3", features = ["tls"] } prost = "0.13.3" -rustls = "0.23.15" # crypto blst = "0.3.12" @@ -34,6 +34,7 @@ hex = "0.4.3" [dev-dependencies] tempfile = "3.13.0" +reqwest = "0.12.8" [build-dependencies] tonic-build = "0.12.3" diff --git a/bolt-cli/src/cli.rs b/bolt-cli/src/cli.rs index c09fe2b9..f3465f0e 100644 --- a/bolt-cli/src/cli.rs +++ b/bolt-cli/src/cli.rs @@ -117,6 +117,28 @@ pub struct DirkOpts { /// The URL of the DIRK keystore. #[clap(long, env = "DIRK_URL")] pub url: String, + + /// The TLS credentials for connecting to the DIRK keystore. + #[clap(flatten)] + pub tls_credentials: TlsCredentials, + + /// The paths to the accounts in the DIRK keystore. + #[clap(long, env = "DIRK_ACCOUNTS", value_delimiter = ',', hide_env_values = true)] + pub accounts: Vec, +} + +/// TLS credentials for connecting to a remote server. +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Parser)] +pub struct TlsCredentials { + /// Path to the client certificate file. (.crt) + #[clap(long, env = "CLIENT_CERT_PATH")] + pub client_cert_path: String, + /// Path to the client key file. (.key) + #[clap(long, env = "CLIENT_KEY_PATH")] + pub client_key_path: String, + /// Path to the CA certificate file. (.crt) + #[clap(long, env = "CA_CERT_PATH")] + pub ca_cert_path: Option, } /// Supported chains for the CLI diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index d5887403..074e38f0 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -13,7 +13,7 @@ mod pubkeys; /// Utility functions and helpers for the CLI. mod utils; -use utils::{keystore::KeystoreSecret, parse_bls_public_key, write_to_file}; +use utils::{dirk::Dirk, keystore::KeystoreSecret, parse_bls_public_key, write_to_file}; /// Protocol Buffers definitions generated by `prost`. mod pb; @@ -23,6 +23,9 @@ async fn main() -> Result<()> { let _ = dotenvy::dotenv(); let cli = Opts::parse(); + // Init the default rustls provider for Dirk + let _ = rustls::crypto::ring::default_provider().install_default(); + match cli.command { Commands::Delegate { delegatee_pubkey, out, chain, source, action } => match source { KeySource::SecretKeys { secret_keys } => { @@ -52,6 +55,8 @@ async fn main() -> Result<()> { println!("Signed delegation messages generated and saved to {}", out); } KeySource::Dirk { opts } => { + let dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; + todo!("generate delegations from dirk"); } }, @@ -71,7 +76,12 @@ async fn main() -> Result<()> { println!("Pubkeys generated and saved to {}", out); } KeySource::Dirk { opts } => { - todo!("list pubkeys from dirk"); + let dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; + let accounts = dirk.list_accounts(opts.accounts).await?; + let pubkeys = pubkeys::list_from_dirk_accounts(&accounts)?; + + write_to_file(&out, &pubkeys)?; + println!("Pubkeys generated and saved to {}", out); } }, } diff --git a/bolt-cli/src/pubkeys.rs b/bolt-cli/src/pubkeys.rs index 54afca93..78ee7e96 100644 --- a/bolt-cli/src/pubkeys.rs +++ b/bolt-cli/src/pubkeys.rs @@ -2,7 +2,10 @@ use ethereum_consensus::crypto::bls::{PublicKey as BlsPublicKey, SecretKey as Bl use eyre::Result; use lighthouse_eth2_keystore::Keystore; -use crate::utils::keystore::{keystore_paths, KeystoreError, KeystoreSecret}; +use crate::{ + pb::Account, + utils::keystore::{keystore_paths, KeystoreError, KeystoreSecret}, +}; /// Derive public keys from the provided secret keys. pub fn list_from_local_keys(secret_keys: &[String]) -> Result> { @@ -34,3 +37,15 @@ pub fn list_from_keystore( Ok(pubkeys) } + +/// Derive public keys from the provided dirk accounts. +pub fn list_from_dirk_accounts(accounts: &[Account]) -> Result> { + let mut pubkeys = Vec::with_capacity(accounts.len()); + + for acc in accounts { + let pubkey = BlsPublicKey::try_from(acc.public_key.as_slice())?; + pubkeys.push(pubkey); + } + + Ok(pubkeys) +} diff --git a/bolt-cli/src/utils/dirk.rs b/bolt-cli/src/utils/dirk.rs index 222a77ec..f9304887 100644 --- a/bolt-cli/src/utils/dirk.rs +++ b/bolt-cli/src/utils/dirk.rs @@ -3,7 +3,10 @@ use std::fs; use eyre::{Context, Result}; use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity}; -use crate::pb::ListerClient; +use crate::{ + cli::TlsCredentials, + pb::{Account, ListAccountsRequest, ListerClient}, +}; /// A Dirk remote signer. /// @@ -17,65 +20,36 @@ impl Dirk { /// Connect to the DIRK server with the given address and TLS credentials. pub async fn connect(addr: String, credentials: TlsCredentials) -> Result { let addr = addr.parse()?; - let tls_config = credentials.compose()?; + let tls_config = compose_credentials(credentials)?; let conn = Channel::builder(addr).tls_config(tls_config)?.connect().await?; Ok(Self { conn }) } - pub fn list_accounts(&self) -> Result<()> { - let lister = ListerClient::new(self.conn.clone()); + /// List all accounts in the keystore. + pub async fn list_accounts(&self, paths: Vec) -> Result> { + let mut lister = ListerClient::new(self.conn.clone()); + let accs = lister.list_accounts(ListAccountsRequest { paths }).await?; - Ok(()) + Ok(accs.into_inner().accounts) } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TlsCredentials { - client_cert_path: String, - client_key_path: String, - ca_cert_path: Option, -} - -impl TlsCredentials { - pub fn new( - client_cert_path: String, - client_key_path: String, - ca_cert_path: Option, - ) -> Self { - Self { client_cert_path, client_key_path, ca_cert_path } - } - - pub fn compose(self) -> Result { - let client_cert = fs::read(self.client_cert_path).wrap_err("Failed to read client cert")?; - let client_key = fs::read(self.client_key_path).wrap_err("Failed to read client key")?; - - let ca_cert = if let Some(ca_path) = self.ca_cert_path { - Some(fs::read(ca_path).wrap_err("Failed to read CA certificate")?) - } else { - None - }; +/// Compose the TLS credentials from the given paths. +fn compose_credentials(creds: TlsCredentials) -> Result { + let client_cert = fs::read(creds.client_cert_path).wrap_err("Failed to read client cert")?; + let client_key = fs::read(creds.client_key_path).wrap_err("Failed to read client key")?; - create_tls_config(client_cert, client_key, ca_cert) - } -} - -// Helper function to create TLS config given the certificate, key, and CA certificate. -fn create_tls_config( - client_cert: Vec, - client_key: Vec, - ca_cert: Option>, -) -> Result { // Create client identity (certificate + key) let identity = Identity::from_pem(&client_cert, &client_key); // Configure the TLS client let mut tls_config = ClientTlsConfig::new().identity(identity); - // Optionally add CA certificate - if let Some(ca_cert_data) = ca_cert { - let ca_cert = Certificate::from_pem(&ca_cert_data); - tls_config = tls_config.ca_certificate(ca_cert); + // Add CA certificate if provided + if let Some(ca_path) = creds.ca_cert_path { + let ca_cert = fs::read(ca_path).wrap_err("Failed to read CA certificate")?; + tls_config = tls_config.ca_certificate(Certificate::from_pem(&ca_cert)); } Ok(tls_config) @@ -85,9 +59,17 @@ fn create_tls_config( mod tests { use super::*; + /// Test connecting to a DIRK server + /// + /// This test should be run manually against a running DIRK server. + /// Eventually this could become part of the entire test setup but for now it's ignored. #[tokio::test] + #[ignore] async fn test_connect_to_dirk() -> eyre::Result<()> { - let url = "http://localhost:9091".to_string(); + // Init the default rustls provider + let _ = rustls::crypto::ring::default_provider().install_default(); + + let url = "https://localhost:9091".to_string(); let test_data_dir = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/dirk"; @@ -97,10 +79,11 @@ mod tests { ca_cert_path: Some(test_data_dir.clone() + "/security/ca.crt"), }; - dbg!(&cred); - let dirk = Dirk::connect(url, cred).await?; + let accounts = dirk.list_accounts(vec!["wallet1".to_string()]).await?; + println!("Dirk Accounts: {:?}", accounts); + Ok(()) } } From 98608b737e470dc85245772d1e5f7c60368e849a Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:07:35 +0200 Subject: [PATCH 07/16] chore: small fixes --- bolt-cli/src/cli.rs | 1 + bolt-cli/src/main.rs | 2 +- bolt-cli/test_data/README.md | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bolt-cli/src/cli.rs b/bolt-cli/src/cli.rs index f3465f0e..1b152126 100644 --- a/bolt-cli/src/cli.rs +++ b/bolt-cli/src/cli.rs @@ -52,6 +52,7 @@ pub enum Commands { /// The action to perform. #[derive(Debug, Clone, ValueEnum, Deserialize)] +#[clap(rename_all = "kebab_case")] pub enum Action { /// Create a delegation message. Delegate, diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index 074e38f0..fd72bbab 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -55,7 +55,7 @@ async fn main() -> Result<()> { println!("Signed delegation messages generated and saved to {}", out); } KeySource::Dirk { opts } => { - let dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; + let _dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; todo!("generate delegations from dirk"); } diff --git a/bolt-cli/test_data/README.md b/bolt-cli/test_data/README.md index fc94ba75..e1e4fd7f 100644 --- a/bolt-cli/test_data/README.md +++ b/bolt-cli/test_data/README.md @@ -1,7 +1,11 @@ # test data for the bolt cli tool -- `lighthouse`: A lighthouse-format keystore according to the [specs][lh-specs]. +- [`lighthouse`](./lighthouse/): A lighthouse-format keystore according to the [specs][lh-specs]. It contains two directories: `validators` for the voting-keystores, and `secrets` for the passwords needed to decrypt the keypairs. +- [`dirk`](./dirk/): A directory containing test TLS certificates and keys for authenticating a test [Dirk][dirk] + server on localhost. The certificates are self-signed for test purposes and are not to be used in production. + [lh-specs]: https://lighthouse-book.sigmaprime.io/validator-management.html#automatic-validator-discovery +[dirk]: https://github.com/attestantio/dirk From fd1120e61d81ae00b183e7851435991d04e003c8 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:22:32 +0200 Subject: [PATCH 08/16] wip: signature request --- bolt-cli/build.rs | 2 +- bolt-cli/src/pb/mod.rs | 17 +- bolt-cli/src/pb/v1.rs | 690 +++++++++++++++++++++++++++++++++++++ bolt-cli/src/pubkeys.rs | 2 +- bolt-cli/src/utils/dirk.rs | 28 +- 5 files changed, 730 insertions(+), 9 deletions(-) diff --git a/bolt-cli/build.rs b/bolt-cli/build.rs index 1028e01e..07c7d446 100644 --- a/bolt-cli/build.rs +++ b/bolt-cli/build.rs @@ -10,7 +10,7 @@ fn main() -> io::Result<()> { } tonic_build::configure().build_client(true).out_dir(PB_OUT_DIR).compile_protos( - &["proto/eth2-signer-api/v1/lister.proto"], + &["proto/eth2-signer-api/v1/lister.proto", "proto/eth2-signer-api/v1/signer.proto"], &["proto/eth2-signer-api/v1/", "proto/eth2-signer-api/"], ) } diff --git a/bolt-cli/src/pb/mod.rs b/bolt-cli/src/pb/mod.rs index 1522b52f..435dccf7 100644 --- a/bolt-cli/src/pb/mod.rs +++ b/bolt-cli/src/pb/mod.rs @@ -1,7 +1,12 @@ -pub mod v1; +mod v1; -#[allow(unused_imports)] -pub use v1::{ - lister_client::ListerClient, Account, DistributedAccount, ListAccountsRequest, - ListAccountsResponse, ResponseState, -}; +/// Re-exported protobuf API for the ETH2 remote signer service. +pub mod eth2_signer_api { + + #[allow(unused_imports)] + pub use super::v1::{ + lister_client::ListerClient, sign_request::Id as SignRequestId, + signer_client::SignerClient, Account, DistributedAccount, ListAccountsRequest, + ListAccountsResponse, ResponseState, SignRequest, SignResponse, + }; +} diff --git a/bolt-cli/src/pb/v1.rs b/bolt-cli/src/pb/v1.rs index 673b2958..a4e1e7a8 100644 --- a/bolt-cli/src/pb/v1.rs +++ b/bolt-cli/src/pb/v1.rs @@ -376,3 +376,693 @@ pub mod lister_server { const NAME: &'static str = SERVICE_NAME; } } +/// AttestationData is defined at +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AttestationData { + #[prost(uint64, tag = "1")] + pub slot: u64, + #[prost(uint64, tag = "2")] + pub committee_index: u64, + #[prost(bytes = "vec", tag = "3")] + pub beacon_block_root: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "4")] + pub source: ::core::option::Option, + #[prost(message, optional, tag = "5")] + pub target: ::core::option::Option, +} +/// Checkpoint is defined at +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Checkpoint { + #[prost(uint64, tag = "1")] + pub epoch: u64, + #[prost(bytes = "vec", tag = "2")] + pub root: ::prost::alloc::vec::Vec, +} +/// BeaconBlockheader is defined at +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BeaconBlockHeader { + #[prost(uint64, tag = "1")] + pub slot: u64, + #[prost(uint64, tag = "2")] + pub proposer_index: u64, + #[prost(bytes = "vec", tag = "3")] + pub parent_root: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "4")] + pub state_root: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "5")] + pub body_root: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignRequest { + #[prost(bytes = "vec", tag = "3")] + pub data: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "4")] + pub domain: ::prost::alloc::vec::Vec, + #[prost(oneof = "sign_request::Id", tags = "1, 2")] + pub id: ::core::option::Option, +} +/// Nested message and enum types in `SignRequest`. +pub mod sign_request { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Id { + #[prost(bytes, tag = "1")] + PublicKey(::prost::alloc::vec::Vec), + #[prost(string, tag = "2")] + Account(::prost::alloc::string::String), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MultisignRequest { + #[prost(message, repeated, tag = "1")] + pub requests: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignBeaconAttestationRequest { + #[prost(bytes = "vec", tag = "3")] + pub domain: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "4")] + pub data: ::core::option::Option, + #[prost(oneof = "sign_beacon_attestation_request::Id", tags = "1, 2")] + pub id: ::core::option::Option, +} +/// Nested message and enum types in `SignBeaconAttestationRequest`. +pub mod sign_beacon_attestation_request { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Id { + #[prost(bytes, tag = "1")] + PublicKey(::prost::alloc::vec::Vec), + #[prost(string, tag = "2")] + Account(::prost::alloc::string::String), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignBeaconAttestationsRequest { + #[prost(message, repeated, tag = "1")] + pub requests: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignBeaconProposalRequest { + #[prost(bytes = "vec", tag = "3")] + pub domain: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag = "4")] + pub data: ::core::option::Option, + #[prost(oneof = "sign_beacon_proposal_request::Id", tags = "1, 2")] + pub id: ::core::option::Option, +} +/// Nested message and enum types in `SignBeaconProposalRequest`. +pub mod sign_beacon_proposal_request { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Id { + #[prost(bytes, tag = "1")] + PublicKey(::prost::alloc::vec::Vec), + #[prost(string, tag = "2")] + Account(::prost::alloc::string::String), + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SignResponse { + #[prost(enumeration = "ResponseState", tag = "1")] + pub state: i32, + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MultisignResponse { + #[prost(message, repeated, tag = "1")] + pub responses: ::prost::alloc::vec::Vec, +} +/// Generated client implementations. +pub mod signer_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct SignerClient { + inner: tonic::client::Grpc, + } + impl SignerClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl SignerClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> SignerClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + SignerClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn sign( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/v1.Signer/Sign"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.Signer", "Sign")); + self.inner.unary(req, path, codec).await + } + pub async fn multisign( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/v1.Signer/Multisign"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.Signer", "Multisign")); + self.inner.unary(req, path, codec).await + } + pub async fn sign_beacon_attestation( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/v1.Signer/SignBeaconAttestation", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("v1.Signer", "SignBeaconAttestation")); + self.inner.unary(req, path, codec).await + } + pub async fn sign_beacon_attestations( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/v1.Signer/SignBeaconAttestations", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("v1.Signer", "SignBeaconAttestations")); + self.inner.unary(req, path, codec).await + } + pub async fn sign_beacon_proposal( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/v1.Signer/SignBeaconProposal", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("v1.Signer", "SignBeaconProposal")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod signer_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with SignerServer. + #[async_trait] + pub trait Signer: std::marker::Send + std::marker::Sync + 'static { + async fn sign( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn multisign( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn sign_beacon_attestation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn sign_beacon_attestations( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn sign_beacon_proposal( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + } + #[derive(Debug)] + pub struct SignerServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl SignerServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for SignerServer + where + T: Signer, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/v1.Signer/Sign" => { + #[allow(non_camel_case_types)] + struct SignSvc(pub Arc); + impl tonic::server::UnaryService + for SignSvc { + type Response = super::SignResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sign(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SignSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/v1.Signer/Multisign" => { + #[allow(non_camel_case_types)] + struct MultisignSvc(pub Arc); + impl tonic::server::UnaryService + for MultisignSvc { + type Response = super::MultisignResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::multisign(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = MultisignSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/v1.Signer/SignBeaconAttestation" => { + #[allow(non_camel_case_types)] + struct SignBeaconAttestationSvc(pub Arc); + impl< + T: Signer, + > tonic::server::UnaryService + for SignBeaconAttestationSvc { + type Response = super::SignResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sign_beacon_attestation(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SignBeaconAttestationSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/v1.Signer/SignBeaconAttestations" => { + #[allow(non_camel_case_types)] + struct SignBeaconAttestationsSvc(pub Arc); + impl< + T: Signer, + > tonic::server::UnaryService + for SignBeaconAttestationsSvc { + type Response = super::MultisignResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sign_beacon_attestations(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SignBeaconAttestationsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/v1.Signer/SignBeaconProposal" => { + #[allow(non_camel_case_types)] + struct SignBeaconProposalSvc(pub Arc); + impl< + T: Signer, + > tonic::server::UnaryService + for SignBeaconProposalSvc { + type Response = super::SignResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sign_beacon_proposal(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SignBeaconProposalSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } + } + } + } + impl Clone for SignerServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "v1.Signer"; + impl tonic::server::NamedService for SignerServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/bolt-cli/src/pubkeys.rs b/bolt-cli/src/pubkeys.rs index 78ee7e96..c06eef8d 100644 --- a/bolt-cli/src/pubkeys.rs +++ b/bolt-cli/src/pubkeys.rs @@ -3,7 +3,7 @@ use eyre::Result; use lighthouse_eth2_keystore::Keystore; use crate::{ - pb::Account, + pb::eth2_signer_api::Account, utils::keystore::{keystore_paths, KeystoreError, KeystoreSecret}, }; diff --git a/bolt-cli/src/utils/dirk.rs b/bolt-cli/src/utils/dirk.rs index f9304887..52f38df9 100644 --- a/bolt-cli/src/utils/dirk.rs +++ b/bolt-cli/src/utils/dirk.rs @@ -1,11 +1,15 @@ use std::fs; +use alloy_primitives::B256; +use ethereum_consensus::crypto::bls::{PublicKey as BlsPublicKey, Signature as BlsSignature}; use eyre::{Context, Result}; use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity}; use crate::{ cli::TlsCredentials, - pb::{Account, ListAccountsRequest, ListerClient}, + pb::eth2_signer_api::{ + Account, ListAccountsRequest, ListerClient, SignRequest, SignRequestId, SignerClient, + }, }; /// A Dirk remote signer. @@ -33,6 +37,28 @@ impl Dirk { Ok(accs.into_inner().accounts) } + + /// Request a signature from the remote signer. + pub async fn request_signature( + &self, + pubkey: BlsPublicKey, + hash: B256, + domain: B256, + ) -> Result { + let mut signer = SignerClient::new(self.conn.clone()); + + let req = SignRequest { + data: hash.to_vec(), + domain: domain.to_vec(), + id: Some(SignRequestId::PublicKey(pubkey.to_vec())), + }; + + let res = signer.sign(req).await?; + let sig = res.into_inner().signature; + let sig = BlsSignature::try_from(sig.as_slice()).wrap_err("Failed to parse signature")?; + + Ok(sig) + } } /// Compose the TLS credentials from the given paths. From abeb889e113f816cc900b0f5de5796c37b444438 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:29:11 +0200 Subject: [PATCH 09/16] feat: initial delegation + e2e test --- bolt-cli/Cargo.lock | 63 +++++++++++++++++ bolt-cli/Cargo.toml | 2 + bolt-cli/src/delegation.rs | 46 +++++++++++- bolt-cli/src/main.rs | 20 +++++- bolt-cli/src/utils/dirk.rs | 74 +++++++++++++++----- bolt-cli/test_data/dirk/.gitignore | 1 + bolt-cli/test_data/dirk/dirk.template.json | 23 ++++++ bolt-cli/test_data/dirk/storage/000000.vlog | Bin 0 -> 20 bytes bolt-cli/test_data/dirk/storage/KEYREGISTRY | 1 + bolt-cli/test_data/dirk/storage/LOCK | 1 + bolt-cli/test_data/dirk/storage/MANIFEST | Bin 0 -> 16 bytes 11 files changed, 211 insertions(+), 20 deletions(-) create mode 100644 bolt-cli/test_data/dirk/.gitignore create mode 100644 bolt-cli/test_data/dirk/dirk.template.json create mode 100644 bolt-cli/test_data/dirk/storage/000000.vlog create mode 100644 bolt-cli/test_data/dirk/storage/KEYREGISTRY create mode 100644 bolt-cli/test_data/dirk/storage/LOCK create mode 100644 bolt-cli/test_data/dirk/storage/MANIFEST diff --git a/bolt-cli/Cargo.lock b/bolt-cli/Cargo.lock index 38db5ad0..c514aedc 100644 --- a/bolt-cli/Cargo.lock +++ b/bolt-cli/Cargo.lock @@ -615,6 +615,8 @@ dependencies = [ "tokio", "tonic", "tonic-build", + "tracing", + "tracing-subscriber", ] [[package]] @@ -2039,6 +2041,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -2172,6 +2184,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parity-scale-codec" version = "3.6.12" @@ -3054,6 +3072,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -3295,6 +3322,16 @@ dependencies = [ "syn 2.0.82", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "threadpool" version = "1.8.1" @@ -3549,6 +3586,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] diff --git a/bolt-cli/Cargo.toml b/bolt-cli/Cargo.toml index 6d630822..edf24d76 100644 --- a/bolt-cli/Cargo.toml +++ b/bolt-cli/Cargo.toml @@ -31,6 +31,8 @@ dotenvy = "0.15.7" eyre = "0.6.12" thiserror = "1.0" hex = "0.4.3" +tracing = "0.1.40" +tracing-subscriber = "0.3.18" [dev-dependencies] tempfile = "3.13.0" diff --git a/bolt-cli/src/delegation.rs b/bolt-cli/src/delegation.rs index 15871f63..46b3cded 100644 --- a/bolt-cli/src/delegation.rs +++ b/bolt-cli/src/delegation.rs @@ -5,12 +5,14 @@ use ethereum_consensus::crypto::{ use eyre::Result; use lighthouse_eth2_keystore::Keystore; use serde::Serialize; +use tracing::debug; use crate::{ cli::{Action, Chain}, utils::{ + dirk::Dirk, keystore::{keystore_paths, KeystoreError, KeystoreSecret}, - signing::compute_commit_boost_signing_root, + signing::{compute_commit_boost_signing_root, compute_domain_from_mask}, }, }; @@ -99,6 +101,48 @@ pub fn generate_from_keystore( Ok(signed_messages) } +/// Generate signed delegations/revocations using a remote Dirk signer +pub async fn generate_from_dirk( + dirk: &mut Dirk, + delegatee_pubkey: BlsPublicKey, + account_paths: Vec, + chain: Chain, + action: Action, +) -> Result> { + let mut signed_messages = Vec::new(); + + // first read the accounts from the remote keystore + let accounts = dirk.list_accounts(account_paths).await?; + debug!("Found {} remote accounts", accounts.len()); + + // specify the signing domain (needs to be included in the signing request) + let domain = compute_domain_from_mask(chain.fork_version()); + + for account in accounts { + // for each available pubkey we control, sign a delegation message + let pubkey = BlsPublicKey::try_from(account.public_key.as_slice())?; + + match action { + Action::Delegate => { + let message = DelegationMessage::new(pubkey.clone(), delegatee_pubkey.clone()); + let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; + let signature = dirk.request_signature(pubkey, signing_root, domain.into()).await?; + let signed = SignedDelegation { message, signature }; + signed_messages.push(SignedMessage::Delegation(signed)); + } + Action::Revoke => { + let message = RevocationMessage::new(pubkey.clone(), delegatee_pubkey.clone()); + let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; + let signature = dirk.request_signature(pubkey, signing_root, domain.into()).await?; + let signed = SignedRevocation { message, signature }; + signed_messages.push(SignedMessage::Revocation(signed)); + } + } + } + + Ok(signed_messages) +} + /// Event types that can be emitted by the validator pubkey to /// signal some action on the Bolt protocol. #[derive(Debug, Clone, Copy)] diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index fd72bbab..367eaf0a 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -13,6 +13,7 @@ mod pubkeys; /// Utility functions and helpers for the CLI. mod utils; +use tracing::debug; use utils::{dirk::Dirk, keystore::KeystoreSecret, parse_bls_public_key, write_to_file}; /// Protocol Buffers definitions generated by `prost`. @@ -21,6 +22,8 @@ mod pb; #[tokio::main] async fn main() -> Result<()> { let _ = dotenvy::dotenv(); + let _ = tracing_subscriber::fmt::try_init(); + let cli = Opts::parse(); // Init the default rustls provider for Dirk @@ -55,9 +58,20 @@ async fn main() -> Result<()> { println!("Signed delegation messages generated and saved to {}", out); } KeySource::Dirk { opts } => { - let _dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; + let mut dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; + let delegatee_pubkey = parse_bls_public_key(&delegatee_pubkey)?; + let signed_messages = delegation::generate_from_dirk( + &mut dirk, + delegatee_pubkey, + opts.accounts, + chain, + action, + ) + .await?; + debug!("Signed {} messages with Dirk", signed_messages.len()); - todo!("generate delegations from dirk"); + write_to_file(&out, &signed_messages)?; + println!("Signed delegation messages generated and saved to {}", out); } }, @@ -76,7 +90,7 @@ async fn main() -> Result<()> { println!("Pubkeys generated and saved to {}", out); } KeySource::Dirk { opts } => { - let dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; + let mut dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; let accounts = dirk.list_accounts(opts.accounts).await?; let pubkeys = pubkeys::list_from_dirk_accounts(&accounts)?; diff --git a/bolt-cli/src/utils/dirk.rs b/bolt-cli/src/utils/dirk.rs index 52f38df9..2d161edf 100644 --- a/bolt-cli/src/utils/dirk.rs +++ b/bolt-cli/src/utils/dirk.rs @@ -17,7 +17,8 @@ use crate::{ /// Reference: https://github.com/attestantio/dirk #[derive(Clone)] pub struct Dirk { - conn: Channel, + lister: ListerClient, + signer: SignerClient, } impl Dirk { @@ -27,33 +28,33 @@ impl Dirk { let tls_config = compose_credentials(credentials)?; let conn = Channel::builder(addr).tls_config(tls_config)?.connect().await?; - Ok(Self { conn }) + let lister = ListerClient::new(conn.clone()); + let signer = SignerClient::new(conn.clone()); + + Ok(Self { lister, signer }) } /// List all accounts in the keystore. - pub async fn list_accounts(&self, paths: Vec) -> Result> { - let mut lister = ListerClient::new(self.conn.clone()); - let accs = lister.list_accounts(ListAccountsRequest { paths }).await?; + pub async fn list_accounts(&mut self, paths: Vec) -> Result> { + let accs = self.lister.list_accounts(ListAccountsRequest { paths }).await?; Ok(accs.into_inner().accounts) } /// Request a signature from the remote signer. pub async fn request_signature( - &self, + &mut self, pubkey: BlsPublicKey, hash: B256, domain: B256, ) -> Result { - let mut signer = SignerClient::new(self.conn.clone()); - let req = SignRequest { data: hash.to_vec(), domain: domain.to_vec(), id: Some(SignRequestId::PublicKey(pubkey.to_vec())), }; - let res = signer.sign(req).await?; + let res = self.signer.sign(req).await?; let sig = res.into_inner().signature; let sig = BlsSignature::try_from(sig.as_slice()).wrap_err("Failed to parse signature")?; @@ -83,33 +84,74 @@ fn compose_credentials(creds: TlsCredentials) -> Result { #[cfg(test)] mod tests { + use std::{process::Command, time::Duration}; + use super::*; - /// Test connecting to a DIRK server + /// Test connecting to a DIRK server and listing available accounts. /// - /// This test should be run manually against a running DIRK server. - /// Eventually this could become part of the entire test setup but for now it's ignored. + /// ```shell + /// cargo test --package bolt-cli --bin bolt-cli -- utils::dirk::tests::test_dirk_connection_e2e + /// --exact --show-output --ignored + /// ``` #[tokio::test] #[ignore] - async fn test_connect_to_dirk() -> eyre::Result<()> { + async fn test_dirk_connection_e2e() -> eyre::Result<()> { // Init the default rustls provider let _ = rustls::crypto::ring::default_provider().install_default(); - let url = "https://localhost:9091".to_string(); - let test_data_dir = env!("CARGO_MANIFEST_DIR").to_string() + "/test_data/dirk"; + // Init the DIRK config file + init_dirk_config(test_data_dir.clone())?; + + // Check if dirk is installed (in $PATH) + if Command::new("dirk") + .arg("--base-dir") + .arg(&test_data_dir) + .arg("--help") + .status() + .is_err() + { + eprintln!("DIRK is not installed in $PATH"); + return Ok(()); + } + + // Start the DIRK server in the background + let mut dirk_proc = Command::new("dirk").arg("--base-dir").arg(&test_data_dir).spawn()?; + + // Wait for some time for the server to start up + tokio::time::sleep(Duration::from_secs(3)).await; + + let url = "https://localhost:9091".to_string(); + let cred = TlsCredentials { client_cert_path: test_data_dir.clone() + "/client1.crt", client_key_path: test_data_dir.clone() + "/client1.key", ca_cert_path: Some(test_data_dir.clone() + "/security/ca.crt"), }; - let dirk = Dirk::connect(url, cred).await?; + let mut dirk = Dirk::connect(url, cred).await?; let accounts = dirk.list_accounts(vec!["wallet1".to_string()]).await?; println!("Dirk Accounts: {:?}", accounts); + // make sure to stop the dirk server + dirk_proc.kill()?; + + Ok(()) + } + + fn init_dirk_config(test_data_dir: String) -> eyre::Result<()> { + // read the template json file from test_data + let template_path = test_data_dir.clone() + "/dirk.template.json"; + let template = fs::read_to_string(template_path).wrap_err("Failed to read template")?; + + // change the occurrence of $PWD to the current working directory in the template + let new_file = test_data_dir.clone() + "/dirk.json"; + let new_content = template.replace("$PWD", &test_data_dir); + fs::write(new_file, new_content).wrap_err("Failed to write dirk config file")?; + Ok(()) } } diff --git a/bolt-cli/test_data/dirk/.gitignore b/bolt-cli/test_data/dirk/.gitignore new file mode 100644 index 00000000..98368746 --- /dev/null +++ b/bolt-cli/test_data/dirk/.gitignore @@ -0,0 +1 @@ +dirk.json \ No newline at end of file diff --git a/bolt-cli/test_data/dirk/dirk.template.json b/bolt-cli/test_data/dirk/dirk.template.json new file mode 100644 index 00000000..54c95432 --- /dev/null +++ b/bolt-cli/test_data/dirk/dirk.template.json @@ -0,0 +1,23 @@ +{ + "server": { + "id": 212483780, + "name": "localhost", + "listen-address": "localhost:9091" + }, + "certificates": { + "ca-cert": "file://$PWD/security/ca.crt", + "server-cert": "file://$PWD/security/localhost.crt", + "server-key": "file://$PWD/security/localhost.key" + }, + "peers": { + "212483780": "localhost:9091" + }, + "permissions": { + "client1": { + "wallet1": "All" + }, + "localhost": { + "wallet1": "All" + } + } +} diff --git a/bolt-cli/test_data/dirk/storage/000000.vlog b/bolt-cli/test_data/dirk/storage/000000.vlog new file mode 100644 index 0000000000000000000000000000000000000000..ff7a6f8f9165d15432753d5c128d3d047deb74b7 GIT binary patch literal 20 XcmZQzfPkhiE3ZTxvilwHAD#*TFq;Ok literal 0 HcmV?d00001 diff --git a/bolt-cli/test_data/dirk/storage/KEYREGISTRY b/bolt-cli/test_data/dirk/storage/KEYREGISTRY new file mode 100644 index 00000000..cd3e15ea --- /dev/null +++ b/bolt-cli/test_data/dirk/storage/KEYREGISTRY @@ -0,0 +1 @@ +AcWHello Badger \ No newline at end of file diff --git a/bolt-cli/test_data/dirk/storage/LOCK b/bolt-cli/test_data/dirk/storage/LOCK new file mode 100644 index 00000000..31ab1683 --- /dev/null +++ b/bolt-cli/test_data/dirk/storage/LOCK @@ -0,0 +1 @@ +33375 diff --git a/bolt-cli/test_data/dirk/storage/MANIFEST b/bolt-cli/test_data/dirk/storage/MANIFEST new file mode 100644 index 0000000000000000000000000000000000000000..0b5596943f5fb52aa3198b6cc783be43165b577a GIT binary patch literal 16 ScmZ=tNiSkxU| Date: Wed, 23 Oct 2024 20:22:18 +0200 Subject: [PATCH 10/16] feat: working dirk delegation --- bolt-cli/.env.keystore.example | 7 - bolt-cli/.env.local.example | 6 - bolt-cli/.gitignore | 5 +- bolt-cli/README.md | 231 ++++-- bolt-cli/build.rs | 7 +- bolt-cli/src/cli.rs | 15 +- bolt-cli/src/delegation.rs | 32 +- bolt-cli/src/main.rs | 7 +- bolt-cli/src/pb/mod.rs | 10 +- bolt-cli/src/pb/v1.rs | 876 +++++++++++++++++++++ bolt-cli/src/utils/dirk.rs | 76 +- bolt-cli/test_data/dirk/dirk.template.json | 3 + bolt-cli/test_data/dirk/wallet1-pf.txt | 1 + 13 files changed, 1176 insertions(+), 100 deletions(-) delete mode 100644 bolt-cli/.env.keystore.example delete mode 100644 bolt-cli/.env.local.example create mode 100644 bolt-cli/test_data/dirk/wallet1-pf.txt diff --git a/bolt-cli/.env.keystore.example b/bolt-cli/.env.keystore.example deleted file mode 100644 index 1e1938fd..00000000 --- a/bolt-cli/.env.keystore.example +++ /dev/null @@ -1,7 +0,0 @@ -# generate keystore - -PATH=keys -PASSWORD=password -DELEGATEE_PUBKEY=0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93 -OUTPUT_FILE_PATH=delegations.json -CHAIN=kurtosis \ No newline at end of file diff --git a/bolt-cli/.env.local.example b/bolt-cli/.env.local.example deleted file mode 100644 index 1d522585..00000000 --- a/bolt-cli/.env.local.example +++ /dev/null @@ -1,6 +0,0 @@ -# generate local - -SECRET_KEYS=0f40d627fa199720b79db91ce3f57034680f3ee6eef161abfb8275e676a7fd15,0f40d627fa199720b79db91ce3f57034680f3ee6eef161abfb8275e676a7fd15 -DELEGATEE_PUBKEY=0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93 -OUTPUT_FILE_PATH=delegations.json -CHAIN=kurtosis \ No newline at end of file diff --git a/bolt-cli/.gitignore b/bolt-cli/.gitignore index 31190eab..12571ac3 100644 --- a/bolt-cli/.gitignore +++ b/bolt-cli/.gitignore @@ -1,6 +1,7 @@ /target + .env .env.* + delegations.json -!.env.local.example -!.env.keystore.example \ No newline at end of file +pubkeys.json diff --git a/bolt-cli/README.md b/bolt-cli/README.md index 64098fba..c52d3e9c 100644 --- a/bolt-cli/README.md +++ b/bolt-cli/README.md @@ -1,82 +1,209 @@ # Bolt CLI -Components: +The Bolt CLI is a collection of command-line tools for interacting with the Bolt protocol. -- `bolt-delegations-cli`: A command-line tool for generating delegation messages signed with a BLS12-381 key. +## Installation -## Bolt-delegations-cli +The Bolt CLI can be built with Cargo. If you don't have the Rust toolchain installed +on your machine, you can follow the steps [here](https://www.rust-lang.org/tools/install). -`bolt-delegations-cli` is an offline command-line tool for safely generating delegation messages -signed with a BLS12-381 key for the [Constraints API](https://docs.boltprotocol.xyz/api/builder) -in [Bolt](https://docs.boltprotocol.xyz/). +Once you have Rust installed, you can build the CLI binary in the following way: -The tool supports two key sources: +```shell +# clone the Bolt repository if you haven't already +git clone git@github.com:chainbound/bolt.git -- Local: A BLS private key provided directly from a file. -- Keystore: A keystore file that contains an encrypted BLS private key. +# navigate to the Bolt CLI package directory +cd bolt-cli -Features: +# build and install the binary on your machine +cargo install --path . --force -- Offline usage: Safely generate delegation messages in an offline environment. -- Flexible key source: Support for both direct local BLS private keys and Ethereum keystore files (ERC-2335 format). -- BLS delegation signing: Sign delegation messages using a BLS secret key and output the signed delegation in JSON format. +# test the installation +bolt-cli --version +``` + +## Usage + +Available commands: + +- [`delegate`](#delegate) - Generate BLS delegation messages for the Constraints API. +- [`pubkeys`](#pubkeys) - List available BLS public keys from various key sources. + +### `Delegate` + +The `delegate` command generates signed delegation messages for the Constraints API. +To learn more about the Constraints API, please refer to the [Bolt documentation][bolt-docs]. + +The command supports three key sources for generating the signed messages: + +- Local BLS secret keys (as hex-encoded strings) via `secret-keys` +- Local EIP-2335 filesystem keystore directories via `local-keystore` +- Remote Dirk keystore via `dirk` (requires TLS credentials) + +
+Usage + +```text +❯ bolt-cli delegate --help + +Generate BLS delegation or revocation messages + +Usage: bolt-cli delegate [OPTIONS] --delegatee-pubkey + +Commands: +secret-keys Use local secret keys to generate the signed messages +local-keystore Use an EIP-2335 filesystem keystore directory to generate the signed messages +dirk Use a remote DIRK keystore to generate the signed messages +help Print this message or the help of the given subcommand(s) + +Options: + --delegatee-pubkey + The BLS public key to which the delegation message should be signed + + [env: DELEGATEE_PUBKEY=] + + --out + The output file for the delegations + + [env: OUTPUT_FILE_PATH=] + [default: delegations.json] + + --chain + The chain for which the delegation message is intended + + [env: CHAIN=] + [default: mainnet] + [possible values: mainnet, holesky, helder, kurtosis] + + --action + The action to perform. The tool can be used to generate delegation or revocation messages (default: delegate) + + [env: ACTION=] + [default: delegate] + + Possible values: + - delegate: Create a delegation message + - revoke: Create a revocation message + +-h, --help + Print help (see a summary with '-h') +``` + +
-### Usage +
+Examples + +1. Generating a delegation using a local BLS secret key + +```text +bolt-cli delegate \ + --delegatee-pubkey 0x8d0edf4fe9c80cd640220ca7a68a48efcbc56a13536d6b274bf3719befaffa13688ebee9f37414b3dddc8c7e77233ce8 \ + --chain holesky \ + secret-keys --secret-keys 642e0d33fde8968a48b5f560c1b20143eb82036c1aa6c7f4adc4beed919a22e3 +``` + +2. Generating a delegation using an ERC-2335 keystore directory + +```text +bolt-cli delegate \ + --delegatee-pubkey 0x8d0edf4fe9c80cd640220ca7a68a48efcbc56a13536d6b274bf3719befaffa13688ebee9f37414b3dddc8c7e77233ce8 \ + --chain holesky \ + local-keystore --path test_data/lighthouse/validators --password-path test_data/lighthouse/secrets +``` + +3. Generating a revocation using a remote DIRK keystore + +```text +bolt-cli delegate \ + --delegatee-pubkey 0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93 \ + dirk --url https://localhost:9091 \ + --client-cert-path ./test_data/dirk/client1.crt \ + --client-key-path ./test_data/dirk/client1.key \ + --ca-cert-path ./test_data/dirk/security/ca.crt \ + --wallet-path wallet1 --passphrases secret +``` + +
+ +### `Pubkeys` + +The `pubkeys` command lists available BLS public keys from different key sources: + +- Local BLS secret keys (as hex-encoded strings) via `secret-keys` +- Local EIP-2335 filesystem keystore directories via `local-keystore` +- Remote Dirk keystore via `dirk` (requires TLS credentials) + +
+Usage ```text -A CLI tool to generate signed delegation messages for BLS keys +❯ bolt-cli pubkeys --help + +Output a list of pubkeys in JSON format -Usage: bolt-delegations-cli +Usage: bolt-cli pubkeys [OPTIONS] Commands: - generate Generate delegation messages - help Print this message or the help of the given subcommand(s) + secret-keys Use local secret keys to generate the signed messages + local-keystore Use an EIP-2335 filesystem keystore directory to generate the signed messages + dirk Use a remote DIRK keystore to generate the signed messages + help Print this message or the help of the given subcommand(s) Options: - -h, --help Print help - -V, --version Print version + --out The output file for the pubkeys [env: OUTPUT_FILE_PATH=] [default: pubkeys.json] + -h, --help Print help +``` + +
+ +
+Examples + +1. Listing BLS public keys from a local secret key + +```text +bolt-cli pubkeys secret-keys --secret-keys 642e0d33fde8968a48b5f560c1b20143eb82036c1aa6c7f4adc4beed919a22e3 ``` -#### Example +2. Listing BLS public keys from an ERC-2335 keystore directory -1. Using a local BLS private key: +```text +bolt-cli pubkeys local-keystore \ + --path test_data/lighthouse/validators \ + --password-path test_data/lighthouse/secrets +``` - ```text - bolt-delegations-cli generate \ - --delegatee-pubkey 0x7890ab... \ - --out my_delegations.json \ - --chain kurtosis \ - local \ - --secret-keys 0xabc123...,0xdef456.. - ``` +3. Listing BLS public keys from a remote DIRK keystore -2. Using an Ethereum keystore file: +```text +bolt-cli pubkeys dirk --url https://localhost:9091 \ + --client-cert-path ./test_data/dirk/client1.crt \ + --client-key-path ./test_data/dirk/client1.key \ + --ca-cert-path ./test_data/dirk/security/ca.crt \ + --wallet-path wallet1 --passphrases secret +``` - ```text - bolt-delegations-cli generate \ - --delegatee-pubkey 0x7890ab... \ - --out my_delegations.json \ - --chain kurtosis \ - keystore \ - --path /keys \ - --password myS3cr3tP@ssw0rd - ``` +
-When using the `keystore` key source, the `--path` flag should point to the directory -containing the encrypted keypair directories. +--- -In case of validator-specific passwords (e.g. Lighthouse format) the `--password-path` -flag must be used instead of `--password`, pointing to the directory containing the password files. +## Security -You can find a reference Lighthouse keystore [here](./test_data/lighthouse/). +The Bolt CLI is designed to be used offline. It does not require any network connections +unless you are using the remote `dirk` key source. In that case, the tool will connect to +the Dirk server with the provided TLS credentials. -#### Supported Chains +The tool does not store any sensitive information beyond the duration of the execution. +It is recommended to use the tool in a secure environment and to avoid storing any sensitive +information in the shell history. -The tool supports the following chains: +If you have any security concerns or have found a security issue/bug, please contact Chainbound +on our official [Discord][discord] or [Twitter][twitter] channels. -- `mainnet` -- `holesky` -- `helder` -- `kurtosis` + -Each chain has its specific fork version used in computing the signing root. +[bolt-docs]: https://docs.boltprotocol.xyz/ +[discord]: https://discord.gg/G5BJjCD9ss +[twitter]: https://twitter.com/chainbound_ diff --git a/bolt-cli/build.rs b/bolt-cli/build.rs index 07c7d446..9342cfe4 100644 --- a/bolt-cli/build.rs +++ b/bolt-cli/build.rs @@ -10,7 +10,12 @@ fn main() -> io::Result<()> { } tonic_build::configure().build_client(true).out_dir(PB_OUT_DIR).compile_protos( - &["proto/eth2-signer-api/v1/lister.proto", "proto/eth2-signer-api/v1/signer.proto"], + &[ + "proto/eth2-signer-api/v1/lister.proto", + "proto/eth2-signer-api/v1/signer.proto", + "proto/eth2-signer-api/v1/accountmanager.proto", + "proto/eth2-signer-api/v1/walletmanager.proto", + ], &["proto/eth2-signer-api/v1/", "proto/eth2-signer-api/"], ) } diff --git a/bolt-cli/src/cli.rs b/bolt-cli/src/cli.rs index 1b152126..1f387988 100644 --- a/bolt-cli/src/cli.rs +++ b/bolt-cli/src/cli.rs @@ -3,7 +3,7 @@ use serde::Deserialize; use crate::utils::keystore::DEFAULT_KEYSTORE_PASSWORD; -/// A CLI tool to generate signed delegation messages for BLS keys. +/// A CLI tool to interact with Bolt Protocol ✨ #[derive(Parser, Debug, Clone, Deserialize)] #[command(author, version, about, long_about = None)] pub struct Opts { @@ -119,13 +119,18 @@ pub struct DirkOpts { #[clap(long, env = "DIRK_URL")] pub url: String, + /// The path of the wallets in the DIRK keystore. + #[clap(long, env = "DIRK_WALLET_PATH")] + pub wallet_path: String, + + /// The passphrases to unlock the wallet in the DIRK keystore. + /// If multiple are provided, they are tried in order until one works. + #[clap(long, env = "DIRK_PASSPHRASES", value_delimiter = ',', hide_env_values = true)] + pub passphrases: Option>, + /// The TLS credentials for connecting to the DIRK keystore. #[clap(flatten)] pub tls_credentials: TlsCredentials, - - /// The paths to the accounts in the DIRK keystore. - #[clap(long, env = "DIRK_ACCOUNTS", value_delimiter = ',', hide_env_values = true)] - pub accounts: Vec, } /// TLS credentials for connecting to a remote server. diff --git a/bolt-cli/src/delegation.rs b/bolt-cli/src/delegation.rs index 46b3cded..1d3f7fde 100644 --- a/bolt-cli/src/delegation.rs +++ b/bolt-cli/src/delegation.rs @@ -1,8 +1,9 @@ +use alloy_primitives::B256; use alloy_signer::k256::sha2::{Digest, Sha256}; use ethereum_consensus::crypto::{ PublicKey as BlsPublicKey, SecretKey as BlsSecretKey, Signature as BlsSignature, }; -use eyre::Result; +use eyre::{bail, Result}; use lighthouse_eth2_keystore::Keystore; use serde::Serialize; use tracing::debug; @@ -70,6 +71,7 @@ pub fn generate_from_keystore( ) -> Result> { let keystores_paths = keystore_paths(keys_path)?; let mut signed_messages = Vec::with_capacity(keystores_paths.len()); + debug!("Found {} keys in the keystore", keystores_paths.len()); for path in keystores_paths { let ks = Keystore::from_json_file(path).map_err(KeystoreError::Eth2Keystore)?; @@ -105,35 +107,47 @@ pub fn generate_from_keystore( pub async fn generate_from_dirk( dirk: &mut Dirk, delegatee_pubkey: BlsPublicKey, - account_paths: Vec, + account_path: String, + passphrases: Option>, chain: Chain, action: Action, ) -> Result> { - let mut signed_messages = Vec::new(); - // first read the accounts from the remote keystore - let accounts = dirk.list_accounts(account_paths).await?; - debug!("Found {} remote accounts", accounts.len()); + let accounts = dirk.list_accounts(account_path).await?; + debug!("Found {} remote accounts to sign with", accounts.len()); + + let mut signed_messages = Vec::with_capacity(accounts.len()); // specify the signing domain (needs to be included in the signing request) - let domain = compute_domain_from_mask(chain.fork_version()); + let domain = B256::from(compute_domain_from_mask(chain.fork_version())); for account in accounts { // for each available pubkey we control, sign a delegation message let pubkey = BlsPublicKey::try_from(account.public_key.as_slice())?; + // Note: before signing, we must unlock the account + if let Some(ref passphrases) = passphrases { + for passphrase in passphrases { + if dirk.unlock_account(account.name.clone(), passphrase.clone()).await? { + break; + } + } + } else { + bail!("A passphrase is required in order to sign messages remotely with Dirk"); + } + match action { Action::Delegate => { let message = DelegationMessage::new(pubkey.clone(), delegatee_pubkey.clone()); let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; - let signature = dirk.request_signature(pubkey, signing_root, domain.into()).await?; + let signature = dirk.request_signature(&account, signing_root, domain).await?; let signed = SignedDelegation { message, signature }; signed_messages.push(SignedMessage::Delegation(signed)); } Action::Revoke => { let message = RevocationMessage::new(pubkey.clone(), delegatee_pubkey.clone()); let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; - let signature = dirk.request_signature(pubkey, signing_root, domain.into()).await?; + let signature = dirk.request_signature(&account, signing_root, domain).await?; let signed = SignedRevocation { message, signature }; signed_messages.push(SignedMessage::Revocation(signed)); } diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index 367eaf0a..5dc57437 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -60,10 +60,12 @@ async fn main() -> Result<()> { KeySource::Dirk { opts } => { let mut dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; let delegatee_pubkey = parse_bls_public_key(&delegatee_pubkey)?; + let signed_messages = delegation::generate_from_dirk( &mut dirk, delegatee_pubkey, - opts.accounts, + opts.wallet_path, + opts.passphrases, chain, action, ) @@ -90,8 +92,9 @@ async fn main() -> Result<()> { println!("Pubkeys generated and saved to {}", out); } KeySource::Dirk { opts } => { + // Note: we don't need to unlock wallets to list pubkeys let mut dirk = Dirk::connect(opts.url, opts.tls_credentials).await?; - let accounts = dirk.list_accounts(opts.accounts).await?; + let accounts = dirk.list_accounts(opts.wallet_path).await?; let pubkeys = pubkeys::list_from_dirk_accounts(&accounts)?; write_to_file(&out, &pubkeys)?; diff --git a/bolt-cli/src/pb/mod.rs b/bolt-cli/src/pb/mod.rs index 435dccf7..5a22114f 100644 --- a/bolt-cli/src/pb/mod.rs +++ b/bolt-cli/src/pb/mod.rs @@ -5,8 +5,12 @@ pub mod eth2_signer_api { #[allow(unused_imports)] pub use super::v1::{ - lister_client::ListerClient, sign_request::Id as SignRequestId, - signer_client::SignerClient, Account, DistributedAccount, ListAccountsRequest, - ListAccountsResponse, ResponseState, SignRequest, SignResponse, + account_manager_client::AccountManagerClient, lister_client::ListerClient, + sign_request::Id as SignRequestId, signer_client::SignerClient, + wallet_manager_client::WalletManagerClient, Account, DistributedAccount, + ListAccountsRequest, ListAccountsResponse, LockAccountRequest, LockAccountResponse, + LockWalletRequest, LockWalletResponse, MultisignRequest, MultisignResponse, ResponseState, + SignRequest, SignResponse, UnlockAccountRequest, UnlockAccountResponse, + UnlockWalletRequest, UnlockWalletResponse, }; } diff --git a/bolt-cli/src/pb/v1.rs b/bolt-cli/src/pb/v1.rs index a4e1e7a8..dbef7a82 100644 --- a/bolt-cli/src/pb/v1.rs +++ b/bolt-cli/src/pb/v1.rs @@ -1066,3 +1066,879 @@ pub mod signer_server { const NAME: &'static str = SERVICE_NAME; } } +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UnlockAccountRequest { + #[prost(string, tag = "1")] + pub account: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub passphrase: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LockAccountRequest { + #[prost(string, tag = "1")] + pub account: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct UnlockAccountResponse { + #[prost(enumeration = "ResponseState", tag = "1")] + pub state: i32, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct LockAccountResponse { + #[prost(enumeration = "ResponseState", tag = "1")] + pub state: i32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenerateRequest { + #[prost(string, tag = "1")] + pub account: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub passphrase: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "3")] + pub participants: u32, + #[prost(uint32, tag = "4")] + pub signing_threshold: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GenerateResponse { + #[prost(enumeration = "ResponseState", tag = "1")] + pub state: i32, + #[prost(string, tag = "2")] + pub message: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "3")] + pub public_key: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub participants: ::prost::alloc::vec::Vec, +} +/// Generated client implementations. +pub mod account_manager_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct AccountManagerClient { + inner: tonic::client::Grpc, + } + impl AccountManagerClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl AccountManagerClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> AccountManagerClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + AccountManagerClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn unlock( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/v1.AccountManager/Unlock"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.AccountManager", "Unlock")); + self.inner.unary(req, path, codec).await + } + pub async fn lock( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/v1.AccountManager/Lock"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.AccountManager", "Lock")); + self.inner.unary(req, path, codec).await + } + pub async fn generate( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/v1.AccountManager/Generate", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("v1.AccountManager", "Generate")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod account_manager_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with AccountManagerServer. + #[async_trait] + pub trait AccountManager: std::marker::Send + std::marker::Sync + 'static { + async fn unlock( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn lock( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn generate( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct AccountManagerServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl AccountManagerServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for AccountManagerServer + where + T: AccountManager, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/v1.AccountManager/Unlock" => { + #[allow(non_camel_case_types)] + struct UnlockSvc(pub Arc); + impl< + T: AccountManager, + > tonic::server::UnaryService + for UnlockSvc { + type Response = super::UnlockAccountResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::unlock(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = UnlockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/v1.AccountManager/Lock" => { + #[allow(non_camel_case_types)] + struct LockSvc(pub Arc); + impl< + T: AccountManager, + > tonic::server::UnaryService + for LockSvc { + type Response = super::LockAccountResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::lock(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = LockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/v1.AccountManager/Generate" => { + #[allow(non_camel_case_types)] + struct GenerateSvc(pub Arc); + impl< + T: AccountManager, + > tonic::server::UnaryService + for GenerateSvc { + type Response = super::GenerateResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::generate(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GenerateSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } + } + } + } + impl Clone for AccountManagerServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "v1.AccountManager"; + impl tonic::server::NamedService for AccountManagerServer { + const NAME: &'static str = SERVICE_NAME; + } +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct UnlockWalletRequest { + #[prost(string, tag = "1")] + pub wallet: ::prost::alloc::string::String, + #[prost(bytes = "vec", tag = "2")] + pub passphrase: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LockWalletRequest { + #[prost(string, tag = "1")] + pub wallet: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct UnlockWalletResponse { + #[prost(enumeration = "ResponseState", tag = "1")] + pub state: i32, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct LockWalletResponse { + #[prost(enumeration = "ResponseState", tag = "1")] + pub state: i32, +} +/// Generated client implementations. +pub mod wallet_manager_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct WalletManagerClient { + inner: tonic::client::Grpc, + } + impl WalletManagerClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl WalletManagerClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> WalletManagerClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + WalletManagerClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn unlock( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/v1.WalletManager/Unlock"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.WalletManager", "Unlock")); + self.inner.unary(req, path, codec).await + } + pub async fn lock( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/v1.WalletManager/Lock"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.WalletManager", "Lock")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod wallet_manager_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with WalletManagerServer. + #[async_trait] + pub trait WalletManager: std::marker::Send + std::marker::Sync + 'static { + async fn unlock( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn lock( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct WalletManagerServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + impl WalletManagerServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for WalletManagerServer + where + T: WalletManager, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/v1.WalletManager/Unlock" => { + #[allow(non_camel_case_types)] + struct UnlockSvc(pub Arc); + impl< + T: WalletManager, + > tonic::server::UnaryService + for UnlockSvc { + type Response = super::UnlockWalletResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::unlock(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = UnlockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/v1.WalletManager/Lock" => { + #[allow(non_camel_case_types)] + struct LockSvc(pub Arc); + impl< + T: WalletManager, + > tonic::server::UnaryService + for LockSvc { + type Response = super::LockWalletResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::lock(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = LockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } + } + } + } + impl Clone for WalletManagerServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "v1.WalletManager"; + impl tonic::server::NamedService for WalletManagerServer { + const NAME: &'static str = SERVICE_NAME; + } +} diff --git a/bolt-cli/src/utils/dirk.rs b/bolt-cli/src/utils/dirk.rs index 2d161edf..f4b31175 100644 --- a/bolt-cli/src/utils/dirk.rs +++ b/bolt-cli/src/utils/dirk.rs @@ -1,24 +1,32 @@ use std::fs; use alloy_primitives::B256; -use ethereum_consensus::crypto::bls::{PublicKey as BlsPublicKey, Signature as BlsSignature}; -use eyre::{Context, Result}; +use ethereum_consensus::crypto::bls::Signature as BlsSignature; +use eyre::{bail, Context, Result}; use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity}; +use tracing::debug; use crate::{ cli::TlsCredentials, pb::eth2_signer_api::{ - Account, ListAccountsRequest, ListerClient, SignRequest, SignRequestId, SignerClient, + Account, AccountManagerClient, ListAccountsRequest, ListerClient, ResponseState, + SignRequest, SignRequestId, SignerClient, UnlockAccountRequest, }, }; /// A Dirk remote signer. /// +/// Available services: +/// - `Lister`: List accounts in the keystore. +/// - `Signer`: Request a signature from the remote signer. +/// - `AccountManager`: Manage accounts in the keystore (lock and unlock accounts). +/// /// Reference: https://github.com/attestantio/dirk #[derive(Clone)] pub struct Dirk { lister: ListerClient, signer: SignerClient, + account_mng: AccountManagerClient, } impl Dirk { @@ -30,34 +38,76 @@ impl Dirk { let lister = ListerClient::new(conn.clone()); let signer = SignerClient::new(conn.clone()); + let account_mng = AccountManagerClient::new(conn); - Ok(Self { lister, signer }) + Ok(Self { lister, signer, account_mng }) } /// List all accounts in the keystore. - pub async fn list_accounts(&mut self, paths: Vec) -> Result> { - let accs = self.lister.list_accounts(ListAccountsRequest { paths }).await?; + pub async fn list_accounts(&mut self, wallet_path: String) -> Result> { + // Request all accounts in the given path. Only one path at a time + // as done in https://github.com/wealdtech/go-eth2-wallet-dirk/blob/182f99b22b64d01e0d4ae67bf47bb055763465d7/grpc.go#L121 + let req = ListAccountsRequest { paths: vec![wallet_path] }; + let res = self.lister.list_accounts(req).await?.into_inner(); + + if !matches!(res.state(), ResponseState::Succeeded) { + bail!("Failed to list accounts: {:?}", res); + } - Ok(accs.into_inner().accounts) + debug!("{} Accounts listed successfully", res.accounts.len()); + Ok(res.accounts) + } + + /// Unlock an account in the keystore with the given passphrase. + pub async fn unlock_account( + &mut self, + account_name: String, + passphrase: String, + ) -> Result { + let pf_bytes = passphrase.as_bytes().to_vec(); + let req = UnlockAccountRequest { account: account_name.clone(), passphrase: pf_bytes }; + let res = self.account_mng.unlock(req).await?.into_inner(); + + match res.state() { + ResponseState::Succeeded => { + debug!("Unlock request succeeded for account {}", account_name); + Ok(true) + } + ResponseState::Denied => { + debug!("Unlock request denied for account {}", account_name); + Ok(false) + } + ResponseState::Unknown => bail!("Unknown response from unlock account: {:?}", res), + ResponseState::Failed => bail!("Failed to unlock account: {:?}", res), + } } /// Request a signature from the remote signer. pub async fn request_signature( &mut self, - pubkey: BlsPublicKey, + account: &Account, hash: B256, domain: B256, ) -> Result { let req = SignRequest { data: hash.to_vec(), domain: domain.to_vec(), - id: Some(SignRequestId::PublicKey(pubkey.to_vec())), + id: Some(SignRequestId::Account(account.name.clone())), }; - let res = self.signer.sign(req).await?; - let sig = res.into_inner().signature; - let sig = BlsSignature::try_from(sig.as_slice()).wrap_err("Failed to parse signature")?; + let res = self.signer.sign(req).await?.into_inner(); + + if !matches!(res.state(), ResponseState::Succeeded) { + bail!("Failed to sign data: {:?}", res); + } + if res.signature.is_empty() { + bail!("Empty signature returned"); + } + + let sig = BlsSignature::try_from(res.signature.as_slice()) + .wrap_err("Failed to parse signature")?; + debug!("Signature request succeeded for account {}", account.name); Ok(sig) } } @@ -133,7 +183,7 @@ mod tests { let mut dirk = Dirk::connect(url, cred).await?; - let accounts = dirk.list_accounts(vec!["wallet1".to_string()]).await?; + let accounts = dirk.list_accounts("wallet1".to_string()).await?; println!("Dirk Accounts: {:?}", accounts); // make sure to stop the dirk server diff --git a/bolt-cli/test_data/dirk/dirk.template.json b/bolt-cli/test_data/dirk/dirk.template.json index 54c95432..e51b8170 100644 --- a/bolt-cli/test_data/dirk/dirk.template.json +++ b/bolt-cli/test_data/dirk/dirk.template.json @@ -19,5 +19,8 @@ "localhost": { "wallet1": "All" } + }, + "unlocker": { + "wallet-passphrases": ["file://$PWD/wallet1-pf.txt"] } } diff --git a/bolt-cli/test_data/dirk/wallet1-pf.txt b/bolt-cli/test_data/dirk/wallet1-pf.txt new file mode 100644 index 00000000..536aca34 --- /dev/null +++ b/bolt-cli/test_data/dirk/wallet1-pf.txt @@ -0,0 +1 @@ +secret \ No newline at end of file From bf13b0f96b987775895c1f8d0807e4ad7fa96738 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:49:49 +0200 Subject: [PATCH 11/16] chore: update readme --- bolt-cli/README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/bolt-cli/README.md b/bolt-cli/README.md index c52d3e9c..06f97e90 100644 --- a/bolt-cli/README.md +++ b/bolt-cli/README.md @@ -1,13 +1,12 @@ # Bolt CLI -The Bolt CLI is a collection of command-line tools for interacting with the Bolt protocol. +The Bolt CLI is a collection of command-line tools for interacting with Bolt protocol. ## Installation -The Bolt CLI can be built with Cargo. If you don't have the Rust toolchain installed -on your machine, you can follow the steps [here](https://www.rust-lang.org/tools/install). - -Once you have Rust installed, you can build the CLI binary in the following way: +This tool can be built with Cargo. If you don't have the Rust toolchain installed +on your machine, you can follow the steps [here][rust]. +Once you have Rust installed, you can build the binary in the following way: ```shell # clone the Bolt repository if you haven't already @@ -30,17 +29,19 @@ Available commands: - [`delegate`](#delegate) - Generate BLS delegation messages for the Constraints API. - [`pubkeys`](#pubkeys) - List available BLS public keys from various key sources. -### `Delegate` - -The `delegate` command generates signed delegation messages for the Constraints API. -To learn more about the Constraints API, please refer to the [Bolt documentation][bolt-docs]. - -The command supports three key sources for generating the signed messages: +All above commands support three key sources: - Local BLS secret keys (as hex-encoded strings) via `secret-keys` - Local EIP-2335 filesystem keystore directories via `local-keystore` - Remote Dirk keystore via `dirk` (requires TLS credentials) +--- + +### `Delegate` + +The `delegate` command generates signed delegation messages for the Constraints API. +To learn more about the Constraints API, please refer to the [Bolt documentation][bolt-docs]. +
Usage @@ -127,13 +128,11 @@ bolt-cli delegate \
-### `Pubkeys` +--- -The `pubkeys` command lists available BLS public keys from different key sources: +### `Pubkeys` -- Local BLS secret keys (as hex-encoded strings) via `secret-keys` -- Local EIP-2335 filesystem keystore directories via `local-keystore` -- Remote Dirk keystore via `dirk` (requires TLS credentials) +The `pubkeys` command lists available BLS public keys from different key sources.
Usage @@ -204,6 +203,7 @@ on our official [Discord][discord] or [Twitter][twitter] channels. +[rust]: https://www.rust-lang.org/tools/install [bolt-docs]: https://docs.boltprotocol.xyz/ [discord]: https://discord.gg/G5BJjCD9ss [twitter]: https://twitter.com/chainbound_ From a08e4bad910cf4f5c762d1bad62f236f167f95ba Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:53:37 +0200 Subject: [PATCH 12/16] chore: update readme --- bolt-cli/README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bolt-cli/README.md b/bolt-cli/README.md index 06f97e90..2c398d3b 100644 --- a/bolt-cli/README.md +++ b/bolt-cli/README.md @@ -4,9 +4,12 @@ The Bolt CLI is a collection of command-line tools for interacting with Bolt pro ## Installation -This tool can be built with Cargo. If you don't have the Rust toolchain installed -on your machine, you can follow the steps [here][rust]. -Once you have Rust installed, you can build the binary in the following way: +Prerequisites: + +- [Rust toolchain][rust] +- [Protoc][protoc] + +Once you have the necessary prerequisites, you can build the binary in the following way: ```shell # clone the Bolt repository if you haven't already @@ -204,6 +207,7 @@ on our official [Discord][discord] or [Twitter][twitter] channels. [rust]: https://www.rust-lang.org/tools/install +[protoc]: https://grpc.io/docs/protoc-installation/ [bolt-docs]: https://docs.boltprotocol.xyz/ [discord]: https://discord.gg/G5BJjCD9ss [twitter]: https://twitter.com/chainbound_ From e47aec7945393086a824b29153bf38458b333d0e Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:07:35 +0200 Subject: [PATCH 13/16] fix: verify signatures before writing to file --- bolt-cli/src/delegation.rs | 69 ++++++++++++++++++++------------------ bolt-cli/src/main.rs | 15 +++++++++ 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/bolt-cli/src/delegation.rs b/bolt-cli/src/delegation.rs index 1d3f7fde..a50d0b6f 100644 --- a/bolt-cli/src/delegation.rs +++ b/bolt-cli/src/delegation.rs @@ -13,7 +13,9 @@ use crate::{ utils::{ dirk::Dirk, keystore::{keystore_paths, KeystoreError, KeystoreSecret}, - signing::{compute_commit_boost_signing_root, compute_domain_from_mask}, + signing::{ + compute_commit_boost_signing_root, compute_domain_from_mask, verify_commit_boost_root, + }, }, }; @@ -139,14 +141,14 @@ pub async fn generate_from_dirk( match action { Action::Delegate => { let message = DelegationMessage::new(pubkey.clone(), delegatee_pubkey.clone()); - let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; + let signing_root = message.digest().into(); // Dirk does the hash tree root internally let signature = dirk.request_signature(&account, signing_root, domain).await?; let signed = SignedDelegation { message, signature }; signed_messages.push(SignedMessage::Delegation(signed)); } Action::Revoke => { let message = RevocationMessage::new(pubkey.clone(), delegatee_pubkey.clone()); - let signing_root = compute_commit_boost_signing_root(message.digest(), &chain)?; + let signing_root = message.digest().into(); // Dirk does the hash tree root internally let signature = dirk.request_signature(&account, signing_root, domain).await?; let signed = SignedRevocation { message, signature }; signed_messages.push(SignedMessage::Revocation(signed)); @@ -249,18 +251,42 @@ impl RevocationMessage { } } +/// Verify the signature of a signed message +pub fn verify_message_signature(message: &SignedMessage, chain: Chain) -> Result<()> { + match message { + SignedMessage::Delegation(signed_delegation) => { + let signer_pubkey = signed_delegation.message.validator_pubkey.clone(); + let digest = signed_delegation.message.digest(); + + let blst_sig = + blst::min_pk::Signature::from_bytes(signed_delegation.signature.as_ref()) + .map_err(|e| eyre::eyre!("Failed to parse signature: {:?}", e))?; + + // Verify the signature + verify_commit_boost_root(signer_pubkey, digest, &blst_sig, &chain) + } + SignedMessage::Revocation(signed_revocation) => { + let signer_pubkey = signed_revocation.message.validator_pubkey.clone(); + let digest = signed_revocation.message.digest(); + + let blst_sig = + blst::min_pk::Signature::from_bytes(signed_revocation.signature.as_ref()) + .map_err(|e| eyre::eyre!("Failed to parse signature: {:?}", e))?; + + // Verify the signature + verify_commit_boost_root(signer_pubkey, digest, &blst_sig, &chain) + } + } +} + #[cfg(test)] mod tests { - use ethereum_consensus::crypto::PublicKey as BlsPublicKey; - use crate::{ cli::{Action, Chain}, - utils::{ - keystore::KeystoreSecret, parse_bls_public_key, signing::verify_commit_boost_root, - }, + utils::{keystore::KeystoreSecret, parse_bls_public_key}, }; - use super::{generate_from_keystore, SignedMessage}; + use super::{generate_from_keystore, verify_message_signature}; #[test] fn test_delegation_keystore_signer_lighthouse() -> eyre::Result<()> { @@ -284,31 +310,8 @@ mod tests { let signed_message = signed_delegations.first().expect("to get signed delegation"); - verify_delegation_signature(signed_message, delegatee_pubkey, chain); + verify_message_signature(signed_message, chain)?; Ok(()) } - - fn verify_delegation_signature( - message: &SignedMessage, - delegatee_pubkey: BlsPublicKey, - chain: Chain, - ) { - match message { - SignedMessage::Delegation(signed_delegation) => { - let output_delegatee_pubkey = signed_delegation.message.delegatee_pubkey.clone(); - let signer_pubkey = signed_delegation.message.validator_pubkey.clone(); - let digest = signed_delegation.message.digest(); - assert_eq!(output_delegatee_pubkey, delegatee_pubkey); - - let blst_sig = - blst::min_pk::Signature::from_bytes(signed_delegation.signature.as_ref()) - .expect("Failed to convert delegation signature"); - - // Verify the signature - assert!(verify_commit_boost_root(signer_pubkey, digest, &blst_sig, &chain).is_ok()); - } - _ => panic!("Expected a delegation message"), - } - } } diff --git a/bolt-cli/src/main.rs b/bolt-cli/src/main.rs index 5dc57437..6bdfecfc 100644 --- a/bolt-cli/src/main.rs +++ b/bolt-cli/src/main.rs @@ -40,6 +40,11 @@ async fn main() -> Result<()> { action, )?; + // Verify signatures + for message in &signed_messages { + delegation::verify_message_signature(message, chain)?; + } + write_to_file(&out, &signed_messages)?; println!("Signed delegation messages generated and saved to {}", out); } @@ -54,6 +59,11 @@ async fn main() -> Result<()> { action, )?; + // Verify signatures + for message in &signed_messages { + delegation::verify_message_signature(message, chain)?; + } + write_to_file(&out, &signed_messages)?; println!("Signed delegation messages generated and saved to {}", out); } @@ -72,6 +82,11 @@ async fn main() -> Result<()> { .await?; debug!("Signed {} messages with Dirk", signed_messages.len()); + // Verify signatures + for message in &signed_messages { + delegation::verify_message_signature(message, chain)?; + } + write_to_file(&out, &signed_messages)?; println!("Signed delegation messages generated and saved to {}", out); } From dadfb73848d7444ef647f2f640d212988efd96a8 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:10:11 +0200 Subject: [PATCH 14/16] feat: added account auto lock --- bolt-cli/src/delegation.rs | 7 ++++++- bolt-cli/src/utils/dirk.rs | 23 +++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/bolt-cli/src/delegation.rs b/bolt-cli/src/delegation.rs index a50d0b6f..239c6871 100644 --- a/bolt-cli/src/delegation.rs +++ b/bolt-cli/src/delegation.rs @@ -6,7 +6,7 @@ use ethereum_consensus::crypto::{ use eyre::{bail, Result}; use lighthouse_eth2_keystore::Keystore; use serde::Serialize; -use tracing::debug; +use tracing::{debug, warn}; use crate::{ cli::{Action, Chain}, @@ -154,6 +154,11 @@ pub async fn generate_from_dirk( signed_messages.push(SignedMessage::Revocation(signed)); } } + + // Try to lock the account back after signing + if let Err(err) = dirk.lock_account(account.name.clone()).await { + warn!("Failed to lock account after signing {}: {:?}", account.name, err); + } } Ok(signed_messages) diff --git a/bolt-cli/src/utils/dirk.rs b/bolt-cli/src/utils/dirk.rs index f4b31175..b47ae94e 100644 --- a/bolt-cli/src/utils/dirk.rs +++ b/bolt-cli/src/utils/dirk.rs @@ -9,8 +9,8 @@ use tracing::debug; use crate::{ cli::TlsCredentials, pb::eth2_signer_api::{ - Account, AccountManagerClient, ListAccountsRequest, ListerClient, ResponseState, - SignRequest, SignRequestId, SignerClient, UnlockAccountRequest, + Account, AccountManagerClient, ListAccountsRequest, ListerClient, LockAccountRequest, + ResponseState, SignRequest, SignRequestId, SignerClient, UnlockAccountRequest, }, }; @@ -82,6 +82,25 @@ impl Dirk { } } + /// Lock an account in the keystore. + pub async fn lock_account(&mut self, account_name: String) -> Result { + let req = LockAccountRequest { account: account_name.clone() }; + let res = self.account_mng.lock(req).await?.into_inner(); + + match res.state() { + ResponseState::Succeeded => { + debug!("Lock request succeeded for account {}", account_name); + Ok(true) + } + ResponseState::Denied => { + debug!("Lock request denied for account {}", account_name); + Ok(false) + } + ResponseState::Unknown => bail!("Unknown response from lock account: {:?}", res), + ResponseState::Failed => bail!("Failed to lock account: {:?}", res), + } + } + /// Request a signature from the remote signer. pub async fn request_signature( &mut self, From eba70525a5eab5f6fea1ec5ac6b8b81b71c3b698 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:15:33 +0200 Subject: [PATCH 15/16] feat: add CI --- .github/workflows/bolt_cli_ci.yml | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/bolt_cli_ci.yml diff --git a/.github/workflows/bolt_cli_ci.yml b/.github/workflows/bolt_cli_ci.yml new file mode 100644 index 00000000..6ea7c18c --- /dev/null +++ b/.github/workflows/bolt_cli_ci.yml @@ -0,0 +1,46 @@ +name: Bolt CLI CI + +on: + push: + paths: + - "bolt-cli/**" + pull_request: + paths: + - "bolt-cli/**" + +env: + CARGO_TERM_COLOR: always + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + cargo-tests: + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + RUST_BACKTRACE: 1 + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + + - name: Cache cargo registry + uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Install cargo-nextest + uses: baptiste0928/cargo-install@v3 + with: + crate: cargo-nextest + + - name: Run bolt-cli tests + run: cd bolt-cli && cargo nextest run --workspace --retries 3 From 048a4d8c6eda207de8593a96955b6b102599d7a8 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:10:33 +0200 Subject: [PATCH 16/16] chore: rename binary: bolt-cli -> bol --- bolt-cli/Cargo.lock | 2 +- bolt-cli/Cargo.toml | 2 +- bolt-cli/README.md | 25 +++++++++++++------------ bolt-cli/src/utils/dirk.rs | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/bolt-cli/Cargo.lock b/bolt-cli/Cargo.lock index c514aedc..6fd80d82 100644 --- a/bolt-cli/Cargo.lock +++ b/bolt-cli/Cargo.lock @@ -593,7 +593,7 @@ dependencies = [ ] [[package]] -name = "bolt-cli" +name = "bolt" version = "0.1.0" dependencies = [ "alloy-primitives 0.8.9", diff --git a/bolt-cli/Cargo.toml b/bolt-cli/Cargo.toml index edf24d76..526ffeec 100644 --- a/bolt-cli/Cargo.toml +++ b/bolt-cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bolt-cli" +name = "bolt" version = "0.1.0" edition = "2021" diff --git a/bolt-cli/README.md b/bolt-cli/README.md index 2c398d3b..6f40376d 100644 --- a/bolt-cli/README.md +++ b/bolt-cli/README.md @@ -22,7 +22,7 @@ cd bolt-cli cargo install --path . --force # test the installation -bolt-cli --version +bolt --version ``` ## Usage @@ -49,11 +49,11 @@ To learn more about the Constraints API, please refer to the [Bolt documentation Usage ```text -❯ bolt-cli delegate --help +❯ bolt delegate --help Generate BLS delegation or revocation messages -Usage: bolt-cli delegate [OPTIONS] --delegatee-pubkey +Usage: bolt delegate [OPTIONS] --delegatee-pubkey Commands: secret-keys Use local secret keys to generate the signed messages @@ -102,7 +102,7 @@ Options: 1. Generating a delegation using a local BLS secret key ```text -bolt-cli delegate \ +bolt delegate \ --delegatee-pubkey 0x8d0edf4fe9c80cd640220ca7a68a48efcbc56a13536d6b274bf3719befaffa13688ebee9f37414b3dddc8c7e77233ce8 \ --chain holesky \ secret-keys --secret-keys 642e0d33fde8968a48b5f560c1b20143eb82036c1aa6c7f4adc4beed919a22e3 @@ -111,17 +111,18 @@ bolt-cli delegate \ 2. Generating a delegation using an ERC-2335 keystore directory ```text -bolt-cli delegate \ +bolt delegate \ --delegatee-pubkey 0x8d0edf4fe9c80cd640220ca7a68a48efcbc56a13536d6b274bf3719befaffa13688ebee9f37414b3dddc8c7e77233ce8 \ --chain holesky \ local-keystore --path test_data/lighthouse/validators --password-path test_data/lighthouse/secrets ``` -3. Generating a revocation using a remote DIRK keystore +3. Generating a delegation using a remote DIRK keystore ```text -bolt-cli delegate \ +bolt delegate \ --delegatee-pubkey 0x83eeddfac5e60f8fe607ee8713efb8877c295ad9f8ca075f4d8f6f2ae241a30dd57f78f6f3863a9fe0d5b5db9d550b93 \ + --chain holesky \ dirk --url https://localhost:9091 \ --client-cert-path ./test_data/dirk/client1.crt \ --client-key-path ./test_data/dirk/client1.key \ @@ -141,11 +142,11 @@ The `pubkeys` command lists available BLS public keys from different key sources Usage ```text -❯ bolt-cli pubkeys --help +❯ bolt pubkeys --help Output a list of pubkeys in JSON format -Usage: bolt-cli pubkeys [OPTIONS] +Usage: bolt pubkeys [OPTIONS] Commands: secret-keys Use local secret keys to generate the signed messages @@ -166,13 +167,13 @@ Options: 1. Listing BLS public keys from a local secret key ```text -bolt-cli pubkeys secret-keys --secret-keys 642e0d33fde8968a48b5f560c1b20143eb82036c1aa6c7f4adc4beed919a22e3 +bolt pubkeys secret-keys --secret-keys 642e0d33fde8968a48b5f560c1b20143eb82036c1aa6c7f4adc4beed919a22e3 ``` 2. Listing BLS public keys from an ERC-2335 keystore directory ```text -bolt-cli pubkeys local-keystore \ +bolt pubkeys local-keystore \ --path test_data/lighthouse/validators \ --password-path test_data/lighthouse/secrets ``` @@ -180,7 +181,7 @@ bolt-cli pubkeys local-keystore \ 3. Listing BLS public keys from a remote DIRK keystore ```text -bolt-cli pubkeys dirk --url https://localhost:9091 \ +bolt pubkeys dirk --url https://localhost:9091 \ --client-cert-path ./test_data/dirk/client1.crt \ --client-key-path ./test_data/dirk/client1.key \ --ca-cert-path ./test_data/dirk/security/ca.crt \ diff --git a/bolt-cli/src/utils/dirk.rs b/bolt-cli/src/utils/dirk.rs index b47ae94e..dc5e594e 100644 --- a/bolt-cli/src/utils/dirk.rs +++ b/bolt-cli/src/utils/dirk.rs @@ -160,7 +160,7 @@ mod tests { /// Test connecting to a DIRK server and listing available accounts. /// /// ```shell - /// cargo test --package bolt-cli --bin bolt-cli -- utils::dirk::tests::test_dirk_connection_e2e + /// cargo test --package bolt -- utils::dirk::tests::test_dirk_connection_e2e /// --exact --show-output --ignored /// ``` #[tokio::test]