From f2fa13e31534506ec4b542e5dca5667935b839b7 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Fri, 6 Sep 2024 22:13:22 +0800 Subject: [PATCH 1/3] print command for spin up a local mpc cluster --- integration-tests/chain-signatures/Cargo.lock | 1 + integration-tests/chain-signatures/Cargo.toml | 1 + .../chain-signatures/src/execute.rs | 2 +- integration-tests/chain-signatures/src/lib.rs | 40 +++++++++++++++ .../chain-signatures/src/local.rs | 50 +++++++++++++++++++ .../chain-signatures/src/main.rs | 12 +++-- 6 files changed, 102 insertions(+), 4 deletions(-) diff --git a/integration-tests/chain-signatures/Cargo.lock b/integration-tests/chain-signatures/Cargo.lock index ed5444513..eb1db9590 100644 --- a/integration-tests/chain-signatures/Cargo.lock +++ b/integration-tests/chain-signatures/Cargo.lock @@ -3763,6 +3763,7 @@ dependencies = [ "secp256k1 0.28.2", "serde", "serde_json", + "shell-escape", "test-log", "testcontainers", "thiserror", diff --git a/integration-tests/chain-signatures/Cargo.toml b/integration-tests/chain-signatures/Cargo.toml index 2f638cbc0..fa906b920 100644 --- a/integration-tests/chain-signatures/Cargo.toml +++ b/integration-tests/chain-signatures/Cargo.toml @@ -19,6 +19,7 @@ rand = "0.7" reqwest = "0.11.16" serde = "1" serde_json = "1" +shell-escape = "0.1.5" testcontainers = { version = "0.15", features = ["experimental"] } tokio = { version = "1.28", features = ["full"] } tracing = "0.1" diff --git a/integration-tests/chain-signatures/src/execute.rs b/integration-tests/chain-signatures/src/execute.rs index 030f5ff3a..1967e5d9d 100644 --- a/integration-tests/chain-signatures/src/execute.rs +++ b/integration-tests/chain-signatures/src/execute.rs @@ -1,7 +1,7 @@ use anyhow::Context; use async_process::Child; -const PACKAGE_MULTICHAIN: &str = "mpc-node"; +pub(crate) const PACKAGE_MULTICHAIN: &str = "mpc-node"; pub fn target_dir() -> Option { let mut out_dir = std::path::Path::new(std::env!("OUT_DIR")); diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 0084ec00b..15b9cb4dd 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -345,6 +345,38 @@ pub async fn docker(cfg: MultichainConfig, docker_client: &DockerClient) -> anyh Ok(Nodes::Docker { ctx, nodes }) } +pub async fn dry_host(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow::Result<()> { + let ctx = setup(docker_client).await?; + + let accounts = + futures::future::join_all((0..cfg.nodes).map(|_| ctx.worker.dev_create_account())) + .await + .into_iter() + .collect::, _>>()?; + for account in accounts.iter().take(cfg.nodes) { + local::Node::dry_run( + &ctx, + account.id(), + account.secret_key(), + &cfg, + ).await?; + } + println!("\nAfter run the nodes, please call the following command to init contract: "); + println!("near call {}", ctx.mpc_contract.id()); + println!(); + + Ok(()) + // ctx.mpc_contract + // .call("init") + // .args_json(json!({ + // "threshold": cfg.threshold, + // "candidates": candidates + // })) + // .transact() + // .await? + // .into_result()?; +} + pub async fn host(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow::Result { let ctx = setup(docker_client).await?; @@ -403,6 +435,14 @@ pub async fn run(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow: return host(cfg, docker_client).await; } +pub async fn dry_run(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow::Result<()> { + #[cfg(feature = "docker-test")] + return dry_docker(cfg, docker_client).await; + + #[cfg(not(feature = "docker-test"))] + return dry_host(cfg, docker_client).await; +} + async fn fetch_from_validator( docker_client: &containers::DockerClient, container: &Container<'_, GenericImage>, diff --git a/integration-tests/chain-signatures/src/local.rs b/integration-tests/chain-signatures/src/local.rs index 3359675d7..0be1cfda1 100644 --- a/integration-tests/chain-signatures/src/local.rs +++ b/integration-tests/chain-signatures/src/local.rs @@ -5,6 +5,9 @@ use async_process::Child; use mpc_keys::hpke; use mpc_node::config::OverrideConfig; use near_workspaces::AccountId; +use crate::execute::executable; +use anyhow::Context; +use shell_escape::escape; pub struct Node { pub address: String, @@ -34,6 +37,53 @@ pub struct NodeConfig { } impl Node { + pub async fn dry_run( + ctx: &super::Context<'_>, + account_id: &AccountId, + account_sk: &near_workspaces::types::SecretKey, + cfg: &MultichainConfig, + ) -> anyhow::Result<()> { + let web_port = utils::pick_unused_port().await?; + let (cipher_sk, cipher_pk) = hpke::generate(); + let sign_sk = + near_crypto::SecretKey::from_seed(near_crypto::KeyType::ED25519, "integration-test"); + + let indexer_options = mpc_node::indexer::Options { + s3_bucket: ctx.localstack.s3_bucket.clone(), + s3_region: ctx.localstack.s3_region.clone(), + s3_url: Some(ctx.localstack.s3_host_address.clone()), + start_block_height: 0, + running_threshold: 120, + behind_threshold: 120, + }; + let near_rpc = ctx.lake_indexer.rpc_host_address.clone(); + let mpc_contract_id = ctx.mpc_contract.id().clone(); + let cli = mpc_node::cli::Cli::Start { + near_rpc, + mpc_contract_id: mpc_contract_id.clone(), + account_id: account_id.clone(), + account_sk: account_sk.to_string().parse()?, + web_port, + cipher_pk: hex::encode(cipher_pk.to_bytes()), + cipher_sk: hex::encode(cipher_sk.to_bytes()), + sign_sk: Some(sign_sk.clone()), + indexer_options, + my_address: None, + storage_options: ctx.storage_options.clone(), + override_config: Some(OverrideConfig::new(serde_json::to_value( + cfg.protocol.clone(), + )?)), + client_header_referer: None, + }; + + let cmd = executable(ctx.release, crate::execute::PACKAGE_MULTICHAIN) + .with_context(|| "could not find target dir for mpc-node")?; + let args = cli.into_str_args(); + let escaped_args: Vec<_> = args.iter().map(|arg| escape(arg.clone().into()).to_string()).collect(); + println!("\nCommand to run node {}:\n {} {}", account_id, cmd.to_str().unwrap(), escaped_args.join(" ")); + Ok(()) + } + pub async fn run( ctx: &super::Context<'_>, account_id: &AccountId, diff --git a/integration-tests/chain-signatures/src/main.rs b/integration-tests/chain-signatures/src/main.rs index ac2c09793..54e707f40 100644 --- a/integration-tests/chain-signatures/src/main.rs +++ b/integration-tests/chain-signatures/src/main.rs @@ -1,6 +1,6 @@ use clap::Parser; use integration_tests_chain_signatures::containers::DockerClient; -use integration_tests_chain_signatures::{run, setup, utils, MultichainConfig}; +use integration_tests_chain_signatures::{run, setup, utils, MultichainConfig, dry_run}; use tokio::signal; use tracing_subscriber::EnvFilter; @@ -70,8 +70,14 @@ async fn main() -> anyhow::Result<()> { println!("Clean up finished"); } Cli::DepServices => { - println!("Settting up dependency services"); - let _ctx = setup(&docker_client).await?; + println!("Setting up dependency services"); + let config = MultichainConfig::default(); + let nodes = dry_run(config.clone(), &docker_client).await?; + + println!("Press Ctrl-C to stop dependency services"); + signal::ctrl_c().await.expect("Failed to listen for event"); + println!("Received Ctrl-C"); + println!("Stopped dependency services"); } } From fa4b2c65610e704cc5153157324e5fd1fc587ffd Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Tue, 8 Oct 2024 17:07:26 +0800 Subject: [PATCH 2/3] fixed all command lines --- integration-tests/chain-signatures/src/lib.rs | 68 +++++++++++++------ .../chain-signatures/src/local.rs | 36 +++++++--- .../chain-signatures/src/main.rs | 4 +- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 713911901..a8f7bb273 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -19,6 +19,7 @@ use mpc_node::storage; use mpc_node::storage::triple_storage::TripleNodeStorageBox; use near_crypto::KeyFile; use near_workspaces::network::{Sandbox, ValidatorKey}; +use near_workspaces::types::{KeyType, SecretKey}; use near_workspaces::{Account, AccountId, Contract, Worker}; use serde_json::json; use testcontainers::{Container, GenericImage}; @@ -298,7 +299,10 @@ pub async fn docker(cfg: MultichainConfig, docker_client: &DockerClient) -> anyh Ok(Nodes::Docker { ctx, nodes }) } -pub async fn dry_host(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow::Result<()> { +pub async fn dry_host( + cfg: MultichainConfig, + docker_client: &DockerClient, +) -> anyhow::Result { let ctx = setup(docker_client).await?; let accounts = @@ -306,28 +310,49 @@ pub async fn dry_host(cfg: MultichainConfig, docker_client: &DockerClient) -> an .await .into_iter() .collect::, _>>()?; + let mut node_cfgs = Vec::new(); for account in accounts.iter().take(cfg.nodes) { - local::Node::dry_run( - &ctx, - account.id(), - account.secret_key(), - &cfg, - ).await?; + node_cfgs.push(local::Node::dry_run(&ctx, &account, &cfg).await?); } + + let candidates: HashMap = accounts + .iter() + .cloned() + .zip(&node_cfgs) + .map(|(account, node_cfg)| { + ( + account.id().clone(), + CandidateInfo { + account_id: account.id().as_str().parse().unwrap(), + url: format!("http://127.0.0.1:{0}", node_cfg.web_port), + cipher_pk: node_cfg.cipher_pk.to_bytes(), + sign_pk: node_cfg.sign_sk.public_key().to_string().parse().unwrap(), + }, + ) + }) + .collect(); + + println!("\nPlease call below to update localnet:\n"); + let near_rpc = ctx.lake_indexer.rpc_host_address.clone(); + println!("near config add-connection --network-name local --connection-name local --rpc-url {} --wallet-url http://127.0.0.1/ --explorer-transaction-url http://127.0.0.1:6666/", near_rpc); println!("\nAfter run the nodes, please call the following command to init contract: "); - println!("near call {}", ctx.mpc_contract.id()); + let args = json!({ + "threshold": cfg.threshold, + "candidates": candidates + }) + .to_string(); + let sk = SecretKey::from_seed(KeyType::ED25519, "testificate"); + + println!("near contract call-function as-transaction {} init json-args '{}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as {} network-config local sign-with-plaintext-private-key --signer-public-key {} --signer-private-key {} send", + ctx.mpc_contract.id(), + args, + ctx.mpc_contract.id(), + sk.public_key().to_string(), + sk.to_string() + ); println!(); - Ok(()) - // ctx.mpc_contract - // .call("init") - // .args_json(json!({ - // "threshold": cfg.threshold, - // "candidates": candidates - // })) - // .transact() - // .await? - // .into_result()?; + Ok(ctx) } pub async fn host(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow::Result { @@ -383,9 +408,12 @@ pub async fn run(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow: return host(cfg, docker_client).await; } -pub async fn dry_run(cfg: MultichainConfig, docker_client: &DockerClient) -> anyhow::Result<()> { +pub async fn dry_run( + cfg: MultichainConfig, + docker_client: &DockerClient, +) -> anyhow::Result { #[cfg(feature = "docker-test")] - return dry_docker(cfg, docker_client).await; + unimplemented!("dry_run only works with native node"); #[cfg(not(feature = "docker-test"))] return dry_host(cfg, docker_client).await; diff --git a/integration-tests/chain-signatures/src/local.rs b/integration-tests/chain-signatures/src/local.rs index e662964b3..a3051b6b4 100644 --- a/integration-tests/chain-signatures/src/local.rs +++ b/integration-tests/chain-signatures/src/local.rs @@ -1,12 +1,12 @@ use crate::{execute, utils, MultichainConfig}; use crate::containers::LakeIndexer; +use crate::execute::executable; +use anyhow::Context; use async_process::Child; use mpc_keys::hpke; use mpc_node::config::OverrideConfig; use near_workspaces::Account; -use crate::execute::executable; -use anyhow::Context; use shell_escape::escape; pub struct Node { @@ -38,10 +38,11 @@ pub struct NodeConfig { impl Node { pub async fn dry_run( ctx: &super::Context<'_>, - account_id: &AccountId, - account_sk: &near_workspaces::types::SecretKey, + account: &Account, cfg: &MultichainConfig, - ) -> anyhow::Result<()> { + ) -> anyhow::Result { + let account_id = account.id(); + let account_sk = account.secret_key(); let web_port = utils::pick_unused_port().await?; let (cipher_sk, cipher_pk) = hpke::generate(); let sign_sk = @@ -58,7 +59,7 @@ impl Node { let near_rpc = ctx.lake_indexer.rpc_host_address.clone(); let mpc_contract_id = ctx.mpc_contract.id().clone(); let cli = mpc_node::cli::Cli::Start { - near_rpc, + near_rpc: near_rpc.clone(), mpc_contract_id: mpc_contract_id.clone(), account_id: account_id.clone(), account_sk: account_sk.to_string().parse()?, @@ -78,9 +79,26 @@ impl Node { let cmd = executable(ctx.release, crate::execute::PACKAGE_MULTICHAIN) .with_context(|| "could not find target dir for mpc-node")?; let args = cli.into_str_args(); - let escaped_args: Vec<_> = args.iter().map(|arg| escape(arg.clone().into()).to_string()).collect(); - println!("\nCommand to run node {}:\n {} {}", account_id, cmd.to_str().unwrap(), escaped_args.join(" ")); - Ok(()) + let escaped_args: Vec<_> = args + .iter() + .map(|arg| escape(arg.clone().into()).to_string()) + .collect(); + println!( + "\nCommand to run node {}:\n {} {}", + account_id, + cmd.to_str().unwrap(), + escaped_args.join(" ") + ); + let node_config = NodeConfig { + web_port, + account: account.clone(), + cipher_pk, + cipher_sk, + sign_sk, + cfg: cfg.clone(), + near_rpc, + }; + Ok(node_config) } pub async fn run( diff --git a/integration-tests/chain-signatures/src/main.rs b/integration-tests/chain-signatures/src/main.rs index 3e3782722..5d8f919ac 100644 --- a/integration-tests/chain-signatures/src/main.rs +++ b/integration-tests/chain-signatures/src/main.rs @@ -1,6 +1,6 @@ use clap::Parser; use integration_tests_chain_signatures::containers::DockerClient; -use integration_tests_chain_signatures::{run, setup, utils, MultichainConfig, dry_run}; +use integration_tests_chain_signatures::{dry_run, run, utils, MultichainConfig}; use tokio::signal; use tracing_subscriber::EnvFilter; @@ -71,7 +71,7 @@ async fn main() -> anyhow::Result<()> { Cli::DepServices => { println!("Setting up dependency services"); let config = MultichainConfig::default(); - let nodes = dry_run(config.clone(), &docker_client).await?; + let _ctx = dry_run(config.clone(), &docker_client).await?; println!("Press Ctrl-C to stop dependency services"); signal::ctrl_c().await.expect("Failed to listen for event"); From e2cb49f9dc0f1461c142daa3a82725f19e769309 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Wed, 9 Oct 2024 22:14:02 +0800 Subject: [PATCH 3/3] clippy --- integration-tests/chain-signatures/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index a8f7bb273..dbdba4d35 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -312,7 +312,7 @@ pub async fn dry_host( .collect::, _>>()?; let mut node_cfgs = Vec::new(); for account in accounts.iter().take(cfg.nodes) { - node_cfgs.push(local::Node::dry_run(&ctx, &account, &cfg).await?); + node_cfgs.push(local::Node::dry_run(&ctx, account, &cfg).await?); } let candidates: HashMap = accounts @@ -347,8 +347,8 @@ pub async fn dry_host( ctx.mpc_contract.id(), args, ctx.mpc_contract.id(), - sk.public_key().to_string(), - sk.to_string() + sk.public_key(), + sk ); println!();