diff --git a/enigma-principal/README.md b/enigma-principal/README.md index 16497d65..5d870847 100644 --- a/enigma-principal/README.md +++ b/enigma-principal/README.md @@ -1,6 +1,15 @@ # Enigma Key Management Node -The Key Management node is part of the Enigma node software stack. The Key Management component is responsible for emitting random numbers from within an enclave into the Enigma contract. Currently, it uses a centralized design in order to maintain simplicity while testing and developing Core, but it will eventually move to a decentralized design matching the rest of the network. +The Key Management node is part of the Enigma node software stack. +The Key Management component is responsible for emitting random numbers from within +an enclave into the Enigma contract, which defines the seed for each epoch. +In addition, it handles the state keys, which encrypt the state of each secret contract +stored on each of the nodes and supplies the acquired keys to the chosen worker/node in +the epoch (according to the seed that defines the epoch and a worker selection algorithm) +for each of the secret contracts, on demand through the jsonRPC server. +Currently, it uses a centralized design in order to maintain simplicity while +testing and developing Core, but it will eventually move to a decentralized design +matching the rest of the network. @@ -32,7 +41,7 @@ The encryption method relies on a DH key exchange between the Principal node and ```sh // Request -curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "id":1, "method":"get_state_keys", "params": {"data": "84a46461746181a75265717565737493dc0020cca7cc937b64ccb8cccacca5cc8f03721bccb6ccbacccf5c78cccb235fccebcce0cce70b1bcc84cccdcc99541461cca0cc8edc002016367accacccb67a4a017ccc8dcca8ccabcc95682ccccb390863780f7114ccddcca0cca0cce0ccc55644ccc7ccc4dc0020ccb1cce9cc9324505bccd32dcca0cce1ccf85dcccf5e19cca0cc9dccb0481ecc8a15ccf62c41cceb320304cca8cce927a269649c1363ccb3301c101f33cce1cc9a0524a67072656669789e456e69676d61204d657373616765a67075626b6579dc0040cce5ccbe28cc9dcc9a2eccbd08ccc0457a5f16ccdfcc9fccdc256c5d5f6c3514cccdcc95ccb47c11ccc4cccd3e31ccf0cce4ccefccc83ccc80cce8121c3939ccbb2561cc80ccec48ccbecca8ccc569ccd2cca3ccda6bcce415ccfa20cc9bcc98ccda", "workerSig": "43f19586b0a0ae626b9418fe8355888013be1c9b4263a4b3a27953de641991e936ed6c4076a2a383b3b001936bf0eb6e23c78fbec1ee36f19c6a9d24d75e9e081c"}}' +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/ // Result { @@ -44,6 +53,22 @@ curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "id":1, "method" } } ``` + +## getHealthCheck + +Requests a health check to be done on the Key management node. needed by the kubernetes cluster to check that all components are alive and +returning reasonable data. +the method, checks if the connection with the enclave and the enigma contract on ethereum are alive and return the same data. + +**Returns** + +bool: True, if the registration key is the same in both components. +False, if either we weren't able to connect to one of the components or if the keys were different. + +An example for a request will look like this: +```sh +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 +``` ## To see all of the options available once compiled cd into /bin and type ``` diff --git a/enigma-principal/app/README.md b/enigma-principal/app/README.md new file mode 100644 index 00000000..25e6d100 --- /dev/null +++ b/enigma-principal/app/README.md @@ -0,0 +1,41 @@ +## App Structure + +this folder consists of all the untrusted KM functionality. + +it's divided into 5 folders: + +##cli + +consists of the scripts called by `main.rs` in the rebooting of the KM and the handling of the +cli options. + + +##boot_network + + Consists of the functionality the boots up the KM. + The `principal_manager` which creates the 2 threads which handle the functionality of the KM, which consist of + the watching blocks thread that is located in `principal_utils.rs` file which counts the number of blocks until the end of the epoch and is in charge of + evaluating a new random seed which will define the new epoch and the second thread which handles the json rpc server + which is located in the `keys_provider_http.rs` file. + `deploy_scripts` consists of other functionality which is used to run tests while running idle. + + ## common_u + + consists of the joint methods to all of the untrusted functionality. In our case it consists only of the custom errors. + + ## epoch_u + + Consists of all scripts which are in charge of handling the epoch data. + There are 3 structs which are provided: + `epoch_state`- holds all data which is needed on the untrusted side that defines an epoch which was created in the enclave. + `epoch_state_manager`- holds a `cap` amount of epochs which can be called upon by workers (cap is defined when booting the network- in the configurations). + `epoch_provider`- holds all what's needed in order to create a new epoch (the eid of the enclave and an enigma-contract object which can communicate with the contract on ethereum) and the epoch_state manager. + + ## esgx + + all the ecall functionality that calls the trusted side. + `epoch_keeper_u.rs` consists of setting the worker params which creates the new epoch - evaluates a new seed, and stores all active workers with it, + to have all necessary data for running the worker selection algorithm and confirm the keys are given to the right worker. + `equote` - similar to the enigma-core, all the functionality that registers a worker and evaluates a key pair for the encalve. + `key_keeper_u.rs` consists of the functionality on the untrusted side which provides the worker with the state keys of the contracts that he is in charge of in the current (or in inside the cap) + epoch. \ No newline at end of file diff --git a/enigma-principal/app/src/boot_network/principal_manager.rs b/enigma-principal/app/src/boot_network/principal_manager.rs index 7f0dea11..726fe37f 100644 --- a/enigma-principal/app/src/boot_network/principal_manager.rs +++ b/enigma-principal/app/src/boot_network/principal_manager.rs @@ -309,6 +309,7 @@ impl Sampler for PrincipalManager { #[logfn(INFO)] fn run>(&self, path: PathBuf, reset_epoch: bool, gas_limit: G) -> Result<(), Error> { let gas_limit: U256 = gas_limit.into(); + // make sure the KM was registered self.verify_identity_or_register(gas_limit)?; // get enigma contract // Start the WorkerParameterized Web3 log filter @@ -322,11 +323,12 @@ impl Sampler for PrincipalManager { let port = self.config.http_port; let server_ep = Arc::clone(&epoch_provider); thread::spawn(move || { + // brings up the JSON rpc server in a separate thread let server = PrincipalHttpServer::new(server_ep, port); server.start(); }); - // watch blocks + // watch blocks in order to decide when to create a new epoch. let polling_interval = self.config.polling_interval; let epoch_size = self.config.epoch_size; self.contract.watch_blocks( diff --git a/enigma-principal/app/src/cli/app.rs b/enigma-principal/app/src/cli/app.rs index bd2fa0d8..8edefb0d 100644 --- a/enigma-principal/app/src/cli/app.rs +++ b/enigma-principal/app/src/cli/app.rs @@ -33,6 +33,7 @@ pub fn create_signer(eid: sgx_enclave_id_t, with_private_key: bool, private_key: } } +/// the starting point of the KM. called by main and is in charge of all functionality called by the cli app. #[logfn(INFO)] pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { let opt = cli::options::Opt::from_args(); @@ -49,6 +50,7 @@ pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { if opt.info { cli::options::print_info(&signing_address, ðereum_address); } else if opt.sign_address { + // store the KM addresses and close the KM. needed for the integration tests. path.push("principal-sign-addr.txt"); let mut file = File::create(&path)?; let prefixed_signing_address = format!("0x{}", signing_address); @@ -117,6 +119,7 @@ pub fn start(eid: sgx_enclave_id_t) -> Result<(), Error> { let response = PrincipalHttpServer::get_state_keys(&epoch_provider, request)?; println!("The getStateKeys response: {}", serde_json::to_string(&response)?); } else { + // the actual functionality of the KM node principal.run(path, false, gas_limit).unwrap(); } if let Some(t) = join_handle { diff --git a/enigma-principal/enclave/src/epoch_keeper_t/epoch_t.rs b/enigma-principal/enclave/src/epoch_keeper_t/epoch_t.rs index fecbca48..d3ae0a25 100644 --- a/enigma-principal/enclave/src/epoch_keeper_t/epoch_t.rs +++ b/enigma-principal/enclave/src/epoch_keeper_t/epoch_t.rs @@ -28,6 +28,8 @@ impl Epoch { .ok_or_else(|| SystemError(EnclaveSystemError::WorkerAuthError { err: "Worker selection returns nothing.".to_string() })) } + /// creates the encoding agreed upon and which is aligned on both ends in order to encrypt/decrypt + /// the data while making sure it cannot be compromised in the process. pub fn encode_for_hashing(&self) -> Bytes { let mut encoding: Vec = Vec::new(); diff --git a/enigma-principal/enclave/src/epoch_keeper_t/mod.rs b/enigma-principal/enclave/src/epoch_keeper_t/mod.rs index dde595c6..88eaf543 100644 --- a/enigma-principal/enclave/src/epoch_keeper_t/mod.rs +++ b/enigma-principal/enclave/src/epoch_keeper_t/mod.rs @@ -93,7 +93,7 @@ fn store_epoch(epoch: Epoch) -> Result<(), EnclaveError> { let mut data = H256::from_uint(&nonce).0.to_vec(); data.extend(hash.to_vec()); let mut marker_doc: SealedDocumentStorage = SealedDocumentStorage { - version: 0x1234, // TODO: what's this? + version: 0x1234, // TODO: remove. not needed. data: [0; 64], }; // Length of the slice guaranteed to be 64 @@ -150,9 +150,11 @@ pub(crate) fn ecall_set_worker_params_internal(worker_params_rlp: &[u8], seed_in }; *nonce_out = EpochNonce::from(nonce); rsgx_read_rand(&mut rand_out[..])?; + // create a random seed let seed = U256::from(rand_out.as_ref()); let epoch = Epoch { nonce, seed, worker_params }; debug_println!("Creating new epoch with nonce {:?} and seed: {:?}", nonce, seed); + store_epoch(epoch.clone())?; epoch } diff --git a/enigma-principal/enclave/src/keys_keeper_t/mod.rs b/enigma-principal/enclave/src/keys_keeper_t/mod.rs index 09c1e973..2b090bc5 100644 --- a/enigma-principal/enclave/src/keys_keeper_t/mod.rs +++ b/enigma-principal/enclave/src/keys_keeper_t/mod.rs @@ -104,6 +104,7 @@ fn new_state_keys(keys_map: &mut HashMap, Ok(results) } +/// builds the key response in the way agreed upon in the ipc documents on the p2p repository fn build_get_state_keys_response(sc_addrs: Vec) -> Result, EnclaveError> { let mut response_data: Vec<(ContractAddress, StateKey)> = Vec::new(); if sc_addrs.is_empty() {