Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

binary to spin up chain signature local cluster #655

Merged
merged 5 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion integration-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,24 @@ Now, you can inspect each container's logs according to your needs using `docker

We have a CLI tool that can instantiate a short-lived development environment that has everything except for the leader node set up. You can then seamlessly plug in your own leader node instance that you have set up manually (the tool gives you a CLI command to use as a starting point, but you can attach debugger, enable extra logs etc). Try it out now (sets up 3 signer nodes):

For fastauth:

```bash
$ export RUST_LOG=info
$ cd integration-tests/fastauth
$ cargo run -- setup-env 3
```

For chain signatures:
```bash
$ export RUST_LOG=info
$ cd integration-tests/chain-signatures
$ cargo run -- setup-env --nodes 3 --threshold 2
```

### I'm getting "Error: error trying to connect: No such file or directory (os error 2)"

It's a known issue on MacOS. Try executiong the following command:
It's a known issue on MacOS. Try executing the following command:

```bash
sudo ln -s $HOME/.docker/run/docker.sock /var/run/docker.sock
Expand Down
1 change: 1 addition & 0 deletions integration-tests/chain-signatures/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions integration-tests/chain-signatures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ crypto-shared = { path = "../../chain-signatures/crypto-shared" }
mpc-contract = { path = "../../chain-signatures/contract" }
mpc-keys = { path = "../../chain-signatures/keys" }
mpc-recovery-node = { path = "../../chain-signatures/node" }
clap = { version = "4.5.4", features = ["derive"] }
lazy_static = "1.4.0"

[dev-dependencies]
Expand Down
29 changes: 24 additions & 5 deletions integration-tests/chain-signatures/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use testcontainers::{Container, GenericImage};

const NETWORK: &str = "mpc_it_network";

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct MultichainConfig {
pub nodes: usize,
pub threshold: usize,
Expand Down Expand Up @@ -109,10 +109,29 @@ impl Nodes<'_> {
}

pub fn near_accounts(&self) -> Vec<Account> {
self.near_acc_sk()
.iter()
.map(|(account_id, account_sk)| {
Account::from_secret_key(account_id.clone(), account_sk.clone(), &self.ctx().worker)
let acc_sk = self.near_acc_sk();
let mut account_ids = Vec::new();
match self {
Nodes::Local { nodes, .. } => {
for node in nodes {
account_ids.push(node.account_id.clone());
}
}
Nodes::Docker { nodes, .. } => {
for node in nodes {
account_ids.push(node.account_id.clone());
}
}
};

account_ids
.into_iter()
.map(|account_id| {
Account::from_secret_key(
account_id.clone(),
acc_sk.get(&account_id).unwrap().clone(),
&self.ctx().worker,
)
})
.collect()
}
Expand Down
79 changes: 79 additions & 0 deletions integration-tests/chain-signatures/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use clap::Parser;
use integration_tests_chain_signatures::containers::DockerClient;
use integration_tests_chain_signatures::{run, setup, utils, MultichainConfig};
use tokio::signal;
use tracing_subscriber::EnvFilter;

#[derive(Parser, Debug)]
enum Cli {
/// Spin up dependent services and mpc nodes
SetupEnv {
#[arg(short, long, default_value_t = 3)]
nodes: usize,
#[arg(short, long, default_value_t = 2)]
threshold: usize,
},
/// Spin up dependent services but not mpc nodes
DepServices,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let subscriber = tracing_subscriber::fmt()
.with_thread_ids(true)
.with_env_filter(EnvFilter::from_default_env());
subscriber.init();
let docker_client = DockerClient::default();

match Cli::parse() {
Cli::SetupEnv { nodes, threshold } => {
println!(
"Setting up an environment with {} nodes, {} threshold ...",
nodes, threshold
);
let config = MultichainConfig {
nodes,
threshold,
..Default::default()
};
println!("Full config: {:?}", config);
let nodes = run(config.clone(), &docker_client).await?;
let ctx = nodes.ctx();
let urls: Vec<_> = (0..config.nodes).map(|i| nodes.url(i)).collect();
let near_acc_sks = nodes.near_acc_sk();
let near_accounts = nodes.near_accounts();
let sk_local_path = nodes.ctx().storage_options.sk_share_local_path.clone();

println!("\nEnvironment is ready:");
println!(" docker-network: {}", ctx.docker_network);
println!(" release: {}", ctx.release);

println!("\nExternal services:");
println!(" datastore: {}", ctx.datastore.local_address);
println!(" lake_indexer: {}", ctx.lake_indexer.rpc_host_address);

println!("\nNodes:");
for i in 0..urls.len() {
println!(" Node {}", i);
println!(" Url: {}", urls[i]);
let account_id = near_accounts[i].id();
println!(" Account: {}", account_id);
let sk = near_acc_sks.get(account_id).unwrap();
println!(" Secret Key: {}", sk);
let pk = sk.public_key();
println!(" Public Key: {}", pk);
}

signal::ctrl_c().await.expect("Failed to listen for event");
println!("Received Ctrl-C");
utils::clear_local_sk_shares(sk_local_path).await?;
println!("Clean up finished");
}
Cli::DepServices => {
println!("Settting up dependency services");
let _ctx = setup(&docker_client).await?;
}
}

Ok(())
}
20 changes: 20 additions & 0 deletions integration-tests/chain-signatures/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::Context;
use hyper::{Body, Client, Method, Request, StatusCode, Uri};
use near_workspaces::result::ExecutionFinalResult;
use near_workspaces::{Account, AccountId};
use std::fs;

pub async fn vote_join(
accounts: Vec<Account>,
Expand Down Expand Up @@ -99,3 +100,22 @@ pub async fn ping_until_ok(addr: &str, timeout: u64) -> anyhow::Result<()> {
.await?;
Ok(())
}

pub async fn clear_local_sk_shares(sk_local_path: Option<String>) -> anyhow::Result<()> {
if let Some(sk_share_local_path) = sk_local_path {
let pattern = format!("{sk_share_local_path}*");
for entry in glob::glob(&pattern).expect("Failed to read glob pattern") {
match entry {
Ok(path) => {
if path.is_file() {
if let Err(e) = fs::remove_file(&path) {
eprintln!("Failed to delete file {:?}: {}", path.display(), e);
}
}
}
Err(e) => eprintln!("{:?}", e),
}
}
}
Ok(())
}
25 changes: 2 additions & 23 deletions integration-tests/chain-signatures/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ use crate::actions::wait_for;

use anyhow::anyhow;
use futures::future::BoxFuture;
use glob::glob;
use integration_tests_chain_signatures::containers::DockerClient;
use integration_tests_chain_signatures::utils::{vote_join, vote_leave};
use integration_tests_chain_signatures::{run, MultichainConfig, Nodes};
use integration_tests_chain_signatures::{run, utils, MultichainConfig, Nodes};
use near_jsonrpc_client::JsonRpcClient;

use near_workspaces::{Account, AccountId};

use std::fs;
use std::str::FromStr;

pub struct MultichainTestContext<'a> {
Expand Down Expand Up @@ -150,26 +148,7 @@ where
cfg,
})
.await;
clear_local_sk_shares(sk_local_path).await?;
utils::clear_local_sk_shares(sk_local_path).await?;

result
}

pub async fn clear_local_sk_shares(sk_local_path: Option<String>) -> anyhow::Result<()> {
if let Some(sk_share_local_path) = sk_local_path {
let pattern = format!("{sk_share_local_path}*");
for entry in glob(&pattern).expect("Failed to read glob pattern") {
match entry {
Ok(path) => {
if path.is_file() {
if let Err(e) = fs::remove_file(&path) {
eprintln!("Failed to delete file {:?}: {}", path.display(), e);
}
}
}
Err(e) => eprintln!("{:?}", e),
}
}
}
Ok(())
}
Loading