From dbc6f2003762c823dfe578dbe347b42dabdecdda Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 6 Dec 2024 22:27:24 +0100 Subject: [PATCH 1/4] Downgrade parity-scale-codec as version we currently use has been yanked (#1205) Downgrade parity-scale-codec as current version has been yanked --- crates/testing-utils/Cargo.toml | 2 +- crates/threshold-signature-server/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/testing-utils/Cargo.toml b/crates/testing-utils/Cargo.toml index 510d81127..65c6fa263 100644 --- a/crates/testing-utils/Cargo.toml +++ b/crates/testing-utils/Cargo.toml @@ -13,7 +13,7 @@ subxt ="0.35.3" sp-keyring ="34.0.0" project-root ="0.2.2" sp-core ={ version="31.0.0", default-features=false } -parity-scale-codec="3.7.0" +parity-scale-codec="3.6.12" lazy_static ="1.5.0" hex-literal ="0.4.1" tokio ={ version="1.42", features=["macros", "fs", "rt-multi-thread", "io-util", "process"] } diff --git a/crates/threshold-signature-server/Cargo.toml b/crates/threshold-signature-server/Cargo.toml index 78147abed..441e3db2b 100644 --- a/crates/threshold-signature-server/Cargo.toml +++ b/crates/threshold-signature-server/Cargo.toml @@ -36,7 +36,7 @@ axum ={ version="0.7.9", features=["ws"] } # Substrate subxt ="0.35.3" -parity-scale-codec="3.7.0" +parity-scale-codec="3.6.12" sp-core ={ version="31.0.0", default-features=false } # Entropy From 808645f6af26c31a7fdc087bd242b52d02d0e861 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 07:27:56 +0000 Subject: [PATCH 2/4] Bump thiserror from 2.0.4 to 2.0.6 in the patch-dependencies group (#1206) Bumps the patch-dependencies group with 1 update: [thiserror](https://github.com/dtolnay/thiserror). Updates `thiserror` from 2.0.4 to 2.0.6 - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/2.0.4...2.0.6) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 18 +++++++++--------- crates/client/Cargo.toml | 2 +- crates/kvdb/Cargo.toml | 2 +- crates/protocol/Cargo.toml | 2 +- crates/threshold-signature-server/Cargo.toml | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6067d3b0..cdf55f3b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2547,7 +2547,7 @@ dependencies = [ "subxt", "synedrion", "tdx-quote", - "thiserror 2.0.4", + "thiserror 2.0.6", "tokio", "tracing", "x25519-dalek 2.0.1", @@ -2582,7 +2582,7 @@ dependencies = [ "sled", "sp-core 31.0.0", "synedrion", - "thiserror 2.0.4", + "thiserror 2.0.6", "tokio", "tracing", "zeroize", @@ -2642,7 +2642,7 @@ dependencies = [ "sp-keyring 34.0.0", "subxt", "synedrion", - "thiserror 2.0.4", + "thiserror 2.0.6", "tokio", "tokio-tungstenite", "tracing", @@ -2858,7 +2858,7 @@ dependencies = [ "subxt-signer", "synedrion", "tdx-quote", - "thiserror 2.0.4", + "thiserror 2.0.6", "tokio", "tokio-tungstenite", "tower-http 0.6.2", @@ -14334,11 +14334,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" dependencies = [ - "thiserror-impl 2.0.4", + "thiserror-impl 2.0.6", ] [[package]] @@ -14354,9 +14354,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 4d8ea2e9f..66a2244a8 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -14,7 +14,7 @@ serde ={ version="1.0", default-features=false, features=["derive"] } entropy-shared={ version="0.3.0", path="../shared", default-features=false } subxt ={ version="0.35.3", default-features=false, features=["jsonrpsee"] } num ="0.4.3" -thiserror ="2.0.4" +thiserror ="2.0.6" futures ="0.3" sp-core ={ version="31.0.0", default-features=false, features=["full_crypto", "serde"] } tracing ="0.1.41" diff --git a/crates/kvdb/Cargo.toml b/crates/kvdb/Cargo.toml index 6c9f3702d..2d8a7d22d 100644 --- a/crates/kvdb/Cargo.toml +++ b/crates/kvdb/Cargo.toml @@ -12,7 +12,7 @@ edition ='2021' # Common rand ={ version="0.8", default-features=false } serde ={ version="1.0", features=["derive"] } -thiserror="2.0.4" +thiserror="2.0.6" hex ="0.4.3" # Substrate diff --git a/crates/protocol/Cargo.toml b/crates/protocol/Cargo.toml index 09ea23155..c6b542101 100644 --- a/crates/protocol/Cargo.toml +++ b/crates/protocol/Cargo.toml @@ -20,7 +20,7 @@ x25519-dalek ={ version="2.0.1", features=["static_secrets"] } futures ="0.3" hex ="0.4.3" blake2 ="0.10.4" -thiserror ="2.0.4" +thiserror ="2.0.6" snow ="0.9.6" getrandom ={ version="0.2", features=["js"] } rand_core ={ version="0.6.4", features=["getrandom"] } diff --git a/crates/threshold-signature-server/Cargo.toml b/crates/threshold-signature-server/Cargo.toml index 441e3db2b..e1a299245 100644 --- a/crates/threshold-signature-server/Cargo.toml +++ b/crates/threshold-signature-server/Cargo.toml @@ -12,7 +12,7 @@ edition ='2021' # Common serde ={ version="1.0", default-features=false, features=["derive"] } serde_json ="1.0" -thiserror ="2.0.4" +thiserror ="2.0.6" anyhow ="1.0.94" blake2 ="0.10.4" x25519-dalek ={ version="2.0.1", features=["static_secrets"] } From cfcb3672c8ce931ba13420aa474b03b07e399f99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 07:37:07 +0000 Subject: [PATCH 3/4] Bump the patch-dependencies group with 2 updates (#1212) Bumps the patch-dependencies group with 2 updates: [serde](https://github.com/serde-rs/serde) and [serde_derive](https://github.com/serde-rs/serde). Updates `serde` from 1.0.215 to 1.0.216 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.215...v1.0.216) Updates `serde_derive` from 1.0.215 to 1.0.216 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.215...v1.0.216) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-dependencies - dependency-name: serde_derive dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- crates/test-cli/Cargo.toml | 2 +- node/cli/Cargo.toml | 2 +- pallets/staking/Cargo.toml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdf55f3b5..298582681 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11596,9 +11596,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -11625,9 +11625,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", diff --git a/crates/test-cli/Cargo.toml b/crates/test-cli/Cargo.toml index d9d9fc141..23c8c67b8 100644 --- a/crates/test-cli/Cargo.toml +++ b/crates/test-cli/Cargo.toml @@ -22,5 +22,5 @@ x25519-dalek ="2.0.1" sp-runtime ={ version="32.0.0", default-features=false } entropy-shared={ version="0.3.0", path="../shared" } serde_json ="1.0.133" -serde ={ version="1.0.215", features=["derive"] } +serde ={ version="1.0.216", features=["derive"] } reqwest ="0.12.9" diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index a33fbdefd..b1cf2d0cb 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -29,7 +29,7 @@ lazy_static ={ version="1.5.0", features=["spin_no_std"] } log ="0.4.22" pallet-im-online={ version="28.0.0" } rand ="0.8.5" -serde ={ version="1.0.215", features=["derive"] } +serde ={ version="1.0.216", features=["derive"] } serde_json ='1.0.133' # Substrate Client diff --git a/pallets/staking/Cargo.toml b/pallets/staking/Cargo.toml index 70da4e1c2..3cb777887 100644 --- a/pallets/staking/Cargo.toml +++ b/pallets/staking/Cargo.toml @@ -15,7 +15,7 @@ targets=['x86_64-unknown-linux-gnu'] codec ={ package="parity-scale-codec", version="3.6.3", default-features=false, features=["derive"] } scale-info ={ version="2.11", default-features=false, features=["derive"] } log ={ version="0.4.22", default-features=false } -serde ={ version="1.0.215", default-features=false } +serde ={ version="1.0.216", default-features=false } rand_chacha={ version="0.3", default-features=false } frame-benchmarking={ version="29.0.0", default-features=false, optional=true } From 6d3351eb347d5ff5812e49cfdd2ae1a6e6b06c73 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 11 Dec 2024 08:43:48 +0100 Subject: [PATCH 4/4] Test CLI command to retrieve quote and change endpoint / TSS account in one command (#1198) * Add get_quote_and_change_endpoint client fn, error handling * Cli command to change endpoint no longer takes quote * Doccomments * Clippy * Add context when calling attest endpoint * Error handle http response in GetTdxQuote command * Improve error handling when getting quotes * Use display not debug for building quote context querystring * Refactor handling of mnemonics in test-cli * Update change TSS endpoints client function and CLI command * get-tdx-quote command now takes quote context as an arguement * Changelog * Use From not Into --- CHANGELOG.md | 1 + crates/client/src/client.rs | 110 +++++++++++++++++++++++------ crates/client/src/errors.rs | 4 ++ crates/client/src/tests.rs | 4 +- crates/shared/src/types.rs | 12 ++++ crates/test-cli/src/lib.rs | 136 ++++++++++++++++-------------------- 6 files changed, 166 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f64774980..3c1670223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ runtime - Protocol message versioning ([#1140](https://github.com/entropyxyz/entropy-core/pull/1140)) - CLI command to get oracle headings ([#1170](https://github.com/entropyxyz/entropy-core/pull/1170)) - Add TSS endpoint to get TDX quote ([#1173](https://github.com/entropyxyz/entropy-core/pull/1173)) +- Test CLI command to retrieve quote and change endpoint / TSS account in one command ([#1198](https://github.com/entropyxyz/entropy-core/pull/1198)) ### Changed - Use correct key rotation endpoint in OCW ([#1104](https://github.com/entropyxyz/entropy-core/pull/1104)) diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 062de590a..71a5c240f 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -17,13 +17,12 @@ //! Used in integration tests and for the test-cli pub use crate::{ chain_api::{get_api, get_rpc}, - errors::ClientError, + errors::{ClientError, SubstrateError}, }; -use anyhow::anyhow; pub use entropy_protocol::{sign_and_encrypt::EncryptedSignedMessage, KeyParams}; +pub use entropy_shared::{HashingAlgorithm, QuoteContext}; use parity_scale_codec::Decode; use rand::Rng; -use std::str::FromStr; pub use synedrion::KeyShare; use crate::{ @@ -39,7 +38,7 @@ use crate::{ EntropyConfig, }, client::entropy::staking_extension::events::{EndpointChanged, ThresholdAccountChanged}, - substrate::{get_registered_details, submit_transaction_with_pair}, + substrate::{get_registered_details, query_chain, submit_transaction_with_pair}, user::{ self, get_all_signers_from_chain, get_validators_not_signer_for_relay, UserSignatureRequest, }, @@ -48,7 +47,6 @@ use crate::{ use base64::prelude::{Engine, BASE64_STANDARD}; use entropy_protocol::RecoverableSignature; -use entropy_shared::HashingAlgorithm; use futures::stream::StreamExt; use sp_core::{ sr25519::{self, Signature}, @@ -338,50 +336,90 @@ pub async fn put_register_request_on_chain( registered_event } -/// Changes the endpoint of a validator +/// Changes the endpoint of a validator, retrieving a TDX quote from the new endpoint internally +pub async fn get_quote_and_change_endpoint( + api: &OnlineClient, + rpc: &LegacyRpcMethods, + validator_keypair: sr25519::Pair, + new_endpoint: String, +) -> Result { + let quote = get_tdx_quote(&new_endpoint, QuoteContext::ChangeEndpoint).await?; + change_endpoint(api, rpc, validator_keypair, new_endpoint, quote).await +} + +/// Changes the endpoint of a validator, with a TDX quote given as an argument pub async fn change_endpoint( api: &OnlineClient, rpc: &LegacyRpcMethods, user_keypair: sr25519::Pair, new_endpoint: String, quote: Vec, -) -> anyhow::Result { +) -> Result { let change_endpoint_tx = entropy::tx().staking_extension().change_endpoint(new_endpoint.into(), quote); let in_block = submit_transaction_with_pair(api, rpc, &user_keypair, &change_endpoint_tx, None).await?; let result_event = in_block .find_first::()? - .ok_or(anyhow!("Error with transaction"))?; + .ok_or(SubstrateError::NoEvent)?; Ok(result_event) } +/// Changes the threshold account info of a validator, retrieving a TDX quote from the new endpoint internally +pub async fn get_quote_and_change_threshold_accounts( + api: &OnlineClient, + rpc: &LegacyRpcMethods, + validator_keypair: sr25519::Pair, + new_tss_account: SubxtAccountId32, + new_x25519_public_key: [u8; 32], + new_pck_certificate_chain: Vec>, +) -> Result { + let quote = get_tdx_quote_with_validator_id( + api, + rpc, + &SubxtAccountId32(validator_keypair.public().0), + QuoteContext::ChangeThresholdAccounts, + ) + .await?; + change_threshold_accounts( + api, + rpc, + validator_keypair, + new_tss_account, + new_x25519_public_key, + new_pck_certificate_chain, + quote, + ) + .await +} + /// Changes the threshold account info of a validator pub async fn change_threshold_accounts( api: &OnlineClient, rpc: &LegacyRpcMethods, - user_keypair: sr25519::Pair, - new_tss_account: String, - new_x25519_public_key: String, + validator_keypair: sr25519::Pair, + new_tss_account: SubxtAccountId32, + new_x25519_public_key: [u8; 32], new_pck_certificate_chain: Vec>, quote: Vec, -) -> anyhow::Result { - let tss_account = SubxtAccountId32::from_str(&new_tss_account)?; - let x25519_public_key = hex::decode(new_x25519_public_key)? - .try_into() - .map_err(|_| anyhow!("X25519 pub key needs to be 32 bytes"))?; +) -> Result { let change_threshold_accounts = entropy::tx().staking_extension().change_threshold_accounts( - tss_account, - x25519_public_key, + new_tss_account, + new_x25519_public_key, new_pck_certificate_chain, quote, ); - let in_block = - submit_transaction_with_pair(api, rpc, &user_keypair, &change_threshold_accounts, None) - .await?; + let in_block = submit_transaction_with_pair( + api, + rpc, + &validator_keypair, + &change_threshold_accounts, + None, + ) + .await?; let result_event = in_block .find_first::()? - .ok_or(anyhow!("Error with transaction"))?; + .ok_or(SubstrateError::NoEvent)?; Ok(result_event) } @@ -463,3 +501,31 @@ pub async fn get_oracle_headings( } Ok(headings) } + +/// Retrieve a TDX quote using the currently configured endpoint associated with the given validator +/// ID +pub async fn get_tdx_quote_with_validator_id( + api: &OnlineClient, + rpc: &LegacyRpcMethods, + validator_stash: &SubxtAccountId32, + quote_context: QuoteContext, +) -> Result, ClientError> { + let query = entropy::storage().staking_extension().threshold_servers(validator_stash); + let server_info = query_chain(api, rpc, query, None).await?.ok_or(ClientError::NoServerInfo)?; + + let tss_endpoint = std::str::from_utf8(&server_info.endpoint)?; + get_tdx_quote(tss_endpoint, quote_context).await +} + +/// Retrieve a TDX quote with a given socket address +pub async fn get_tdx_quote( + tss_endpoint: &str, + quote_context: QuoteContext, +) -> Result, ClientError> { + let response = + reqwest::get(format!("http://{}/attest?context={}", tss_endpoint, quote_context)).await?; + if response.status() != reqwest::StatusCode::OK { + return Err(ClientError::QuoteGet(response.text().await?)); + } + Ok(response.bytes().await?.to_vec()) +} diff --git a/crates/client/src/errors.rs b/crates/client/src/errors.rs index c2f4ab241..61cd74d8f 100644 --- a/crates/client/src/errors.rs +++ b/crates/client/src/errors.rs @@ -123,4 +123,8 @@ pub enum ClientError { Codec(#[from] parity_scale_codec::Error), #[error("Attestation request: {0}")] AttestationRequest(#[from] AttestationRequestError), + #[error("Unable to get TDX quote: {0}")] + QuoteGet(String), + #[error("Unable to get info for TSS server from chain")] + NoServerInfo, } diff --git a/crates/client/src/tests.rs b/crates/client/src/tests.rs index 52abd3329..a42b7758e 100644 --- a/crates/client/src/tests.rs +++ b/crates/client/src/tests.rs @@ -141,8 +141,8 @@ async fn test_change_threshold_accounts() { &api, &rpc, one.into(), - tss_public_key.to_string(), - hex::encode(*x25519_public_key.as_bytes()), + tss_public_key.into(), + *x25519_public_key.as_bytes(), pck_certificate_chain, quote, ) diff --git a/crates/shared/src/types.rs b/crates/shared/src/types.rs index d6156a0be..2de1b647c 100644 --- a/crates/shared/src/types.rs +++ b/crates/shared/src/types.rs @@ -146,6 +146,18 @@ pub enum QuoteContext { ChangeThresholdAccounts, } +#[cfg(feature = "std")] +impl std::fmt::Display for QuoteContext { + /// Custom display implementation so that it can be used to build a query string + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + QuoteContext::Validate => write!(f, "validate"), + QuoteContext::ChangeEndpoint => write!(f, "change_endpoint"), + QuoteContext::ChangeThresholdAccounts => write!(f, "change_threshold_accounts"), + } + } +} + /// A trait for types which can handle attestation requests. #[cfg(not(feature = "wasm"))] pub trait AttestationHandler { diff --git a/crates/test-cli/src/lib.rs b/crates/test-cli/src/lib.rs index 8b76fe5f8..42a030545 100644 --- a/crates/test-cli/src/lib.rs +++ b/crates/test-cli/src/lib.rs @@ -15,7 +15,7 @@ //! Simple CLI to test registering, updating programs and signing use anyhow::{anyhow, ensure}; -use clap::{Parser, Subcommand}; +use clap::{Parser, Subcommand, ValueEnum}; use colored::Colorize; use entropy_client::{ chain_api::{ @@ -27,15 +27,15 @@ use entropy_client::{ EntropyConfig, }, client::{ - change_endpoint, change_threshold_accounts, get_accounts, get_api, get_oracle_headings, - get_programs, get_rpc, jumpstart_network, register, remove_program, sign, store_program, - update_programs, VERIFYING_KEY_LENGTH, + get_accounts, get_api, get_oracle_headings, get_programs, get_quote_and_change_endpoint, + get_quote_and_change_threshold_accounts, get_rpc, get_tdx_quote, jumpstart_network, + register, remove_program, sign, store_program, update_programs, VERIFYING_KEY_LENGTH, }, }; -pub use entropy_shared::PROGRAM_VERSION_NUMBER; +pub use entropy_shared::{QuoteContext, PROGRAM_VERSION_NUMBER}; use sp_core::{sr25519, Hasher, Pair}; use sp_runtime::{traits::BlakeTwo256, Serialize}; -use std::{fs, path::PathBuf}; +use std::{fs, path::PathBuf, str::FromStr}; use subxt::{ backend::legacy::LegacyRpcMethods, utils::{AccountId32 as SubxtAccountId32, H256}, @@ -150,11 +150,6 @@ enum CliCommand { ChangeEndpoint { /// New endpoint to change to (ex. "127.0.0.1:3001") new_endpoint: String, - /// The Intel TDX quote used to prove that this TSS is running on TDX hardware. - /// - /// The quote format is specified in: - /// https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf - quote: String, /// The mnemonic for the validator stash account to use for the call, should be stash address #[arg(short, long)] mnemonic_option: Option, @@ -167,11 +162,6 @@ enum CliCommand { new_x25519_public_key: String, /// The new Provisioning Certification Key (PCK) certificate chain to be used for the TSS. new_pck_certificate_chain: Vec, - /// The Intel TDX quote used to prove that this TSS is running on TDX hardware. - /// - /// The quote format is specified in: - /// https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf - quote: String, /// The mnemonic for the validator stash account to use for the call, should be stash address #[arg(short, long)] mnemonic_option: Option, @@ -197,6 +187,9 @@ enum CliCommand { GetTdxQuote { /// The socket address of the TS server, eg: `127.0.0.1:3002` tss_endpoint: String, + /// The context in which this quote will be used. Must be one of + #[arg(value_enum)] + quote_context: QuoteContextArg, /// The filename to write the quote to. Defaults to `quote.dat` #[arg(long)] output_filename: Option, @@ -222,20 +215,12 @@ pub async fn run_command( std::env::var("ENTROPY_DEVNET").unwrap_or("ws://localhost:9944".to_string()) }); - let passed_mnemonic = std::env::var("DEPLOYER_MNEMONIC"); - let api = get_api(&endpoint_addr).await?; let rpc = get_rpc(&endpoint_addr).await?; match cli.command.clone() { CliCommand::Register { mnemonic_option, programs, program_version_numbers } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.expect("No mnemonic set") - }; - - let program_keypair = ::from_string(&mnemonic, None)?; + let program_keypair = handle_mnemonic(mnemonic_option)?; let program_account = SubxtAccountId32(program_keypair.public().0); cli.log(format!("Program account: {}", program_keypair.public())); @@ -274,13 +259,9 @@ pub async fn run_command( } }, CliCommand::Sign { signature_verifying_key, message, auxilary_data, mnemonic_option } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.unwrap_or("//Alice".to_string()) - }; // If an account name is not provided, use the Alice key - let user_keypair = ::from_string(&mnemonic, None)?; + let user_keypair = handle_mnemonic(mnemonic_option) + .unwrap_or(::from_string("//Alice", None)?); cli.log(format!("User account for current call: {}", user_keypair.public())); @@ -315,12 +296,7 @@ pub async fn run_command( aux_data_interface_file, program_version_number, } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.expect("No Mnemonic set") - }; - let keypair = ::from_string(&mnemonic, None)?; + let keypair = handle_mnemonic(mnemonic_option)?; cli.log(format!("Storing program using account: {}", keypair.public())); let program = match program_file { @@ -370,12 +346,7 @@ pub async fn run_command( } }, CliCommand::RemoveProgram { mnemonic_option, hash } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.expect("No Mnemonic set") - }; - let keypair = ::from_string(&mnemonic, None)?; + let keypair = handle_mnemonic(mnemonic_option)?; cli.log(format!("Removing program using account: {}", keypair.public())); let hash: [u8; 32] = hex::decode(hash)? @@ -396,12 +367,7 @@ pub async fn run_command( programs, program_version_numbers, } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.expect("No Mnemonic set") - }; - let program_keypair = ::from_string(&mnemonic, None)?; + let program_keypair = handle_mnemonic(mnemonic_option)?; cli.log(format!("Program account: {}", program_keypair.public())); let mut programs_info = Vec::new(); @@ -499,18 +465,12 @@ pub async fn run_command( Ok("Got status".to_string()) } }, - CliCommand::ChangeEndpoint { new_endpoint, quote, mnemonic_option } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.expect("No Mnemonic set") - }; - - let user_keypair = ::from_string(&mnemonic, None)?; + CliCommand::ChangeEndpoint { new_endpoint, mnemonic_option } => { + let user_keypair = handle_mnemonic(mnemonic_option)?; cli.log(format!("User account for current call: {}", user_keypair.public())); let result_event = - change_endpoint(&api, &rpc, user_keypair, new_endpoint, quote.into()).await?; + get_quote_and_change_endpoint(&api, &rpc, user_keypair, new_endpoint).await?; cli.log(format!("Event result: {:?}", result_event)); if cli.json { @@ -523,27 +483,24 @@ pub async fn run_command( new_tss_account, new_x25519_public_key, new_pck_certificate_chain, - quote, mnemonic_option, } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.expect("No Mnemonic set") - }; - let user_keypair = ::from_string(&mnemonic, None)?; + let user_keypair = handle_mnemonic(mnemonic_option)?; cli.log(format!("User account for current call: {}", user_keypair.public())); + let new_tss_account = SubxtAccountId32::from_str(&new_tss_account)?; + let new_x25519_public_key = hex::decode(new_x25519_public_key)? + .try_into() + .map_err(|_| anyhow!("X25519 pub key needs to be 32 bytes"))?; let new_pck_certificate_chain = new_pck_certificate_chain.iter().cloned().map(|i| i.into()).collect::<_>(); - let result_event = change_threshold_accounts( + let result_event = get_quote_and_change_threshold_accounts( &api, &rpc, user_keypair, new_tss_account, new_x25519_public_key, new_pck_certificate_chain, - quote.into(), ) .await?; cli.log(format!("Event result: {:?}", result_event)); @@ -555,13 +512,7 @@ pub async fn run_command( } }, CliCommand::JumpstartNetwork { mnemonic_option } => { - let mnemonic = if let Some(mnemonic_option) = mnemonic_option { - mnemonic_option - } else { - passed_mnemonic.unwrap_or("//Alice".to_string()) - }; - - let signer = ::from_string(&mnemonic, None)?; + let signer = handle_mnemonic(mnemonic_option)?; cli.log(format!("Account being used for jumpstart: {}", signer.public())); jumpstart_network(&api, &rpc, signer).await?; @@ -576,9 +527,8 @@ pub async fn run_command( let headings = get_oracle_headings(&api, &rpc).await?; Ok(serde_json::to_string_pretty(&headings)?) }, - CliCommand::GetTdxQuote { tss_endpoint, output_filename } => { - let quote_bytes = - reqwest::get(format!("http://{}/attest", tss_endpoint)).await?.bytes().await?; + CliCommand::GetTdxQuote { tss_endpoint, output_filename, quote_context } => { + let quote_bytes = get_tdx_quote(&tss_endpoint, quote_context.into()).await?; let output_filename = output_filename.unwrap_or("quote.dat".into()); std::fs::write(&output_filename, quote_bytes)?; @@ -713,3 +663,35 @@ impl StatusOutput { Self { accounts, programs } } } + +/// Get an sr25519 from a mnemonic given as either option or environment variable +fn handle_mnemonic(mnemonic_option: Option) -> anyhow::Result { + let mnemonic = if let Some(mnemonic) = mnemonic_option { + mnemonic + } else { + std::env::var("DEPLOYER_MNEMONIC") + .map_err(|_| anyhow!("A mnemonic must be given either by the command line option or DEPLOYER_MNEMONIC environment variable"))? + }; + Ok(::from_string(&mnemonic, None)?) +} + +/// This is the same as [QuoteContext] but implements [ValueEnum] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)] +enum QuoteContextArg { + /// To be used in the `validate` extrinsic + Validate, + /// To be used in the `change_endpoint` extrinsic + ChangeEndpoint, + /// To be used in the `change_threshold_accounts` extrinsic + ChangeThresholdAccounts, +} + +impl From for QuoteContext { + fn from(quote_context: QuoteContextArg) -> Self { + match quote_context { + QuoteContextArg::Validate => QuoteContext::Validate, + QuoteContextArg::ChangeEndpoint => QuoteContext::ChangeEndpoint, + QuoteContextArg::ChangeThresholdAccounts => QuoteContext::ChangeThresholdAccounts, + } + } +}