-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from Apocentre/chore/split_cli_admin
Chore/split cli admin
- Loading branch information
Showing
4 changed files
with
218 additions
and
179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
use anyhow::Result; | ||
use clap::{Parser, Subcommand}; | ||
use log::info; | ||
use std::path::PathBuf; | ||
use zkbitcoin::{ | ||
committee::orchestrator::{CommitteeConfig, Member}, | ||
constants::{ZKBITCOIN_FEE_PUBKEY, ZKBITCOIN_PUBKEY}, | ||
frost, taproot_addr_from, | ||
}; | ||
|
||
#[derive(Parser)] | ||
#[command(author, version, about, long_about = None)] | ||
struct Cli { | ||
#[command(subcommand)] | ||
command: Commands, | ||
} | ||
|
||
#[derive(Subcommand)] | ||
enum Commands { | ||
/// Generates an MPC committee via a trusted dealer. | ||
/// Ideally this is just used for testing as it is more secure to do a DKG. | ||
GenerateCommittee { | ||
/// Number of nodes in the committee. | ||
#[arg(short, long)] | ||
num: u16, | ||
|
||
/// Minimum number of committee member required for a signature. | ||
#[arg(short, long)] | ||
threshold: u16, | ||
|
||
/// Output directory to write the committee configuration files to. | ||
#[arg(short, long)] | ||
output_dir: String, | ||
}, | ||
|
||
/// Starts an MPC node given a configuration | ||
StartCommitteeNode { | ||
/// The address to run the node on. | ||
#[arg(short, long)] | ||
address: Option<String>, | ||
|
||
/// The path to the node's key package. | ||
#[arg(short, long)] | ||
key_path: String, | ||
|
||
/// The path to the MPC committee public key package. | ||
#[arg(short, long)] | ||
publickey_package_path: String, | ||
}, | ||
|
||
/// Starts an orchestrator | ||
StartOrchestrator { | ||
/// The address to run the node on. | ||
#[arg(short, long)] | ||
address: Option<String>, | ||
|
||
#[arg(short, long)] | ||
publickey_package_path: String, | ||
|
||
#[arg(short, long)] | ||
committee_cfg_path: String, | ||
}, | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<()> { | ||
// init default log level to info (unless RUST_LOG is set) | ||
env_logger::init_from_env(env_logger::Env::default().default_filter_or("info")); | ||
|
||
// debug info | ||
info!( | ||
"- zkbitcoin_address: {}", | ||
taproot_addr_from(ZKBITCOIN_PUBKEY).unwrap().to_string() | ||
); | ||
info!( | ||
"- zkbitcoin_fund_address: {}", | ||
taproot_addr_from(ZKBITCOIN_FEE_PUBKEY).unwrap().to_string() | ||
); | ||
|
||
// parse CLI | ||
let cli = Cli::parse(); | ||
match &cli.command { | ||
Commands::GenerateCommittee { | ||
num, | ||
threshold, | ||
output_dir, | ||
} => { | ||
let output_dir = PathBuf::from(output_dir); | ||
|
||
// deal until we get a public key starting with 0x02 | ||
let (mut key_packages, mut pubkey_package) = | ||
frost::gen_frost_keys(*num, *threshold).unwrap(); | ||
let mut pubkey = pubkey_package.verifying_key().to_owned(); | ||
loop { | ||
if pubkey.serialize()[0] == 2 { | ||
break; | ||
} | ||
(key_packages, pubkey_package) = frost::gen_frost_keys(*num, *threshold).unwrap(); | ||
pubkey = pubkey_package.verifying_key().to_owned(); | ||
} | ||
|
||
// all key packages | ||
{ | ||
for (id, key_package) in key_packages.values().enumerate() { | ||
let filename = format!("key-{id}.json"); | ||
|
||
let path = output_dir.join(filename); | ||
std::fs::create_dir_all(path.clone().parent().unwrap()) | ||
.expect("Couldn't create directory"); | ||
let file = std::fs::File::create(&path) | ||
.expect("couldn't create file given output dir"); | ||
serde_json::to_writer_pretty(file, key_package).unwrap(); | ||
} | ||
} | ||
|
||
// public key package | ||
{ | ||
let path = output_dir.join("publickey-package.json"); | ||
let file = | ||
std::fs::File::create(path).expect("couldn't create file given output dir"); | ||
serde_json::to_writer_pretty(file, &pubkey_package).unwrap(); | ||
} | ||
|
||
// create the committee-cfg.json file | ||
{ | ||
let ip = "http://127.0.0.1:889"; | ||
let committee_cfg = CommitteeConfig { | ||
threshold: *threshold as usize, | ||
members: key_packages | ||
.iter() | ||
.enumerate() | ||
.map(|(id, (member_id, _))| { | ||
( | ||
*member_id, | ||
Member { | ||
address: format!("{}{}", ip, id), | ||
}, | ||
) | ||
}) | ||
.collect(), | ||
}; | ||
let path = output_dir.join("committee-cfg.json"); | ||
let file = | ||
std::fs::File::create(path).expect("couldn't create file given output dir"); | ||
serde_json::to_writer_pretty(file, &committee_cfg).unwrap(); | ||
} | ||
} | ||
|
||
Commands::StartCommitteeNode { | ||
address, | ||
key_path, | ||
publickey_package_path, | ||
} => { | ||
let key_package = { | ||
let full_path = PathBuf::from(key_path); | ||
let file = std::fs::File::open(full_path).expect("file not found"); | ||
let key: frost::KeyPackage = | ||
serde_json::from_reader(file).expect("error while reading file"); | ||
key | ||
}; | ||
|
||
let pubkey_package = { | ||
let full_path = PathBuf::from(publickey_package_path); | ||
let file = std::fs::File::open(full_path).expect("file not found"); | ||
let publickey_package: frost::PublicKeyPackage = | ||
serde_json::from_reader(file).expect("error while reading file"); | ||
publickey_package | ||
}; | ||
|
||
zkbitcoin::committee::node::run_server(address.as_deref(), key_package, pubkey_package) | ||
.await | ||
.unwrap(); | ||
} | ||
|
||
Commands::StartOrchestrator { | ||
address, | ||
publickey_package_path, | ||
committee_cfg_path, | ||
} => { | ||
let pubkey_package = { | ||
let full_path = PathBuf::from(publickey_package_path); | ||
let file = std::fs::File::open(full_path).expect("file not found"); | ||
let publickey_package: frost::PublicKeyPackage = | ||
serde_json::from_reader(file).expect("error while reading file"); | ||
publickey_package | ||
}; | ||
|
||
let committee_cfg = { | ||
let full_path = PathBuf::from(committee_cfg_path); | ||
let file = std::fs::File::open(full_path).expect("file not found"); | ||
let publickey_package: CommitteeConfig = | ||
serde_json::from_reader(file).expect("error while reading file"); | ||
publickey_package | ||
}; | ||
|
||
// sanity check (unfortunately the publickey_package doesn't contain this info) | ||
assert!(committee_cfg.threshold > 0); | ||
|
||
zkbitcoin::committee::orchestrator::run_server( | ||
address.as_deref(), | ||
pubkey_package, | ||
committee_cfg, | ||
) | ||
.await | ||
.unwrap(); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} |
Oops, something went wrong.