From f75230c20832ca93996aa662840abef64d7e27f5 Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Tue, 28 Jan 2020 12:31:37 +0200 Subject: [PATCH 01/28] DEV: added error return on enigma-core main --- enigma-core/app/src/main.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/enigma-core/app/src/main.rs b/enigma-core/app/src/main.rs index 80b8d2d7..20b86129 100644 --- a/enigma-core/app/src/main.rs +++ b/enigma-core/app/src/main.rs @@ -20,12 +20,13 @@ use db::DB; use cli::Opt; use structopt::StructOpt; use futures::Future; +use failure::Fallible; -fn main() { +fn main() -> Fallible<()> { let opt: Opt = Opt::from_args(); - let log_level = log::LevelFilter::from_str(&opt.log_level).unwrap(); + let log_level = log::LevelFilter::from_str(&opt.log_level)?; let datadir = opt.data_dir.clone().unwrap_or_else(|| dirs::home_dir().unwrap().join(".enigma")); let hostname = os::hostname(); @@ -34,7 +35,7 @@ fn main() { debug!("CLI params: {:?}", opt); - let enclave = esgx::general::init_enclave_wrapper().map_err(|e| {error!("Init Enclave Failed {:?}", e);}).unwrap(); + let enclave = esgx::general::init_enclave_wrapper().map_err(|e| {error!("Init Enclave Failed {:?}", e);})?; let eid = enclave.geteid(); info!("Init Enclave Successful. Enclave id {}", eid); @@ -44,5 +45,7 @@ fn main() { server .run(move |multi| ipc_listener::handle_message(&mut db, multi, &opt.spid, eid, opt.retries)) .wait() - .unwrap(); + ?; + + Ok(()) } \ No newline at end of file From 25836b4e59cbf2411af4c7af07709d203dddb945 Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Tue, 28 Jan 2020 16:18:03 +0200 Subject: [PATCH 02/28] DEV: added thiserror crate and PrincipalConfig custom error --- enigma-principal/app/Cargo.lock | 21 +++++++++++++++++++ enigma-principal/app/Cargo.toml | 1 + .../app/src/boot_network/principal_manager.rs | 9 ++++---- .../app/src/common_u/custom_errors.rs | 11 ++++++++++ enigma-principal/app/src/common_u/mod.rs | 1 + enigma-principal/app/src/main.rs | 1 + 6 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 enigma-principal/app/src/common_u/custom_errors.rs diff --git a/enigma-principal/app/Cargo.lock b/enigma-principal/app/Cargo.lock index c5b2f945..5a5b1f15 100644 --- a/enigma-principal/app/Cargo.lock +++ b/enigma-principal/app/Cargo.lock @@ -497,6 +497,7 @@ dependencies = [ "sgx_urts 1.0.9 (git+https://github.com/baidu/rust-sgx-sdk.git?rev=v1.0.9)", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "web3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2179,6 +2180,24 @@ dependencies = [ "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thiserror" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thiserror-impl 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread-id" version = "3.3.0" @@ -2904,6 +2923,8 @@ dependencies = [ "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6f357d1814b33bc2dc221243f8424104bfe72dbe911d5b71b3816a2dff1c977e" +"checksum thiserror-impl 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2e25d25307eb8436894f727aba8f65d07adf02e5b35a13cebed48bd282bfef" "checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" diff --git a/enigma-principal/app/Cargo.toml b/enigma-principal/app/Cargo.toml index e465f536..11000e17 100644 --- a/enigma-principal/app/Cargo.toml +++ b/enigma-principal/app/Cargo.toml @@ -13,6 +13,7 @@ enigma-tools-m = { path = "../../enigma-tools-m" } ethabi = "8.0.1" etcommon-rlp = "0.2" failure = "0.1.3" +thiserror = "1.0.9" rustc-hex = "1.0.0" serde_json = "1.0" serde = "1.0" diff --git a/enigma-principal/app/src/boot_network/principal_manager.rs b/enigma-principal/app/src/boot_network/principal_manager.rs index 7f0dea11..15b23e7c 100644 --- a/enigma-principal/app/src/boot_network/principal_manager.rs +++ b/enigma-principal/app/src/boot_network/principal_manager.rs @@ -28,6 +28,7 @@ use std::path::PathBuf; use secp256k1::key::SecretKey; use secp256k1::Message; use secp256k1::Secp256k1; +use common_u::custom_errors::ConfigError; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct PrincipalConfig { @@ -181,7 +182,7 @@ impl ReportManager { impl PrincipalConfig { // load json config into the struct #[logfn(DEBUG)] - pub fn load_config(config_path: &str) -> Result { + pub fn load_config(config_path: &str) -> Result { info!("loading Principal config"); // All configurations from env should be with the same names of the // PrincipalConfig struct fields in uppercase letters @@ -189,12 +190,12 @@ impl PrincipalConfig { Ok(config) => Ok(config), Err(_) => { info!("trying to load from path: {:?}", config_path); - let mut f = File::open(config_path)?; + let mut f = File::open(config_path).or(Err(ConfigError::FileDoesntExist))?; let mut contents = String::new(); - f.read_to_string(&mut contents)?; + f.read_to_string(&mut contents).or(Err(ConfigError::NotAString))?; - Ok(serde_json::from_str(&contents)?) + serde_json::from_str(&contents).or(Err(ConfigError::Parsing)) } } } diff --git a/enigma-principal/app/src/common_u/custom_errors.rs b/enigma-principal/app/src/common_u/custom_errors.rs new file mode 100644 index 00000000..cb6c0d39 --- /dev/null +++ b/enigma-principal/app/src/common_u/custom_errors.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ConfigError { + #[error("Unable to open config file")] + FileDoesntExist, + #[error("Unable to convert file content to string")] + NotAString, + #[error("Cannot parse data")] + Parsing, +} \ No newline at end of file diff --git a/enigma-principal/app/src/common_u/mod.rs b/enigma-principal/app/src/common_u/mod.rs index 629e98fb..a116486e 100644 --- a/enigma-principal/app/src/common_u/mod.rs +++ b/enigma-principal/app/src/common_u/mod.rs @@ -1 +1,2 @@ pub mod errors; +pub mod custom_errors; \ No newline at end of file diff --git a/enigma-principal/app/src/main.rs b/enigma-principal/app/src/main.rs index 086c8138..8036139c 100644 --- a/enigma-principal/app/src/main.rs +++ b/enigma-principal/app/src/main.rs @@ -9,6 +9,7 @@ extern crate enigma_tools_m; extern crate enigma_tools_u; extern crate enigma_types; extern crate ethabi; +extern crate thiserror; #[macro_use] extern crate failure; extern crate jsonrpc_http_server; From f8fd778e421fddf6070020b349fdcbd7e5b646f8 Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Tue, 28 Jan 2020 16:49:36 +0200 Subject: [PATCH 03/28] DEV: removed duplicate code in the principal manager --- .../app/src/boot_network/principal_manager.rs | 36 +++++++++---------- enigma-principal/app/src/cli/app.rs | 4 +-- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/enigma-principal/app/src/boot_network/principal_manager.rs b/enigma-principal/app/src/boot_network/principal_manager.rs index 15b23e7c..55567195 100644 --- a/enigma-principal/app/src/boot_network/principal_manager.rs +++ b/enigma-principal/app/src/boot_network/principal_manager.rs @@ -82,10 +82,8 @@ pub struct ReportManager { } pub struct PrincipalManager { - pub config: PrincipalConfig, pub contract: Arc, - pub report_manager: ReportManager, - pub eid: sgx_enclave_id_t, + report_manager: ReportManager, } pub struct SgxEthereumSigner { @@ -135,9 +133,9 @@ impl EcdsaSign for PrivateKeyEthereumSigner { } impl ReportManager { - pub fn new(config: PrincipalConfig, eid: sgx_enclave_id_t) -> Result { + pub fn new(config: PrincipalConfig, eid: sgx_enclave_id_t) -> Self { let as_service = service::AttestationService::new_with_retries(&config.attestation_service_url, config.attestation_retries); - Ok(ReportManager { config, as_service, eid }) + ReportManager { config, as_service, eid } } pub fn get_signing_address(&self) -> Result { @@ -207,7 +205,7 @@ impl PrincipalManager { // General interface of a Sampler == The entity that manages the principal node logic. pub trait Sampler { /// load with config from file - fn new(config: PrincipalConfig, contract: Arc, report_manager: ReportManager) -> Result + fn new(contract: Arc, report_manager: ReportManager) -> Self where Self: Sized; fn get_signing_address(&self) -> Result; @@ -229,10 +227,8 @@ pub trait Sampler { } impl Sampler for PrincipalManager { - fn new(config: PrincipalConfig, contract: Arc, report_manager: ReportManager) -> Result { - let eid = report_manager.eid; - // let registration_params = report_manager.get_registration_params()?; - Ok(PrincipalManager { config, contract, report_manager, eid }) + fn new(contract: Arc, report_manager: ReportManager) -> Self { + PrincipalManager { contract, report_manager } } fn get_signing_address(&self) -> Result { @@ -245,7 +241,7 @@ impl Sampler for PrincipalManager { // noinspection RsBorrowChecker fn get_account_address(&self) -> Address { self.contract.account } - fn get_network_url(&self) -> String { self.config.url.clone() } + fn get_network_url(&self) -> String { self.report_manager.config.url.clone() } fn get_block_number(&self) -> Result { let block_number = match self.get_web3().eth().block_number().wait() { @@ -271,7 +267,7 @@ impl Sampler for PrincipalManager { registration_params.report, registration_params.signature, gas_limit, - self.config.confirmations as usize, + self.report_manager.config.confirmations as usize, )?; Ok(receipt.transaction_hash) } @@ -313,14 +309,14 @@ impl Sampler for PrincipalManager { self.verify_identity_or_register(gas_limit)?; // get enigma contract // Start the WorkerParameterized Web3 log filter - let eid: Arc = Arc::new(self.eid); + let eid: Arc = Arc::new(self.report_manager.eid); let epoch_provider = Arc::new(EpochProvider::new(eid, path, self.contract.clone())?); if reset_epoch { epoch_provider.epoch_state_manager.reset()?; } // Start the JSON-RPC Server - let port = self.config.http_port; + let port = self.report_manager.config.http_port; let server_ep = Arc::clone(&epoch_provider); thread::spawn(move || { let server = PrincipalHttpServer::new(server_ep, port); @@ -328,15 +324,15 @@ impl Sampler for PrincipalManager { }); // watch blocks - let polling_interval = self.config.polling_interval; - let epoch_size = self.config.epoch_size; + let polling_interval = self.report_manager.config.polling_interval; + let epoch_size = self.report_manager.config.epoch_size; self.contract.watch_blocks( epoch_size, polling_interval, epoch_provider, gas_limit, - self.config.confirmations as usize, - self.config.max_epochs, + self.report_manager.config.confirmations as usize, + self.report_manager.config.max_epochs, ); Ok(()) } @@ -393,7 +389,7 @@ mod test { pub fn init_no_deploy(eid: u64) -> Result { let mut config = get_config()?; - let enclave_manager = ReportManager::new(config.clone(), eid)?; + let enclave_manager = ReportManager::new(config.clone(), eid); let ethereum_signer = Box::new(SgxEthereumSigner{eid}) as Box; let contract = Arc::new(EnigmaContract::from_deployed( &config.enigma_contract_address, @@ -405,7 +401,7 @@ mod test { )?); let _gas_limit = 5_999_999; config.max_epochs = None; - let principal: PrincipalManager = PrincipalManager::new(config.clone(), contract, enclave_manager).unwrap(); + let principal: PrincipalManager = PrincipalManager::new( contract, enclave_manager); Ok(principal) } diff --git a/enigma-principal/app/src/cli/app.rs b/enigma-principal/app/src/cli/app.rs index bd2fa0d8..e70b7b4e 100644 --- a/enigma-principal/app/src/cli/app.rs +++ b/enigma-principal/app/src/cli/app.rs @@ -37,7 +37,7 @@ pub fn create_signer(eid: sgx_enclave_id_t, with_private_key: bool, private_key: pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { let opt = cli::options::Opt::from_args(); let mut principal_config = PrincipalConfig::load_config(opt.principal_config.as_str())?; - let report_manager = ReportManager::new(principal_config.clone(), eid)?; + let report_manager = ReportManager::new(principal_config.clone(), eid); let signing_address = report_manager.get_signing_address()?; let ethereum_address = report_manager.get_ethereum_address()?; let mut path = storage_dir(ENCLAVE_DIR)?; @@ -82,7 +82,7 @@ pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { let gas_limit = 5_999_999; - let principal: PrincipalManager = PrincipalManager::new(principal_config.clone(), enigma_contract, report_manager)?; + let principal: PrincipalManager = PrincipalManager::new( enigma_contract, report_manager); println!("Connected to the Enigma contract: {:?} with account: {:?}", &contract_address, principal.get_account_address()); // step 2 optional - run miner to simulate blocks From f4e913c82b37789463159e399160c2138c88d3f8 Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Tue, 28 Jan 2020 17:16:08 +0200 Subject: [PATCH 04/28] STY: removed unused code --- .../app/src/boot_network/deploy_scripts.rs | 8 ------- .../src/boot_network/keys_provider_http.rs | 4 +--- .../app/src/boot_network/principal_manager.rs | 24 +++---------------- .../app/src/epoch_u/epoch_provider.rs | 4 +--- .../app/src/esgx/epoch_keeper_u.rs | 5 ++-- enigma-principal/app/src/esgx/general.rs | 2 +- .../app/src/esgx/keys_keeper_u.rs | 2 +- enigma-principal/app/src/main.rs | 8 ------- 8 files changed, 9 insertions(+), 48 deletions(-) diff --git a/enigma-principal/app/src/boot_network/deploy_scripts.rs b/enigma-principal/app/src/boot_network/deploy_scripts.rs index d70bfc5a..e26fc1cf 100644 --- a/enigma-principal/app/src/boot_network/deploy_scripts.rs +++ b/enigma-principal/app/src/boot_network/deploy_scripts.rs @@ -47,14 +47,6 @@ pub fn forward_blocks(w3: &Arc>, interval: u64, deployer: Address) -> #[cfg(test)] mod test { use esgx::general::init_enclave_wrapper; - use std::env; - - /// This function is important to enable testing both on the CI server and local. - /// On the CI Side: - /// The ethereum network url is being set into env variable 'NODE_URL' and taken from there. - /// Anyone can modify it by simply doing $export NODE_URL= and then running the tests. - /// The default is set to ganache cli "http://localhost:8545" - fn get_node_url() -> String { env::var("NODE_URL").unwrap_or("http://localhost:8545".to_string()) } #[test] fn test_deploy_enigma_contract_environment() { diff --git a/enigma-principal/app/src/boot_network/keys_provider_http.rs b/enigma-principal/app/src/boot_network/keys_provider_http.rs index b3a0b3d7..4a405702 100644 --- a/enigma-principal/app/src/boot_network/keys_provider_http.rs +++ b/enigma-principal/app/src/boot_network/keys_provider_http.rs @@ -218,10 +218,8 @@ mod test { extern crate jsonrpc_test as test; use std::collections::HashMap; - use std::thread; use rustc_hex::FromHex; - use serde_json::error::ErrorCode::EofWhileParsingObject; use web3::types::{H160, U256}; use web3::types::Bytes; @@ -261,7 +259,7 @@ mod test { }); test::Rpc::from(io) }; - for i in 0..5 { + for _ in 0..5 { let response = rpc.request(METHOD_GET_STATE_KEYS, &(REF_MSG, REF_SIG, Value::Null, Value::Null)); assert!(response.contains(REF_RESPONSE)); } diff --git a/enigma-principal/app/src/boot_network/principal_manager.rs b/enigma-principal/app/src/boot_network/principal_manager.rs index 55567195..a2f80a86 100644 --- a/enigma-principal/app/src/boot_network/principal_manager.rs +++ b/enigma-principal/app/src/boot_network/principal_manager.rs @@ -350,35 +350,17 @@ pub fn run_miner(account: Address, w3: Arc>, interval: u64) -> thread #[cfg(test)] mod test { extern crate tempfile; - use std::{env, path::Path, sync::Arc, sync::Mutex, thread, time}; - use self::tempfile::TempDir; + use std::{env, path::Path, sync::Arc, thread, time}; - use web3::{ - futures::{Future, stream::Stream}, - transports::Http, - types::{FilterBuilder, Log}, - Web3, - }; + use web3::{futures::{Future, stream::Stream}, types::FilterBuilder, }; - use enigma_tools_u::web3_utils::{enigma_contract::EnigmaContract, w3utils}; + use enigma_tools_u::web3_utils::enigma_contract::EnigmaContract; use epoch_u::epoch_types::{WorkersParameterizedEvent, WORKER_PARAMETERIZED_EVENT}; use esgx::general::init_enclave_wrapper; use super::*; const GAS_LIMIT: usize = 5999999; - /// This function is important to enable testing both on the CI server and local. - /// On the CI Side: - /// The ethereum network url is being set into env variable 'NODE_URL' and taken from there. - /// Anyone can modify it by simply doing $export NODE_URL= and then running the tests. - /// The default is set to ganache cli "http://localhost:8545" - pub fn get_node_url() -> String { env::var("NODE_URL").unwrap_or(String::from("http://localhost:8545")) } - - /// helps in assertion to check if a random event was indeed broadcast. - pub fn filter_random(w3: &Arc>, contract_addr: Option<&str>, event_name: &str) -> Result, Error> { - let logs = w3utils::filter_blocks(w3, contract_addr, event_name)?; - Ok(logs) - } #[logfn(DEBUG)] pub fn get_config() -> Result { diff --git a/enigma-principal/app/src/epoch_u/epoch_provider.rs b/enigma-principal/app/src/epoch_u/epoch_provider.rs index 8b3efb1f..a247630e 100644 --- a/enigma-principal/app/src/epoch_u/epoch_provider.rs +++ b/enigma-principal/app/src/epoch_u/epoch_provider.rs @@ -369,12 +369,10 @@ impl EpochProvider { pub mod test { extern crate tempfile; - use self::tempfile::TempDir; use std::collections::HashMap; use web3::types::{Bytes, H160}; - use enigma_tools_u::{esgx::general::storage_dir}; use enigma_types::ContractAddress; use super::*; @@ -384,7 +382,7 @@ pub mod test { pub fn setup_epoch_storage_dir() -> PathBuf { let tempdir = tempfile::tempdir().unwrap(); - let mut temp_path = tempdir.into_path(); + let temp_path = tempdir.into_path(); println!("path is: {:?}", temp_path); temp_path } diff --git a/enigma-principal/app/src/esgx/epoch_keeper_u.rs b/enigma-principal/app/src/esgx/epoch_keeper_u.rs index 594c0e9a..ede8840e 100644 --- a/enigma-principal/app/src/esgx/epoch_keeper_u.rs +++ b/enigma-principal/app/src/esgx/epoch_keeper_u.rs @@ -76,8 +76,7 @@ pub fn set_or_verify_worker_params(eid: sgx_enclave_id_t, worker_params: &InputW #[cfg(test)] pub mod tests { - use rustc_hex::{FromHex, ToHex}; - use web3::types::{Address, H160, H256}; + use web3::types::H160; use esgx::general::init_enclave_wrapper; @@ -116,7 +115,7 @@ pub mod tests { let stakes: Vec = vec![90000000000]; let km_block_number = 1; let worker_params = get_worker_params(km_block_number, workers, stakes); - for i in 0..5 { + for _ in 0..5 { let epoch_state = set_or_verify_worker_params(enclave.geteid(), &worker_params, None).unwrap(); assert!(epoch_state.confirmed_state.is_none()); } diff --git a/enigma-principal/app/src/esgx/general.rs b/enigma-principal/app/src/esgx/general.rs index 9a8a735f..2081050c 100644 --- a/enigma-principal/app/src/esgx/general.rs +++ b/enigma-principal/app/src/esgx/general.rs @@ -1,7 +1,7 @@ use enigma_tools_u::{self, esgx::general::storage_dir}; use sgx_types::*; use sgx_urts::SgxEnclave; -use std::{fs, path}; +use std::fs; static ENCLAVE_FILE: &'static str = "../bin/enclave.signed.so"; pub static ENCLAVE_DIR: &'static str = ".enigma"; diff --git a/enigma-principal/app/src/esgx/keys_keeper_u.rs b/enigma-principal/app/src/esgx/keys_keeper_u.rs index bb7c405f..5bf78469 100644 --- a/enigma-principal/app/src/esgx/keys_keeper_u.rs +++ b/enigma-principal/app/src/esgx/keys_keeper_u.rs @@ -103,7 +103,7 @@ pub mod tests { let sig = StringWrapper("2535cfe1bcea215dc552acbca1a213354e055709f8e071c593bb9a8c1551b7791d6fd611ded1912065b3b518f6a75a1c78643b0a2e06397707b21768be637cb41b".to_string()); let request = StateKeyRequest { data: msg, sig, block_number: None, addresses: None }; - let response = get_enc_state_keys(enclave.geteid(), request, epoch_state.nonce, &[]).unwrap(); + get_enc_state_keys(enclave.geteid(), request, epoch_state.nonce, &[]).unwrap(); enclave.destroy(); } diff --git a/enigma-principal/app/src/main.rs b/enigma-principal/app/src/main.rs index 8036139c..ae93c7c2 100644 --- a/enigma-principal/app/src/main.rs +++ b/enigma-principal/app/src/main.rs @@ -75,21 +75,13 @@ fn main() { #[cfg(test)] mod tests { - use enigma_tools_u::common_u::logging; use esgx::general::init_enclave_wrapper; - use log::LevelFilter; use sgx_types::{sgx_enclave_id_t, sgx_status_t}; - use std::path::Path; extern "C" { fn ecall_run_tests(eid: sgx_enclave_id_t) -> sgx_status_t; } - pub fn log_to_stdout(level: Option) { - let level = level.unwrap_or_else(|| LevelFilter::max()); - logging::init_logger(level, ".", "Tests".to_string()).unwrap(); - } - #[test] pub fn test_enclave_internal() { // initiate the enclave From 8c34227ffa5b8b1b69fc05a3492c74e87b93d72d Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Tue, 28 Jan 2020 18:47:47 +0200 Subject: [PATCH 05/28] DEV: custom errors for report manager --- .../app/src/boot_network/principal_manager.rs | 16 ++++++++-------- .../app/src/common_u/custom_errors.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/enigma-principal/app/src/boot_network/principal_manager.rs b/enigma-principal/app/src/boot_network/principal_manager.rs index a2f80a86..ccb4cedd 100644 --- a/enigma-principal/app/src/boot_network/principal_manager.rs +++ b/enigma-principal/app/src/boot_network/principal_manager.rs @@ -28,7 +28,7 @@ use std::path::PathBuf; use secp256k1::key::SecretKey; use secp256k1::Message; use secp256k1::Secp256k1; -use common_u::custom_errors::ConfigError; +use common_u::custom_errors::{ConfigError, ReportManagerErr}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct PrincipalConfig { @@ -138,26 +138,26 @@ impl ReportManager { ReportManager { config, as_service, eid } } - pub fn get_signing_address(&self) -> Result { - let _signing_address = esgx::equote::get_register_signing_address(self.eid)?; + pub fn get_signing_address(&self) -> Result { + let _signing_address = esgx::equote::get_register_signing_address(self.eid).or(Err(ReportManagerErr::GetRegisterAddrErr))?; let signing_address = _signing_address.to_vec().to_hex(); Ok(signing_address) } - pub fn get_ethereum_address(&self) -> Result { + pub fn get_ethereum_address(&self) -> Result { if self.config.with_private_key { return Ok(self.config.account_address.clone()); } - let _signing_address = esgx::equote::get_ethereum_address(self.eid)?; + let _signing_address = esgx::equote::get_ethereum_address(self.eid).or(Err(ReportManagerErr::GetEtherAddrErr))?; let signing_address = _signing_address.to_vec().to_hex(); Ok(signing_address) } #[logfn(DEBUG)] - pub fn get_registration_params(&self) -> Result { + pub fn get_registration_params(&self) -> Result { let signing_address = self.get_signing_address()?; let mode = option_env!("SGX_MODE").unwrap_or_default(); - let enc_quote = retry_quote(self.eid, &self.config.spid, 18)?; + let enc_quote = retry_quote(self.eid, &self.config.spid, 18).or(Err(ReportManagerErr::QuoteErr))?; let report: String; let signature: String; @@ -169,7 +169,7 @@ impl ReportManager { } else { // Hardware Mode println!("Hardware mode"); - let response = self.as_service.get_report(enc_quote)?; + let response = self.as_service.get_report(enc_quote).or(Err(ReportManagerErr::QuoteErr))?; report = response.result.report_string; signature = response.result.signature; } diff --git a/enigma-principal/app/src/common_u/custom_errors.rs b/enigma-principal/app/src/common_u/custom_errors.rs index cb6c0d39..1e3e94b0 100644 --- a/enigma-principal/app/src/common_u/custom_errors.rs +++ b/enigma-principal/app/src/common_u/custom_errors.rs @@ -8,4 +8,14 @@ pub enum ConfigError { NotAString, #[error("Cannot parse data")] Parsing, +} + +#[derive(Error, Debug)] +pub enum ReportManagerErr { + #[error("An error occurred while trying to get the registration signing address from inside the enclave")] + GetRegisterAddrErr, + #[error("An error occurred while trying to get the Ethereum address from inside the enclave")] + GetEtherAddrErr, + #[error("Error while trying to produce quote")] + QuoteErr, } \ No newline at end of file From ea884b00a26e64c03ed575cab76b7f49a34feedc Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Tue, 28 Jan 2020 18:52:49 +0200 Subject: [PATCH 06/28] BUG: added extern crate for failure --- enigma-core/app/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/enigma-core/app/src/main.rs b/enigma-core/app/src/main.rs index 20b86129..e124f679 100644 --- a/enigma-core/app/src/main.rs +++ b/enigma-core/app/src/main.rs @@ -2,6 +2,7 @@ extern crate enigma_core_app; #[macro_use] extern crate log; extern crate log_derive; +extern crate failure; use log::{debug, info}; From d675ea4dea2d51c8af11226b9cfc0b8ce9dce3bb Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Wed, 29 Jan 2020 14:19:42 +0200 Subject: [PATCH 07/28] BUG: fixed a error mapping in main --- enigma-core/app/src/main.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/enigma-core/app/src/main.rs b/enigma-core/app/src/main.rs index e124f679..8b8540fc 100644 --- a/enigma-core/app/src/main.rs +++ b/enigma-core/app/src/main.rs @@ -2,6 +2,7 @@ extern crate enigma_core_app; #[macro_use] extern crate log; extern crate log_derive; +#[macro_use] extern crate failure; use log::{debug, info}; @@ -21,7 +22,7 @@ use db::DB; use cli::Opt; use structopt::StructOpt; use futures::Future; -use failure::Fallible; +use failure::{Fallible, format_err}; fn main() -> Fallible<()> { @@ -35,8 +36,10 @@ fn main() -> Fallible<()> { debug!("CLI params: {:?}", opt); - - let enclave = esgx::general::init_enclave_wrapper().map_err(|e| {error!("Init Enclave Failed {:?}", e);})?; + let enclave = esgx::general::init_enclave_wrapper().map_err(|e| { + error!("Init Enclave Failed sgx_status_t = {:?}", e); + failure::format_err!("Init Enclave Failed sgx_status_t = {}", e) + })?; let eid = enclave.geteid(); info!("Init Enclave Successful. Enclave id {}", eid); From 09eaff71e7c742592140d5110997e94b45c10a70 Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Thu, 30 Jan 2020 10:40:52 +0200 Subject: [PATCH 08/28] STY: removed unused code --- enigma-principal/app/src/esgx/equote.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/enigma-principal/app/src/esgx/equote.rs b/enigma-principal/app/src/esgx/equote.rs index a54e70fe..4d45f026 100644 --- a/enigma-principal/app/src/esgx/equote.rs +++ b/enigma-principal/app/src/esgx/equote.rs @@ -13,15 +13,6 @@ extern "C" { extern "C" { fn ecall_sign_ethereum(eid: sgx_enclave_id_t, data: &[u8; 32], sig: &mut [u8; 65]) -> sgx_status_t; } -// this struct is returned during the process registration back to the surface. -// quote: the base64 encoded quote -// address : the clear text public key for ecdsa signing and registration -#[derive(Serialize, Deserialize, Debug)] -pub struct GetRegisterResult { - pub errored: bool, - pub quote: String, - pub address: String, -} // wrapper function for getting the enclave public sign key (the one attached with produce_quote()) #[logfn(TRACE)] From 5a2a1f66a6636d0311883e03512a923319e6c363 Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Thu, 30 Jan 2020 10:41:27 +0200 Subject: [PATCH 09/28] DEV: changed threading to crossbeam --- enigma-principal/app/Cargo.lock | 1 + enigma-principal/app/Cargo.toml | 1 + .../app/src/boot_network/principal_manager.rs | 107 +++++++++--------- enigma-principal/app/src/cli/app.rs | 18 +-- enigma-principal/app/src/main.rs | 2 +- 5 files changed, 66 insertions(+), 63 deletions(-) diff --git a/enigma-principal/app/Cargo.lock b/enigma-principal/app/Cargo.lock index 5a5b1f15..58c05f7e 100644 --- a/enigma-principal/app/Cargo.lock +++ b/enigma-principal/app/Cargo.lock @@ -472,6 +472,7 @@ name = "enigma-principal-app" version = "0.3.0" dependencies = [ "colour 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "enigma-crypto 0.3.0", "enigma-tools-m 0.3.0", diff --git a/enigma-principal/app/Cargo.toml b/enigma-principal/app/Cargo.toml index 11000e17..8eb05bd4 100644 --- a/enigma-principal/app/Cargo.toml +++ b/enigma-principal/app/Cargo.toml @@ -22,6 +22,7 @@ rmp-serde = "0.13.7" structopt = "0.2.10" url = "1.7.1" colour = "0.3" +crossbeam-utils = "0.7" dirs = "1.0" web3 = { version = "0.8", default-features = false, features=["http", "tls"] } jsonrpc-http-server = "11.0.0" diff --git a/enigma-principal/app/src/boot_network/principal_manager.rs b/enigma-principal/app/src/boot_network/principal_manager.rs index ccb4cedd..bb243c73 100644 --- a/enigma-principal/app/src/boot_network/principal_manager.rs +++ b/enigma-principal/app/src/boot_network/principal_manager.rs @@ -1,4 +1,4 @@ -use std::{fs::File, io::prelude::*, str, sync::Arc, thread}; +use std::{fs::File, io::prelude::*, str, sync::Arc}; use failure::Error; use rustc_hex::ToHex; @@ -12,6 +12,7 @@ use web3::{ Web3, }; use envy; +use crossbeam_utils::thread; use enigma_crypto::EcdsaSign; use boot_network::{deploy_scripts, keys_provider_http::PrincipalHttpServer, principal_utils::Principal}; @@ -205,8 +206,7 @@ impl PrincipalManager { // General interface of a Sampler == The entity that manages the principal node logic. pub trait Sampler { /// load with config from file - fn new(contract: Arc, report_manager: ReportManager) -> Self - where Self: Sized; + fn new(contract: Arc, report_manager: ReportManager) -> Self; fn get_signing_address(&self) -> Result; @@ -318,44 +318,41 @@ impl Sampler for PrincipalManager { // Start the JSON-RPC Server let port = self.report_manager.config.http_port; let server_ep = Arc::clone(&epoch_provider); - thread::spawn(move || { - let server = PrincipalHttpServer::new(server_ep, port); - server.start(); + thread::scope(|s| { + s.spawn(|_| { + let server = PrincipalHttpServer::new(server_ep, port); + server.start(); + }); + s.spawn(|_|{ + // watch blocks + let polling_interval = self.report_manager.config.polling_interval; + let epoch_size = self.report_manager.config.epoch_size; + self.contract.watch_blocks( + epoch_size, + polling_interval, + epoch_provider, + gas_limit, + self.report_manager.config.confirmations as usize, + self.report_manager.config.max_epochs, + ); + }); }); - - // watch blocks - let polling_interval = self.report_manager.config.polling_interval; - let epoch_size = self.report_manager.config.epoch_size; - self.contract.watch_blocks( - epoch_size, - polling_interval, - epoch_provider, - gas_limit, - self.report_manager.config.confirmations as usize, - self.report_manager.config.max_epochs, - ); Ok(()) } } -/// Helper method to start 'miner' that simulates blocks. -pub fn run_miner(account: Address, w3: Arc>, interval: u64) -> thread::JoinHandle<()> { - thread::spawn(move || { - deploy_scripts::forward_blocks(&Arc::clone(&w3), interval, account).unwrap(); - }) -} - //////////////////////// TESTS ///////////////////////////////////////// #[cfg(test)] mod test { extern crate tempfile; - use std::{env, path::Path, sync::Arc, thread, time}; + use std::{env, path::Path, sync::Arc, time}; use web3::{futures::{Future, stream::Stream}, types::FilterBuilder, }; - + use crossbeam_utils::thread; use enigma_tools_u::web3_utils::enigma_contract::EnigmaContract; use epoch_u::epoch_types::{WorkersParameterizedEvent, WORKER_PARAMETERIZED_EVENT}; + use boot_network::deploy_scripts; use esgx::general::init_enclave_wrapper; use super::*; @@ -424,35 +421,39 @@ mod test { let principal = init_no_deploy(eid).unwrap(); let account = principal.get_account_address(); - // run simulated miner - run_miner(account, Arc::clone(&principal.contract.web3), 1); - let contract = Arc::clone(&principal.contract); - let child = thread::spawn(move || { - let event = WorkersParameterizedEvent::new(); - let event_sig = event.0.signature(); - let filter = FilterBuilder::default() - .address(vec![contract.address()]) - .topics(Some(vec![event_sig.into()]), None, None, None) - .build(); - - let event_future = contract - .web3 - .eth_filter() - .create_logs_filter(filter) - .then(|filter| { - filter.unwrap().stream(time::Duration::from_secs(1)).for_each(|log| { - println!("Got {} log: {:?}", WORKER_PARAMETERIZED_EVENT, log); - Ok(()) + thread::scope(|s| { + // run simulated miner + s.spawn(|_| { + let interval = 1; + deploy_scripts::forward_blocks(&Arc::clone(&principal.contract.web3), interval, account).unwrap(); + }); + s.spawn(|_| { + let event = WorkersParameterizedEvent::new(); + let event_sig = event.0.signature(); + let filter = FilterBuilder::default() + .address(vec![contract.address()]) + .topics(Some(vec![event_sig.into()]), None, None, None) + .build(); + + let event_future = contract + .web3 + .eth_filter() + .create_logs_filter(filter) + .then(|filter| { + filter.unwrap().stream(time::Duration::from_secs(1)).for_each(|log| { + println!("Got {} log: {:?}", WORKER_PARAMETERIZED_EVENT, log); + Ok(()) + }) }) - }) - .map_err(|err| eprintln!("Unable to process WorkersParameterized log: {:?}", err)); - event_future.wait().unwrap(); + .map_err(|err| eprintln!("Unable to process WorkersParameterized log: {:?}", err)); + event_future.wait().unwrap(); + }); + s.spawn(|_| { + // run principal + principal.run(tempdir.into_path(), true, GAS_LIMIT).unwrap(); + }); }); - - // run principal - principal.run(tempdir.into_path(), true, GAS_LIMIT).unwrap(); - child.join().unwrap(); } #[test] diff --git a/enigma-principal/app/src/cli/app.rs b/enigma-principal/app/src/cli/app.rs index e70b7b4e..15175fd0 100644 --- a/enigma-principal/app/src/cli/app.rs +++ b/enigma-principal/app/src/cli/app.rs @@ -85,12 +85,12 @@ pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { let principal: PrincipalManager = PrincipalManager::new( enigma_contract, report_manager); println!("Connected to the Enigma contract: {:?} with account: {:?}", &contract_address, principal.get_account_address()); - // step 2 optional - run miner to simulate blocks - let join_handle = if opt.mine > 0 { - Some(principal_manager::run_miner(principal.get_account_address(), principal.get_web3(), opt.mine as u64)) - } else { - None - }; +// // step 2 optional - run miner to simulate blocks +// let join_handle = if opt.mine > 0 { +// Some(principal_manager::run_miner(principal.get_account_address(), principal.get_web3(), opt.mine as u64)) +// } else { +// None +// }; let eid_safe = Arc::new(eid); //TODO: Ugly, refactor to instantiate only once, consider passing to the run method @@ -119,9 +119,9 @@ pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { } else { principal.run(path, false, gas_limit).unwrap(); } - if let Some(t) = join_handle { - t.join().unwrap(); - } +// if let Some(t) = join_handle { +// t.join().unwrap(); +// } } Ok(()) } diff --git a/enigma-principal/app/src/main.rs b/enigma-principal/app/src/main.rs index ae93c7c2..e3ad65a8 100644 --- a/enigma-principal/app/src/main.rs +++ b/enigma-principal/app/src/main.rs @@ -33,7 +33,7 @@ extern crate web3; extern crate rmp_serde; extern crate envy; extern crate itertools; - +extern crate crossbeam_utils; extern crate secp256k1; From fcf1dfd44b4ed3a46970c66c171cdcc68918884c Mon Sep 17 00:00:00 2001 From: Avishai Weingarten Date: Sun, 2 Feb 2020 15:10:43 +0200 Subject: [PATCH 10/28] MAINT: refactoring the KM-1 --- .../app/src/boot_network/deploy_scripts.rs | 4 +- .../src/boot_network/keys_provider_http.rs | 40 +- enigma-principal/app/src/boot_network/mod.rs | 1 - .../app/src/boot_network/principal_manager.rs | 488 ++++++------------ enigma-principal/app/src/cli/app.rs | 145 +++--- enigma-principal/app/src/cli/options.rs | 88 ---- .../{epoch_u => controller}/epoch_types.rs | 4 +- .../app/src/controller/km_controller.rs | 404 +++++++++++++++ .../km_utils.rs} | 31 +- enigma-principal/app/src/controller/mod.rs | 4 + .../app/src/controller/verifier.rs | 201 ++++++++ .../app/src/epoch_u/epoch_provider.rs | 443 ---------------- enigma-principal/app/src/epoch_u/mod.rs | 2 - .../app/src/esgx/epoch_keeper_u.rs | 6 +- enigma-principal/app/src/esgx/equote.rs | 1 - enigma-principal/app/src/main.rs | 4 +- .../src/web3_utils/enigma_contract.rs | 9 +- 17 files changed, 886 insertions(+), 989 deletions(-) rename enigma-principal/app/src/{epoch_u => controller}/epoch_types.rs (99%) create mode 100644 enigma-principal/app/src/controller/km_controller.rs rename enigma-principal/app/src/{boot_network/principal_utils.rs => controller/km_utils.rs} (56%) create mode 100644 enigma-principal/app/src/controller/mod.rs create mode 100644 enigma-principal/app/src/controller/verifier.rs delete mode 100644 enigma-principal/app/src/epoch_u/epoch_provider.rs delete mode 100644 enigma-principal/app/src/epoch_u/mod.rs diff --git a/enigma-principal/app/src/boot_network/deploy_scripts.rs b/enigma-principal/app/src/boot_network/deploy_scripts.rs index e26fc1cf..d713aaf5 100644 --- a/enigma-principal/app/src/boot_network/deploy_scripts.rs +++ b/enigma-principal/app/src/boot_network/deploy_scripts.rs @@ -1,7 +1,7 @@ use enigma_tools_u::web3_utils::w3utils; use failure::Error; use rustc_hex::ToHex; -use std::{str, sync::Arc, thread, time}; +use std::{str, thread, time}; use web3::{ contract::{Contract, Options}, futures::Future, @@ -27,7 +27,7 @@ fn deploy_dummy_miner(w3: &Web3, deployer: &str) -> Result, } /// TESTING: mimic block creation to test the watch blocks method of the principal node -pub fn forward_blocks(w3: &Arc>, interval: u64, deployer: Address) -> Result<(), Error> { +pub fn forward_blocks(w3: &Web3, interval: u64, deployer: Address) -> Result<(), Error> { let contract = deploy_dummy_miner(&w3, &deployer.to_fixed_bytes().to_hex())?; println!("deployed dummy contract at address = {:?}", contract.address()); loop { diff --git a/enigma-principal/app/src/boot_network/keys_provider_http.rs b/enigma-principal/app/src/boot_network/keys_provider_http.rs index 4a405702..63b722f6 100644 --- a/enigma-principal/app/src/boot_network/keys_provider_http.rs +++ b/enigma-principal/app/src/boot_network/keys_provider_http.rs @@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize}; use enigma_crypto::KeyPair; use enigma_types::{ContractAddress, EnclaveReturn}; use enigma_tools_u::web3_utils::enigma_contract::ContractQueries; -use epoch_u::{epoch_provider::EpochProvider, epoch_types::EpochState}; +use controller::{km_controller::KMController, epoch_types::SignedEpoch}; use esgx::keys_keeper_u::get_enc_state_keys; use esgx; use common_u::errors::{RequestValueErr, EnclaveFailError, EpochStateTransitionErr, JSON_RPC_ERROR_ILLEGAL_STATE, JSON_RPC_ERROR_WORKER_NOT_AUTHORIZED}; @@ -86,7 +86,7 @@ impl From for StringWrapper { } pub struct PrincipalHttpServer { - epoch_provider: Arc, + controller: Arc, pub port: u16, } @@ -99,10 +99,10 @@ impl StateKeyRequest { } impl PrincipalHttpServer { - pub fn new(epoch_provider: Arc, port: u16) -> PrincipalHttpServer { PrincipalHttpServer { epoch_provider, port } } + pub fn new(controller: Arc, port: u16) -> PrincipalHttpServer { PrincipalHttpServer { controller, port } } #[logfn(DEBUG)] - fn find_epoch_contract_addresses(request: &StateKeyRequest, msg: &PrincipalMessage, epoch_state: &EpochState) -> Result, Error> { + fn find_epoch_contract_addresses(request: &StateKeyRequest, msg: &PrincipalMessage, epoch_state: &SignedEpoch) -> Result, Error> { let image = msg.to_sign()?; let sig = request.get_sig()?; let worker = KeyPair::recover(&image, sig)?.address(); @@ -112,10 +112,10 @@ impl PrincipalHttpServer { } #[logfn(DEBUG)] - pub fn get_state_keys(epoch_provider: &EpochProvider, request: StateKeyRequest) -> Result { + pub fn get_state_keys(&self, request: StateKeyRequest) -> Result { let epoch_state = match request.block_number.clone() { - Some(block_number) => epoch_provider.find_epoch(block_number.try_into()?)?, - None => epoch_provider.find_last_epoch()?, + Some(block_number) => self.controller.find_epoch(block_number.try_into()?)?, + None => self.controller.find_last_epoch()?, }; let addresses = &request.addresses; let addrs: Vec = { @@ -128,7 +128,7 @@ impl PrincipalHttpServer { Self::find_epoch_contract_addresses(&request, &msg, &epoch_state)? } }; - let response = get_enc_state_keys(*epoch_provider.eid, request, epoch_state.nonce, &addrs)?; + let response = get_enc_state_keys(self.controller.eid, request, epoch_state.nonce, &addrs)?; let response_data = serde_json::to_value(&response)?; Ok(response_data) } @@ -171,14 +171,14 @@ impl PrincipalHttpServer { /// This function is used to make sure the km is up and running. /// it can be requested via the jsonRPC server using the following command: /// curl -sb -o /dev/null -X POST -d '{"jsonrpc": "2.0", "id": "1", "method": "getHealthCheck", "params": []}' -H "Content-Type: application/json" 127.0.0.1:3040 - pub fn health_check(epoch_provider: &EpochProvider) -> Value { + pub fn health_check(&self) -> Value { // Ethereum - let contract_signing_address = match epoch_provider.contract.get_signing_address() { + let contract_signing_address = match self.controller.contract.get_signing_address() { Ok(addr) => addr, Err(_) => return Value::Bool(false), }; // Enclave - let enclave_signing_address: H160 = match esgx::equote::get_register_signing_address(*epoch_provider.eid) { + let enclave_signing_address: H160 = match esgx::equote::get_register_signing_address(self.controller.eid) { Ok(addr) => addr.into(), Err(_) => return Value::Bool(false), }; @@ -190,18 +190,18 @@ impl PrincipalHttpServer { /// Example: /// curl -X POST --data '{"jsonrpc": "2.0", "id": "1", "method": "getStateKeys", "params": ["84a46461746181a75265717565737493dc0020cca7cc937b64ccb8cccacca5cc8f03721bccb6ccbacccf5c78cccb235fccebcce0cce70b1bcc84cccdcc99541461cca0cc8edc002016367accacccb67a4a017ccc8dcca8ccabcc95682ccccb390863780f7114ccddcca0cca0cce0ccc55644ccc7ccc4dc0020ccb1cce9cc9324505bccd32dcca0cce1ccf85dcccf5e19cca0cc9dccb0481ecc8a15ccf62c41cceb320304cca8cce927a269649c1363ccb3301c101f33cce1cc9a0524a67072656669789e456e69676d61204d657373616765a67075626b6579dc0040cce5ccbe28cc9dcc9a2eccbd08ccc0457a5f16ccdfcc9fccdc256c5d5f6c3514cccdcc95ccb47c11ccc4cccd3e31ccf0cce4ccefccc83ccc80cce8121c3939ccbb2561cc80ccec48ccbecca8ccc569ccd2cca3ccda6bcce415ccfa20cc9bcc98ccda", "43f19586b0a0ae626b9418fe8355888013be1c9b4263a4b3a27953de641991e936ed6c4076a2a383b3b001936bf0eb6e23c78fbec1ee36f19c6a9d24d75e9e081c"]}' -H "Content-Type: application/json" http://127.0.0.1:3040/ #[logfn(DEBUG)] - pub fn start(&self) { + pub fn start(self) { + let server1 = Arc::new(self); + let server2 = Arc::clone(&server1); + let port = server2.port; let mut io = IoHandler::default(); - let epoch_provider = Arc::clone(&self.epoch_provider); - let port = self.port; io.add_method(METHOD_GET_STATE_KEYS, move |params: Params| { let request = params.parse::()?; - let body = Self::get_state_keys(&epoch_provider, request).map_err(Self::handle_error)?; // Not sure that this is the best idiom + let body = server1.get_state_keys(request).map_err(Self::handle_error)?; // Not sure that this is the best idiom Ok(body) }); - let hc_epoch_provider = Arc::clone(&self.epoch_provider); - io.add_method(METHOD_GET_HEALTH_CHECK, move |_| { - let body = Self::health_check(&hc_epoch_provider); + io.add_method(METHOD_GET_HEALTH_CHECK, move |_| { + let body = server2.health_check(); Ok(body) }); let server = @@ -224,7 +224,7 @@ mod test { use web3::types::Bytes; use enigma_types::{ContractAddress, Hash256}; - use epoch_u::epoch_types::ConfirmedEpochState; + use controller::epoch_types::ConfirmedEpochState; use esgx::epoch_keeper_u::set_or_verify_worker_params; use esgx::epoch_keeper_u::tests::get_worker_params; use esgx::general::init_enclave_wrapper; @@ -279,7 +279,7 @@ mod test { let sig = Bytes::from(REF_SIG.from_hex().unwrap()); let nonce = U256::from(0); let km_block_number = U256::from(1); - let epoch_state = EpochState { seed, sig, nonce, km_block_number, confirmed_state }; + let epoch_state = SignedEpoch { seed, sig, nonce, km_block_number, confirmed_state }; let msg = PrincipalMessage::from_message(&request.get_data().unwrap()).unwrap(); let results = PrincipalHttpServer::find_epoch_contract_addresses(&request, &msg, &epoch_state).unwrap(); assert_eq!(results, vec![address]) diff --git a/enigma-principal/app/src/boot_network/mod.rs b/enigma-principal/app/src/boot_network/mod.rs index 4b0b0abe..499ba8bd 100644 --- a/enigma-principal/app/src/boot_network/mod.rs +++ b/enigma-principal/app/src/boot_network/mod.rs @@ -1,4 +1,3 @@ pub mod deploy_scripts; pub mod keys_provider_http; pub mod principal_manager; -pub mod principal_utils; diff --git a/enigma-principal/app/src/boot_network/principal_manager.rs b/enigma-principal/app/src/boot_network/principal_manager.rs index bb243c73..c1ceeeed 100644 --- a/enigma-principal/app/src/boot_network/principal_manager.rs +++ b/enigma-principal/app/src/boot_network/principal_manager.rs @@ -1,38 +1,20 @@ -use std::{fs::File, io::prelude::*, str, sync::Arc}; +use std::{fs::File, io::prelude::*, str}; -use failure::Error; -use rustc_hex::ToHex; use serde_derive::*; use serde_json; use sgx_types::sgx_enclave_id_t; -use web3::{ - futures::Future, - transports::Http, - types::{Address, H160, H256, U256}, - Web3, -}; use envy; -use crossbeam_utils::thread; use enigma_crypto::EcdsaSign; -use boot_network::{deploy_scripts, keys_provider_http::PrincipalHttpServer, principal_utils::Principal}; -use enigma_tools_u::{ - attestation_service::service, - esgx::equote::retry_quote, - web3_utils::enigma_contract::{ContractFuncs, ContractQueries, EnigmaContract}, -}; -use epoch_u::epoch_provider::EpochProvider; use esgx; -use enigma_tools_u::common_u::errors::Web3Error; -use std::path::PathBuf; use secp256k1::key::SecretKey; use secp256k1::Message; use secp256k1::Secp256k1; -use common_u::custom_errors::{ConfigError, ReportManagerErr}; +use common_u::custom_errors::ConfigError; #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct PrincipalConfig { +pub struct KMConfig { // Path to IEnigma.Json ** probably a good place to document that IEnigma.Json is used because parsing the entire Enigma.json will fail to due missing types pub enigma_contract_path: String, // Not 100% sure on this one. Path to where we download the enigma.json ABI from? Either way, probably unused @@ -69,23 +51,18 @@ pub struct PrincipalConfig { pub confirmations: u64, } -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct RegistrationParams { - pub signing_address: String, - pub report: String, - pub signature: String, -} -pub struct ReportManager { - pub config: PrincipalConfig, - as_service: service::AttestationService, - pub eid: sgx_enclave_id_t, -} +// +//pub struct ReportManager { +// pub config: KMConfig, +// as_service: service::AttestationService, +// pub eid: sgx_enclave_id_t, +//} -pub struct PrincipalManager { - pub contract: Arc, - report_manager: ReportManager, -} +//pub struct PrincipalManager { +// pub contract: EnigmaContract, +// report_manager: ReportManager, +//} pub struct SgxEthereumSigner { eid: sgx_enclave_id_t, @@ -133,59 +110,57 @@ impl EcdsaSign for PrivateKeyEthereumSigner { } } -impl ReportManager { - pub fn new(config: PrincipalConfig, eid: sgx_enclave_id_t) -> Self { - let as_service = service::AttestationService::new_with_retries(&config.attestation_service_url, config.attestation_retries); - ReportManager { config, as_service, eid } - } - - pub fn get_signing_address(&self) -> Result { - let _signing_address = esgx::equote::get_register_signing_address(self.eid).or(Err(ReportManagerErr::GetRegisterAddrErr))?; - let signing_address = _signing_address.to_vec().to_hex(); - Ok(signing_address) - } - - pub fn get_ethereum_address(&self) -> Result { - if self.config.with_private_key { - return Ok(self.config.account_address.clone()); - } - let _signing_address = esgx::equote::get_ethereum_address(self.eid).or(Err(ReportManagerErr::GetEtherAddrErr))?; - let signing_address = _signing_address.to_vec().to_hex(); - Ok(signing_address) - } - - #[logfn(DEBUG)] - pub fn get_registration_params(&self) -> Result { - let signing_address = self.get_signing_address()?; - let mode = option_env!("SGX_MODE").unwrap_or_default(); - let enc_quote = retry_quote(self.eid, &self.config.spid, 18).or(Err(ReportManagerErr::QuoteErr))?; - - let report: String; - let signature: String; - if mode == "SW" { - // Software Mode - println!("Simulation mode"); - report = enc_quote; - signature = String::new(); - } else { - // Hardware Mode - println!("Hardware mode"); - let response = self.as_service.get_report(enc_quote).or(Err(ReportManagerErr::QuoteErr))?; - report = response.result.report_string; - signature = response.result.signature; - } - Ok(RegistrationParams { signing_address, report, signature }) - } -} - -impl PrincipalConfig { +//impl ReportManager { +// pub fn new(config: KMConfig, eid: sgx_enclave_id_t) -> Self { +// let as_service = service::AttestationService::new_with_retries(&config.attestation_service_url, config.attestation_retries); +// ReportManager { config, as_service, eid } +// } +// +// pub fn get_signing_address(&self) -> Result { +// esgx::equote::get_register_signing_address(self.eid).or(Err(ReportManagerErr::GetRegisterAddrErr)).into() +// } +// +// pub fn get_ethereum_address(&self) -> Result { +// if self.config.with_private_key { +// return Ok(self.config.account_address.clone()); +// } +// let _signing_address = esgx::equote::get_ethereum_address(self.eid).or(Err(ReportManagerErr::GetEtherAddrErr))?; +// let signing_address = _signing_address.to_vec().to_hex(); +// Ok(signing_address) +// } +// +// #[logfn(DEBUG)] +// pub fn get_registration_params(&self) -> Result { +// let signing_address = self.get_signing_address()?; +// let mode = option_env!("SGX_MODE").unwrap_or_default(); +// let enc_quote = retry_quote(self.eid, &self.config.spid, 18).or(Err(ReportManagerErr::QuoteErr))?; +// +// let report: String; +// let signature: String; +// if mode == "SW" { +// // Software Mode +// println!("Simulation mode"); +// report = enc_quote; +// signature = String::new(); +// } else { +// // Hardware Mode +// println!("Hardware mode"); +// let response = self.as_service.get_report(enc_quote).or(Err(ReportManagerErr::QuoteErr))?; +// report = response.result.report_string; +// signature = response.result.signature; +// } +// Ok(RegistrationParams { signing_address, report, signature }) +// } +//} + +impl KMConfig { // load json config into the struct #[logfn(DEBUG)] - pub fn load_config(config_path: &str) -> Result { + pub fn load_config(config_path: &str) -> Result { info!("loading Principal config"); // All configurations from env should be with the same names of the // PrincipalConfig struct fields in uppercase letters - match envy::from_env::() { + match envy::from_env::() { Ok(config) => Ok(config), Err(_) => { info!("trying to load from path: {:?}", config_path); @@ -199,147 +174,94 @@ impl PrincipalConfig { } } } -impl PrincipalManager { - pub fn get_web3(&self) -> Arc> { Arc::clone(&self.contract.web3) } -} - -// General interface of a Sampler == The entity that manages the principal node logic. -pub trait Sampler { - /// load with config from file - fn new(contract: Arc, report_manager: ReportManager) -> Self; - - fn get_signing_address(&self) -> Result; - - fn get_contract_address(&self) -> Address; - - fn get_account_address(&self) -> Address; - - fn get_network_url(&self) -> String; - - fn get_block_number(&self) -> Result; - - fn register>(&self, signing_address: H160, gas_limit: G) -> Result; - - fn verify_identity_or_register>(&self, gas_limit: G) -> Result, Error>; - - /// after initiation, this will run the principal node and block. - fn run>(&self, path: PathBuf, reset_epoch: bool, gas: G) -> Result<(), Error>; -} - -impl Sampler for PrincipalManager { - fn new(contract: Arc, report_manager: ReportManager) -> Self { - PrincipalManager { contract, report_manager } - } - - fn get_signing_address(&self) -> Result { - let sig_addr = self.report_manager.get_signing_address()?; - Ok(sig_addr.parse()?) - } - fn get_contract_address(&self) -> Address { self.contract.address() } - - // noinspection RsBorrowChecker - fn get_account_address(&self) -> Address { self.contract.account } - - fn get_network_url(&self) -> String { self.report_manager.config.url.clone() } - - fn get_block_number(&self) -> Result { - let block_number = match self.get_web3().eth().block_number().wait() { - Ok(block_number) => block_number, - Err(err) => return Err(Web3Error { - message: format!("Current block number not available: {:?}", err), - }.into()), - }; - Ok(block_number) - } - - #[logfn(DEBUG)] - fn register>(&self, signing_address: H160, gas_limit: G) -> Result { - let registration_params = self.report_manager.get_registration_params()?; - // the register method on the Enigma contract expects a staking address - // since it's suited for the workers as well. - // staking is irrelevant for the KM and therefore we are sending an empty address - let staking_address = H160::zero(); - println!("Registering"); - let receipt = self.contract.register( - staking_address, - signing_address, - registration_params.report, - registration_params.signature, - gas_limit, - self.report_manager.config.confirmations as usize, - )?; - Ok(receipt.transaction_hash) - } - - /// Verifies whether the worker is registered in the Enigma contract. - /// If not, create a `register` transaction. - /// - /// # Arguments - /// - /// * `gas_limit` - The gas limit of the `register` transaction - #[logfn(DEBUG)] - fn verify_identity_or_register>(&self, gas_limit: G) -> Result, Error> { - let signing_address = self.get_signing_address()?; - let registered_signing_address = self.contract.get_signing_address()?; - if signing_address == registered_signing_address { - debug!("Already registered with enigma signing address {:?}", registered_signing_address); - Ok(None) - } else { - let tx = self.register(signing_address, gas_limit)?; - debug!("Registered by transaction {:?}", tx); - Ok(Some(tx)) - } - } - - /// Warms up the application. - /// 1. Register the worker if not already registered - /// 2. Create an `EpochProvider` which loads the local `EpochState` if available - /// 3. Start the JSON-RPC server - /// 4. Watch the blocks for new epochs - /// - /// # Arguments - /// - /// * `path` - path to the directory in which we store the epoch state. - /// * `reset_epoch` - If true, reset the epoch state - /// * `gas_limit` - The gas limit for all Enigma contract transactions - #[logfn(INFO)] - fn run>(&self, path: PathBuf, reset_epoch: bool, gas_limit: G) -> Result<(), Error> { - let gas_limit: U256 = gas_limit.into(); - self.verify_identity_or_register(gas_limit)?; - // get enigma contract - // Start the WorkerParameterized Web3 log filter - let eid: Arc = Arc::new(self.report_manager.eid); - let epoch_provider = Arc::new(EpochProvider::new(eid, path, self.contract.clone())?); - if reset_epoch { - epoch_provider.epoch_state_manager.reset()?; - } - - // Start the JSON-RPC Server - let port = self.report_manager.config.http_port; - let server_ep = Arc::clone(&epoch_provider); - thread::scope(|s| { - s.spawn(|_| { - let server = PrincipalHttpServer::new(server_ep, port); - server.start(); - }); - s.spawn(|_|{ - // watch blocks - let polling_interval = self.report_manager.config.polling_interval; - let epoch_size = self.report_manager.config.epoch_size; - self.contract.watch_blocks( - epoch_size, - polling_interval, - epoch_provider, - gas_limit, - self.report_manager.config.confirmations as usize, - self.report_manager.config.max_epochs, - ); - }); - }); - Ok(()) - } -} +//// General interface of a Sampler == The entity that manages the principal node logic. +//pub trait Sampler { +// /// load with config from file +// fn new(contract: EnigmaContract, report_manager: ReportManager) -> Self; +// +// fn get_signing_address(&self) -> Result; +// +// fn get_contract_address(&self) -> Address; +// +// fn get_account_address(&self) -> Address; +// +// fn get_network_url(&self) -> String; +// +// fn get_block_number(&self) -> Result; +// +// fn register>(&self, signing_address: H160, gas_limit: G) -> Result; +// +// /// after initiation, this will run the principal node and block. +// fn run>(&self, path: PathBuf, reset_epoch: bool, gas: G) -> Result<(), Error>; +//} + +//impl Sampler for PrincipalManager { +// fn new(contract: EnigmaContract, report_manager: ReportManager) -> Self { +// PrincipalManager { contract, report_manager } +// } +// +// fn get_signing_address(&self) -> Result { +// let sig_addr = self.report_manager.get_signing_address()?; +// Ok(sig_addr.parse()?) +// } +// +// +// fn get_network_url(&self) -> String { self.report_manager.config.url.clone() } +// +//// fn get_block_number(&self) -> Result { +//// let block_number = self.contract.web3.eth().block_number().wait(). +//// map_err(|e| { Web3Error { message: format!("Current block number not available: {:?}", e), }.into()})? +//// } +// +// /// Warms up the application. +// /// 1. Register the worker if not already registered +// /// 2. Create an `EpochProvider` which loads the local `EpochState` if available +// /// 3. Start the JSON-RPC server +// /// 4. Watch the blocks for new epochs +// /// +// /// # Arguments +// /// +// /// * `path` - path to the directory in which we store the epoch state. +// /// * `reset_epoch` - If true, reset the epoch state +// /// * `gas_limit` - The gas limit for all Enigma contract transactions +// #[logfn(INFO)] +// fn run>(&self, path: PathBuf, reset_epoch: bool, gas_limit: G) -> Result<(), Error> { +// let gas_limit: U256 = gas_limit.into(); +// self.verify_identity_or_register(gas_limit)?; +// // get enigma contract +// // Start the WorkerParameterized Web3 log filter +// let eid: sgx_enclave_id_t = self.report_manager.eid; +// let epoch_provider = KMController::new(eid, path, self.contract.clone())?; +// if reset_epoch { +// epoch_provider.epoch_state_manager.reset()?; +// } +// +// // Start the JSON-RPC Server +// let port = self.report_manager.config.http_port; +// let server_ep = &epoch_provider; +// thread::scope(|s| { +// s.spawn(|_| { +// let server = PrincipalHttpServer::new(server_ep, port); +// server.start(); +// }); +// s.spawn(|_|{ +// // watch blocks +// let polling_interval = self.report_manager.config.polling_interval; +// let epoch_size = self.report_manager.config.epoch_size; +// self.contract.watch_blocks( +// epoch_size, +// polling_interval, +// epoch_provider, +// gas_limit, +// self.report_manager.config.confirmations as usize, +// self.report_manager.config.max_epochs, +// ); +// }); +// }); +// Ok(()) +// } +//} //////////////////////// TESTS ///////////////////////////////////////// @@ -347,114 +269,34 @@ impl Sampler for PrincipalManager { mod test { extern crate tempfile; use std::{env, path::Path, sync::Arc, time}; - + use failure::Error; use web3::{futures::{Future, stream::Stream}, types::FilterBuilder, }; use crossbeam_utils::thread; use enigma_tools_u::web3_utils::enigma_contract::EnigmaContract; - use epoch_u::epoch_types::{WorkersParameterizedEvent, WORKER_PARAMETERIZED_EVENT}; + use controller::epoch_types::{WorkersParameterizedEvent, WORKER_PARAMETERIZED_EVENT}; use boot_network::deploy_scripts; use esgx::general::init_enclave_wrapper; use super::*; - const GAS_LIMIT: usize = 5999999; - - #[logfn(DEBUG)] - pub fn get_config() -> Result { - let config_path = "../app/tests/principal_node/config/principal_test_config.json"; - let config = PrincipalConfig::load_config(config_path)?; - Ok(config) - } - - pub fn init_no_deploy(eid: u64) -> Result { - let mut config = get_config()?; - let enclave_manager = ReportManager::new(config.clone(), eid); - let ethereum_signer = Box::new(SgxEthereumSigner{eid}) as Box; - let contract = Arc::new(EnigmaContract::from_deployed( - &config.enigma_contract_address, - Path::new(&config.enigma_contract_path), - Some(&config.account_address), - config.chain_id, - &config.url, - ethereum_signer, - )?); - let _gas_limit = 5_999_999; - config.max_epochs = None; - let principal: PrincipalManager = PrincipalManager::new( contract, enclave_manager); - Ok(principal) - } - // TODO: The two tests below require the Enigma contract to be deployed /// Not a standalone unit test, must be coordinated with the Enigma Contract tests - #[test] - #[ignore] - fn test_set_worker_params() { - let tempdir = tempfile::tempdir().unwrap(); - let gas_limit: U256 = 5999999.into(); - let enclave = init_enclave_wrapper().unwrap(); - let eid = enclave.geteid(); - let principal = init_no_deploy(eid).unwrap(); - principal.verify_identity_or_register(gas_limit).unwrap(); - - let block_number = principal.get_block_number().unwrap(); - let eid_safe = Arc::new(eid); - let epoch_provider = EpochProvider::new(eid_safe, tempdir.into_path(), principal.contract.clone()).unwrap(); - epoch_provider.epoch_state_manager.reset().unwrap(); - epoch_provider.set_worker_params(block_number, gas_limit, 0).unwrap(); - } - - /// This test is more like a system-test than a unit-test. - /// It is only dependent on an ethereum node running under the NODE_URL evn var or the default localhost:8545 - /// First it deploys all the contracts related (EnigmaToken, Enigma) and runs miner to simulate blocks. - /// Second, it spawns a background thread to poll for events and searchses for the WorkersParameterized event. - /// Then, the principal register (full process including quote) and then, - /// starts watching blocks and emits random with WorkersParameterized event. - /// The testing is looking for atleast 2 emmits of the WorkersParameterized event and compares the event triggerd - /// If the event name is different or if it takes more than 30 seconds then the test will fail. - #[test] - #[ignore] - fn test_full_principal_logic() { - let tempdir = tempfile::tempdir().unwrap(); - let _gas_limit: U256 = 5999999.into(); - let enclave = init_enclave_wrapper().unwrap(); - let eid = enclave.geteid(); - let principal = init_no_deploy(eid).unwrap(); - let account = principal.get_account_address(); - - let contract = Arc::clone(&principal.contract); - thread::scope(|s| { - // run simulated miner - s.spawn(|_| { - let interval = 1; - deploy_scripts::forward_blocks(&Arc::clone(&principal.contract.web3), interval, account).unwrap(); - }); - s.spawn(|_| { - let event = WorkersParameterizedEvent::new(); - let event_sig = event.0.signature(); - let filter = FilterBuilder::default() - .address(vec![contract.address()]) - .topics(Some(vec![event_sig.into()]), None, None, None) - .build(); - - let event_future = contract - .web3 - .eth_filter() - .create_logs_filter(filter) - .then(|filter| { - filter.unwrap().stream(time::Duration::from_secs(1)).for_each(|log| { - println!("Got {} log: {:?}", WORKER_PARAMETERIZED_EVENT, log); - Ok(()) - }) - }) - .map_err(|err| eprintln!("Unable to process WorkersParameterized log: {:?}", err)); - event_future.wait().unwrap(); - }); - s.spawn(|_| { - // run principal - principal.run(tempdir.into_path(), true, GAS_LIMIT).unwrap(); - }); - }); - } +// #[test] +// #[ignore] +// fn test_set_worker_params() { +// let tempdir = tempfile::tempdir().unwrap(); +// let gas_limit: U256 = 5999999.into(); +// let enclave = init_enclave_wrapper().unwrap(); +// let eid = enclave.geteid(); +// let principal = init_no_deploy(eid).unwrap(); +// principal.verify_identity_or_register(gas_limit).unwrap(); +// +// let block_number = principal.get_block_number().unwrap(); +// let eid_safe = eid; +// let epoch_provider = KMController::new(eid_safe, tempdir.into_path(), principal.contract.clone()).unwrap(); +// epoch_provider.epoch_state_manager.reset().unwrap(); +// epoch_provider.set_worker_params(block_number, gas_limit, 0).unwrap(); +// } #[test] fn test_load_config_from_env() { @@ -475,7 +317,7 @@ mod test { env::set_var("HTTP_PORT","3040"); env::set_var("CONFIRMATIONS","0"); env::set_var("CHAIN_ID", "13"); - let config = PrincipalConfig::load_config("this is not a path").unwrap(); + let config = KMConfig::load_config("this is not a path").unwrap(); assert_eq!(config.polling_interval, 1); assert_eq!(config.http_port, 3040); assert_eq!(config.attestation_retries, 11); diff --git a/enigma-principal/app/src/cli/app.rs b/enigma-principal/app/src/cli/app.rs index 15175fd0..ee2f7f14 100644 --- a/enigma-principal/app/src/cli/app.rs +++ b/enigma-principal/app/src/cli/app.rs @@ -1,11 +1,8 @@ +use std::sync::Arc; use boot_network::{ - keys_provider_http::{PrincipalHttpServer, StateKeyRequest}, + keys_provider_http::PrincipalHttpServer, principal_manager::{ - self, - PrincipalManager, - ReportManager, - Sampler, - PrincipalConfig, + KMConfig, SgxEthereumSigner, PrivateKeyEthereumSigner }, @@ -13,13 +10,17 @@ use boot_network::{ use cli; use enigma_crypto::EcdsaSign; use enigma_tools_u::{esgx::general::storage_dir, web3_utils::enigma_contract::EnigmaContract}; -use epoch_u::epoch_provider::EpochProvider; +use controller::{km_controller::KMController, km_utils::Principal}; use esgx::general::ENCLAVE_DIR; +use esgx::equote; use failure::Error; use sgx_types::sgx_enclave_id_t; -use std::{fs::File, io::prelude::*, path::Path, sync::Arc}; +use std::{fs::File, io::prelude::*, path::Path}; use structopt::StructOpt; -use rustc_hex::FromHex; +use rustc_hex::{FromHex, ToHex}; +use common_u::custom_errors::ReportManagerErr; +use crossbeam_utils::thread; +use web3::types::U256; pub fn create_signer(eid: sgx_enclave_id_t, with_private_key: bool, private_key: &[u8]) -> Box { if with_private_key { @@ -33,95 +34,93 @@ pub fn create_signer(eid: sgx_enclave_id_t, with_private_key: bool, private_key: } } +fn get_signing_address(eid: sgx_enclave_id_t) -> Result { + Ok(equote::get_register_signing_address(eid).or(Err(ReportManagerErr::GetRegisterAddrErr))?.to_hex()) +} + +fn get_ethereum_address(eid: sgx_enclave_id_t, config: KMConfig) -> Result { + if config.with_private_key { + return Ok(config.account_address.clone()); + } + Ok(equote::get_ethereum_address(eid).or(Err(ReportManagerErr::GetEtherAddrErr))?.to_hex()) +} + #[logfn(INFO)] pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { let opt = cli::options::Opt::from_args(); - let mut principal_config = PrincipalConfig::load_config(opt.principal_config.as_str())?; - let report_manager = ReportManager::new(principal_config.clone(), eid); - let signing_address = report_manager.get_signing_address()?; - let ethereum_address = report_manager.get_ethereum_address()?; - let mut path = storage_dir(ENCLAVE_DIR)?; + let config = KMConfig::load_config(opt.principal_config.as_str())?; - let private_key = principal_config.private_key.from_hex()?; - - let ethereum_signer = create_signer(eid, principal_config.with_private_key, &private_key); + let mut path = storage_dir(ENCLAVE_DIR)?; + let ethereum_address = get_ethereum_address(eid, config.clone())?; - if opt.info { - cli::options::print_info(&signing_address, ðereum_address); - } else if opt.sign_address { + if opt.sign_address { path.push("principal-sign-addr.txt"); let mut file = File::create(&path)?; + + let signing_address = get_signing_address(eid)?; let prefixed_signing_address = format!("0x{}", signing_address); + file.write_all(prefixed_signing_address.as_bytes())?; println!("Wrote signing address: {:?} in file: {:?}", prefixed_signing_address, path); path.pop(); path.push("ethereum-account-addr.txt"); let mut file = File::create(&path)?; + let prefixed_ethereum_address = format!("0x{}", ethereum_address); + file.write_all(prefixed_ethereum_address.as_bytes())?; println!("Wrote ethereum address: {:?} in file: {:?}", prefixed_ethereum_address, path); - } else if opt.deploy { - unimplemented!("Self-deploy mode not yet implemented. Fix issues with linked libraries in the Enigma contract."); } else { - println!("[Mode:] run node NO DEPLOY."); - // step1 : build the config of the principal node - // optional : set time limit for the principal node - let contract_address = opt.contract_address.unwrap_or_else(|| principal_config.enigma_contract_address.clone()); - let enigma_contract = Arc::new(EnigmaContract::from_deployed( + let private_key = config.private_key.from_hex()?; + let ethereum_signer = create_signer(eid, config.with_private_key, &private_key); + + let contract_address = opt.contract_address.unwrap_or_else(|| config.enigma_contract_address.clone()); + let enigma_contract = EnigmaContract::from_deployed( &contract_address, - Path::new(&principal_config.enigma_contract_path), + Path::new(&config.enigma_contract_path), Some(ðereum_address), - principal_config.chain_id, - &principal_config.url, + config.chain_id, + &config.url, ethereum_signer, - )?); - - principal_config.max_epochs = if opt.time_to_live > 0 { Some(opt.time_to_live) } else { None }; + )?; let gas_limit = 5_999_999; - let principal: PrincipalManager = PrincipalManager::new( enigma_contract, report_manager); - println!("Connected to the Enigma contract: {:?} with account: {:?}", &contract_address, principal.get_account_address()); - -// // step 2 optional - run miner to simulate blocks -// let join_handle = if opt.mine > 0 { -// Some(principal_manager::run_miner(principal.get_account_address(), principal.get_web3(), opt.mine as u64)) -// } else { -// None -// }; - - let eid_safe = Arc::new(eid); - //TODO: Ugly, refactor to instantiate only once, consider passing to the run method - let epoch_provider = EpochProvider::new(eid_safe, path.clone(), principal.contract.clone())?; - if opt.reset_epoch_state { - epoch_provider.epoch_state_manager.reset()?; - } - // step3 : run the principal manager - if opt.register { - match principal.verify_identity_or_register(gas_limit)? { - Some(tx) => println!("Registered Principal with tx: {:?}", tx), - None => println!("Principal already registered"), - }; - } else if opt.set_worker_params { - let block_number = principal.get_block_number()?; - let tx = epoch_provider.set_worker_params(block_number, gas_limit, principal_config.confirmations as usize)?; - println!("The setWorkersParams tx: {:?}", tx); - } else if opt.confirm_worker_params { - let block_number = principal.get_block_number()?; - let tx = epoch_provider.confirm_worker_params(block_number, gas_limit, principal_config.confirmations as usize)?; - println!("The setWorkersParams tx: {:?}", tx); - } else if opt.get_state_keys.is_some() { - let request: StateKeyRequest = serde_json::from_str(&opt.get_state_keys.unwrap())?; - let response = PrincipalHttpServer::get_state_keys(&epoch_provider, request)?; - println!("The getStateKeys response: {}", serde_json::to_string(&response)?); - } else { - principal.run(path, false, gas_limit).unwrap(); - } -// if let Some(t) = join_handle { -// t.join().unwrap(); -// } + let controller = KMController::new(eid, path.clone(), enigma_contract, config)?; + println!("Connected to the Enigma contract: {:?} with account: {:?}", &contract_address, controller.contract.get_km_account()); + + run(opt.reset_epoch_state, gas_limit, controller).unwrap(); + } + Ok(()) +} + +#[logfn(INFO)] +fn run>(reset_epoch: bool, gas_limit: G, controller: KMController) -> Result<(), Error> { + let gas_limit: U256 = gas_limit.into(); + controller.verify_identity_or_register(gas_limit)?; + if reset_epoch { + controller.epoch_verifier.reset()?; } + + // Start the JSON-RPC Server + let port = controller.config.http_port; + let controller1 = Arc::new(controller); + let controller2 = Arc::clone(&controller1); + thread::scope(|s| { + s.spawn(|_| { + let server = PrincipalHttpServer::new(controller1, port); + server.start(); + }); + s.spawn(|_|{ + controller2.watch_blocks( + controller2.config.epoch_size, + controller2.config.polling_interval, + gas_limit, + controller2.config.confirmations as usize, + ); + }); + }); Ok(()) } diff --git a/enigma-principal/app/src/cli/options.rs b/enigma-principal/app/src/cli/options.rs index 47bc496e..d5db632c 100644 --- a/enigma-principal/app/src/cli/options.rs +++ b/enigma-principal/app/src/cli/options.rs @@ -4,30 +4,11 @@ use url::Url; #[derive(StructOpt, Debug)] #[structopt(name = "basic")] pub struct Opt { - /// Run info mode and shutdown. (Not actually running the node) - #[structopt(short = "i", long = "info")] - pub info: bool, /// Output the signing address only #[structopt(short = "w", long = "write-sign-address")] pub sign_address: bool, - /// Run the Register procedure and shutdown - #[structopt(short = "r", long = "register")] - pub register: bool, - - /// Run the Set Worker Params procedure and shutdown - #[structopt(short = "p", long = "set-worker-params")] - pub set_worker_params: bool, - - /// Confirm the Worker Params in the local state and shutdown - #[structopt(short = "f", long = "confirm-worker-params")] - pub confirm_worker_params: bool, - - /// Get state keys and shutdown - #[structopt(short = "k", long = "get-state-keys")] - pub get_state_keys: Option, - /// Optional: The Enigma contract address, use the config if not provided #[structopt(short = "c", long = "contract-address")] pub contract_address: Option, @@ -44,14 +25,6 @@ pub struct Opt { #[structopt(short = "n", long = "network", default_value = "http://.c")] pub network: Url, - /// Optional: simulate blocks mining --mine <> - #[structopt(short = "m", long = "mine", default_value = "0")] - pub mine: usize, - - /// Optional: how many loops to perform (seconds) for the principal in time (TTL) - #[structopt(short = "x", long = "time-to-live", default_value = "0")] - pub time_to_live: usize, - /// Optional: if --deploy then change default to custom config file #[structopt(short = "y", long = "deploy-config", default_value = "../app/tests/principal_node/config/deploy_config.json")] pub deploy_config: String, @@ -64,64 +37,3 @@ pub struct Opt { #[structopt(short = "l", long = "log-level", default_value = "info")] pub log_level: String, } - -// fn all_colours() { -// black!("black "); -// red!("red "); -// green!("green "); -// yellow!("yellow "); -// blue!("blue "); -// magenta!("magenta "); -// cyan!("cyan "); -// white!("white "); -// dark_black!("dark_black "); -// dark_red!("dark_red "); -// dark_green!("dark_green "); -// dark_yellow!("dark_yellow "); -// dark_blue!("dark_blue "); -// dark_magenta!("dark_magenta "); -// dark_cyan!("dark_cyan "); -// dark_white!("dark_white "); -// prnt!("default colour\n\n"); -//} - -pub fn print_logo() { - yellow!("<>------------------------------------------<>\n"); - magenta!( - " -\t╔═╗ ┌┐┌ ┬ ┌─┐ ┌┬┐ ┌─┐ -\t║╣ │││ │ │ ┬ │││ ├─┤ -\t╚═╝ ┘└┘ ┴ └─┘ ┴ ┴ ┴ ┴ \n -\t╔═╗ ┬─┐ ┬ ┌┐┌ ┌─┐ ┬ ┌─┐ ┌─┐ ┬ -\t╠═╝ ├┬┘ │ │││ │ │ ├─┘ ├─┤ │ -\t╩ ┴└─ ┴ ┘└┘ └─┘ ┴ ┴ ┴ ┴ ┴─┘\n -\t╔╗╔ ┌─┐ ┌┬┐ ┌─┐ -\t║║║ │ │ ││ ├┤ -\t╝╚╝ └─┘ ─┴┘ └─┘\n" - ); - yellow!("<>------------------------------------------<>\n"); -} -pub fn print_info(signing_address: &str, ethereum_address: &str) { - print_logo(); - yellow!("<>------------------------------------------<>\n"); - green!("--info => Print the signing address and help.\n"); - green!("--verbose => Verbosity of the log output (up to 5 -vvvvv).\n"); - green!("--debug-stdout => Print the debugging directly to stdout.\n"); - green!("--write-sign-address => Write the signing address to ~/.enigma/principal-sign-addr.txt.\n"); - green!("--register => Run the Register procedure and shutdown.\n"); - green!("--set-worker-params => Run the Set Worker Params procedure and shutdown.\n"); - green!("--confirm-worker-params => Confirm the Worker Params in the local state and shutdown.\n"); - green!("--get-state-keys => Get the state keys from the message and shutdown.\n"); - green!("--contract-address => The Enigma contract address, use the config if not provided.\n"); - green!("--reset-epoch-state => Optional: Reset the Epoch state in storage.\n"); - green!("--deploy => Optional, deploy the Enigma contract.\n"); - green!("--network => Currently ignored, use a custom network (use config file instead).\n"); - green!("--mine => Optional, simulate new blocks, speed = seconds interval.\n"); - green!("--time-to-live