From 631ca84e09bfda26d23bf594f31bb04e34f99181 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 30 Jun 2021 12:42:58 +0200 Subject: [PATCH 1/3] introduce custom enclave error. --- enclave/Cargo.lock | 1 + enclave/Cargo.toml | 6 +++ enclave/src/error.rs | 29 ++++++++++++++ enclave/src/lib.rs | 94 ++++++++++++++++++++------------------------ 4 files changed, 79 insertions(+), 51 deletions(-) create mode 100644 enclave/src/error.rs diff --git a/enclave/Cargo.lock b/enclave/Cargo.lock index b195497697..a9725bf766 100644 --- a/enclave/Cargo.lock +++ b/enclave/Cargo.lock @@ -2639,6 +2639,7 @@ dependencies = [ "cid", "derive_more", "env_logger", + "frame-support", "httparse", "ipfs-unixfs", "itertools", diff --git a/enclave/Cargo.toml b/enclave/Cargo.toml index 12fa9cc30c..6ba83233e6 100644 --- a/enclave/Cargo.toml +++ b/enclave/Cargo.toml @@ -94,6 +94,12 @@ features = ["disable_oom", "disable_panic_handler", "disable_allocator", "sgx"] git = "https://github.com/apache/teaclave-sgx-sdk.git" rev = "v1.1.3" +[dependencies.frame-support] +git = "https://github.com/paritytech/substrate.git" +branch = "master" +version = "3.0.0" +default-features = false + [dependencies.sp-core] git = "https://github.com/paritytech/substrate.git" branch = "master" diff --git a/enclave/src/error.rs b/enclave/src/error.rs new file mode 100644 index 0000000000..ef34ba4fa0 --- /dev/null +++ b/enclave/src/error.rs @@ -0,0 +1,29 @@ +use derive_more::{Display, From}; +use sgx_types::sgx_status_t; +use crate::rpc; + +#[derive(Debug, Display, From)] +pub enum Error { + Rpc(rpc::error::Error), + Codec(codec::Error), + Sgx(sgx_status_t) +} + +impl From for sgx_status_t { + /// return sgx_status for top level enclave functions + fn from(error: Error) -> sgx_status_t { + match error { + Error::Sgx(status) => status, + _=> { + log::warn!("Tried extracting sgx_status for non-sgx error: {:?}", error); + sgx_status_t::SGX_ERROR_UNEXPECTED + } + } + } +} + +impl From for Result { + fn from(error: Error) -> Result { + Err(error) + } +} \ No newline at end of file diff --git a/enclave/src/lib.rs b/enclave/src/lib.rs index 9f058238e9..d3a6f8ae02 100644 --- a/enclave/src/lib.rs +++ b/enclave/src/lib.rs @@ -32,7 +32,8 @@ extern crate sgx_tstd as std; use base58::ToBase58; -use sgx_types::{sgx_epid_group_id_t, sgx_status_t, sgx_target_info_t, SgxResult}; +use sgx_types::{sgx_epid_group_id_t, sgx_status_t, sgx_target_info_t}; + use substrate_api_client::compose_extrinsic_offline; use substratee_node_primitives::{CallWorkerFn, ShieldFundsFn}; @@ -61,6 +62,7 @@ use chain_relay::{ storage_proof::{StorageProof, StorageProofChecker}, Block, Header, LightValidation, }; +use frame_support::ensure; use sp_runtime::OpaqueExtrinsic; use sp_runtime::{generic::SignedBlock, traits::Header as HeaderT}; use substrate_api_client::extrinsic::xt_primitives::UncheckedExtrinsicV4; @@ -91,10 +93,12 @@ pub mod rpc; pub mod tests; pub mod tls_ra; pub mod top_pool; +pub mod error; use substratee_settings::node::{BLOCK_CONFIRMED, CALL_CONFIRMED, RUNTIME_SPEC_VERSION, RUNTIME_TRANSACTION_VERSION, SUBSTRATEE_REGISTRY_MODULE, CALL_WORKER, SHIELD_FUNDS, REGISTER_ENCLAVE}; use substratee_settings::enclave::{CALL_TIMEOUT, GETTER_TIMEOUT}; use codec::alloc::string::String; +use crate::error::Error; pub const CERTEXPIRYDAYS: i64 = 90i64; @@ -107,6 +111,8 @@ pub enum Timeout { pub type Hash = sp_core::H256; type BPool = BasicPool, Block>; +pub type EnclaveResult = Result; + #[no_mangle] pub unsafe extern "C" fn init() -> sgx_status_t { // initialize the logging environment in the enclave @@ -232,7 +238,7 @@ fn create_extrinsics( validator: LightValidation, calls_buffer: Vec, mut nonce: u32, -) -> SgxResult>> { +) -> EnclaveResult>> { // get information for composing the extrinsic let signer = ed25519::unseal_pair()?; debug!("Restored ECC pubkey: {:?}", signer.public()); @@ -313,12 +319,12 @@ pub unsafe extern "C" fn get_state( if !requests.is_empty() { let responses: Vec>> = match worker_request(requests) { Ok(resp) => resp, - Err(e) => return e, + Err(e) => return e.into(), }; let update_map = match verify_worker_responses(responses, latest_header) { Ok(map) => map, - Err(e) => return e, + Err(e) => return e.into(), }; Stf::update_storage(&mut state, &update_map); @@ -486,7 +492,7 @@ pub unsafe extern "C" fn produce_blocks( fn send_block_and_confirmation( confirmations: Vec>, signed_blocks: Vec, -) -> SgxResult<()> { +) -> EnclaveResult<()> { let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; let res = unsafe { @@ -499,13 +505,8 @@ fn send_block_and_confirmation( ) }; - if rt != sgx_status_t::SGX_SUCCESS { - return Err(rt); - } - - if res != sgx_status_t::SGX_SUCCESS { - return Err(res); - } + ensure!(rt == sgx_status_t::SGX_SUCCESS, rt); + ensure!(res == sgx_status_t::SGX_SUCCESS, res); Ok(()) } @@ -542,7 +543,7 @@ fn get_stf_state( fn execute_top_pool_calls( latest_onchain_header: Header, -) -> SgxResult<(Vec, Vec)> { +) -> EnclaveResult<(Vec, Vec)> { debug!("Executing pending pool operations"); let mut calls = Vec::::new(); let mut blocks = Vec::::new(); @@ -552,7 +553,7 @@ fn execute_top_pool_calls( Some(mutex) => mutex, None => { error!("Could not get mutex to pool"); - return Err(sgx_status_t::SGX_ERROR_UNEXPECTED); + return Error::Sgx(sgx_status_t::SGX_ERROR_UNEXPECTED).into(); } }; let pool_guard: SgxMutexGuard = pool_mutex.lock().unwrap(); @@ -570,10 +571,8 @@ fn execute_top_pool_calls( let mut is_done = false; for shard in shards.clone().into_iter() { // retrieve trusted operations from pool - let trusted_getters = match author.get_pending_tops_separated(shard) { - Ok((_, getters)) => getters, - Err(_) => return Err(sgx_status_t::SGX_ERROR_UNEXPECTED), - }; + let trusted_getters = author + .get_pending_tops_separated(shard)?.1; for trusted_getter_signed in trusted_getters.into_iter() { // get state let value_opt = get_stf_state(trusted_getter_signed.clone(), shard); @@ -626,10 +625,8 @@ fn execute_top_pool_calls( let prev_state_hash = state::hash_of(state.state.clone())?; // retrieve trusted operations from pool - let trusted_calls = match author.get_pending_tops_separated(shard) { - Ok((calls, _)) => calls, - Err(_) => return Err(sgx_status_t::SGX_ERROR_UNEXPECTED), - }; + let trusted_calls = author.get_pending_tops_separated(shard)?.0; + debug!("Got following trusted calls from pool: {:?}", trusted_calls); // call execution for trusted_call_signed in trusted_calls.into_iter() { @@ -708,21 +705,20 @@ pub fn compose_block_and_confirmation( shard: ShardIdentifier, state_hash_apriori: H256, state: &mut StfState, -) -> SgxResult<(OpaqueCall, SignedSidechainBlock)> { +) -> EnclaveResult<(OpaqueCall, SignedSidechainBlock)> { let signer_pair = ed25519::unseal_pair()?; let layer_one_head = latest_onchain_header.hash(); - let block_number = match Stf::get_sidechain_block_number(state) { - Some(number) => number + 1, - None => return Err(sgx_status_t::SGX_ERROR_UNEXPECTED), - }; + let block_number = Stf::get_sidechain_block_number(state) + .map(|n| n + 1) + .ok_or(Error::Sgx(sgx_status_t::SGX_ERROR_UNEXPECTED))?; + Stf::update_sidechain_block_number(state, block_number); let block_number: u64 = block_number; //FIXME! Should be either u64 or u32! Not both.. - let parent_hash = match Stf::get_last_block_hash(state) { - Some(hash) => hash, - None => return Err(sgx_status_t::SGX_ERROR_UNEXPECTED), - }; + let parent_hash = Stf::get_last_block_hash(state) + .ok_or(Error::Sgx(sgx_status_t::SGX_ERROR_UNEXPECTED))?; + // hash previous of state let state_hash_aposteriori = state::hash_of(state.state.clone())?; let state_update = state.state_diff.clone().encode(); @@ -754,7 +750,7 @@ pub fn compose_block_and_confirmation( Ok((opaque_call, signed_block)) } -pub fn update_states(header: Header) -> SgxResult<()> { +pub fn update_states(header: Header) -> EnclaveResult<()> { debug!("Update STF storage upon block import!"); let requests: Vec = Stf::storage_hashes_to_update_on_block() .into_iter() @@ -809,7 +805,7 @@ pub fn update_states(header: Header) -> SgxResult<()> { /// Scans blocks for extrinsics that ask the enclave to execute some actions. /// Executes indirect invocation calls, aswell as shielding and unshielding calls /// Returns all unshielding call confirmations as opaque calls -pub fn scan_block_for_relevant_xt(block: &Block) -> SgxResult> { +pub fn scan_block_for_relevant_xt(block: &Block) -> EnclaveResult> { debug!("Scanning block {} for relevant xt", block.header.number()); let mut opaque_calls = Vec::::new(); for xt_opaque in block.extrinsics.iter() { @@ -860,7 +856,7 @@ pub fn scan_block_for_relevant_xt(block: &Block) -> SgxResult> { fn handle_shield_funds_xt( calls: &mut Vec, xt: UncheckedExtrinsicV4, -) -> SgxResult<()> { +) -> EnclaveResult<()> { let (call, account_encrypted, amount, shard) = xt.function.clone(); info!("Found ShieldFunds extrinsic in block: \nCall: {:?} \nAccount Encrypted {:?} \nAmount: {} \nShard: {}", call, account_encrypted, amount, shard.encode().to_base58(), @@ -909,7 +905,7 @@ fn handle_shield_funds_xt( fn decrypt_unchecked_extrinsic( xt: UncheckedExtrinsicV4, -) -> SgxResult<(TrustedCallSigned, ShardIdentifier)> { +) -> EnclaveResult<(TrustedCallSigned, ShardIdentifier)> { let (call, request) = xt.function; let (shard, cyphertext) = (request.shard, request.cyphertext); debug!("Found CallWorker extrinsic in block: \nCall: {:?} \nRequest: \nshard: {}\ncyphertext: {:?}", @@ -921,10 +917,9 @@ fn decrypt_unchecked_extrinsic( debug!("decrypt the call"); let rsa_keypair = rsa3072::unseal_pair()?; let request_vec = rsa3072::decrypt(&cyphertext, &rsa_keypair)?; - match TrustedCallSigned::decode(&mut request_vec.as_slice()) { - Ok(call) => Ok((call, shard)), - Err(_) => Err(sgx_status_t::SGX_ERROR_UNEXPECTED), - } + + Ok(TrustedCallSigned::decode(&mut request_vec.as_slice()) + .map(|call| (call, shard))?) } fn handle_trusted_worker_call( @@ -934,7 +929,7 @@ fn handle_trusted_worker_call( header: Header, shard: ShardIdentifier, author_pointer: Option>>, -) -> SgxResult> { +) -> EnclaveResult> { debug!("query mrenclave of self"); let mrenclave = attestation::get_mrenclave_of_self()?; debug!("MRENCLAVE of self is {}", mrenclave.m.to_base58()); @@ -1019,7 +1014,7 @@ fn handle_trusted_worker_call( fn verify_worker_responses( responses: Vec>>, header: Header, -) -> SgxResult, Option>>> { +) -> EnclaveResult, Option>>> { let mut update_map = HashMap::new(); for response in responses.iter() { match response { @@ -1038,7 +1033,8 @@ fn verify_worker_responses( // Todo: Why do they do it like that, we could supply the proof only and get the value from the proof directly?? if &actual != value { error!("Wrong storage value supplied"); - return Err(sgx_status_t::SGX_ERROR_UNEXPECTED); + // todo: return another error now that we introduced our custom error + return Error::Sgx(sgx_status_t::SGX_ERROR_UNEXPECTED).into(); } update_map.insert(key.clone(), value.clone()); } @@ -1098,7 +1094,7 @@ pub enum WorkerResponse { fn worker_request( req: Vec, -) -> SgxResult>> { +) -> EnclaveResult>> { let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; let mut resp: Vec = vec![0; 4196 * 4]; @@ -1112,12 +1108,8 @@ fn worker_request( ) }; - if rt != sgx_status_t::SGX_SUCCESS { - return Err(rt); - } + ensure!(rt == sgx_status_t::SGX_SUCCESS, rt); + ensure!(res == sgx_status_t::SGX_SUCCESS, res); - if res != sgx_status_t::SGX_SUCCESS { - return Err(res); - } - Ok(Decode::decode(&mut resp.as_slice()).unwrap()) -} + Ok(Decode::decode(&mut resp.as_slice())?) +} \ No newline at end of file From 2d95803a7e63bf24dbf6c932c880f369a35a589d Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 30 Jun 2021 12:50:17 +0200 Subject: [PATCH 2/3] minor fmt --- enclave/src/error.rs | 2 +- enclave/src/lib.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/enclave/src/error.rs b/enclave/src/error.rs index ef34ba4fa0..d508c2e330 100644 --- a/enclave/src/error.rs +++ b/enclave/src/error.rs @@ -15,7 +15,7 @@ impl From for sgx_status_t { match error { Error::Sgx(status) => status, _=> { - log::warn!("Tried extracting sgx_status for non-sgx error: {:?}", error); + log::warn!("Tried extracting sgx_status from non-sgx error: {:?}", error); sgx_status_t::SGX_ERROR_UNEXPECTED } } diff --git a/enclave/src/lib.rs b/enclave/src/lib.rs index d3a6f8ae02..e54049364d 100644 --- a/enclave/src/lib.rs +++ b/enclave/src/lib.rs @@ -34,7 +34,6 @@ use base58::ToBase58; use sgx_types::{sgx_epid_group_id_t, sgx_status_t, sgx_target_info_t}; - use substrate_api_client::compose_extrinsic_offline; use substratee_node_primitives::{CallWorkerFn, ShieldFundsFn}; use substratee_worker_primitives::block::{ @@ -98,7 +97,6 @@ pub mod error; use substratee_settings::node::{BLOCK_CONFIRMED, CALL_CONFIRMED, RUNTIME_SPEC_VERSION, RUNTIME_TRANSACTION_VERSION, SUBSTRATEE_REGISTRY_MODULE, CALL_WORKER, SHIELD_FUNDS, REGISTER_ENCLAVE}; use substratee_settings::enclave::{CALL_TIMEOUT, GETTER_TIMEOUT}; use codec::alloc::string::String; -use crate::error::Error; pub const CERTEXPIRYDAYS: i64 = 90i64; @@ -111,7 +109,8 @@ pub enum Timeout { pub type Hash = sp_core::H256; type BPool = BasicPool, Block>; -pub type EnclaveResult = Result; +use crate::error::Error; +pub type EnclaveResult = Result; #[no_mangle] pub unsafe extern "C" fn init() -> sgx_status_t { From 146c46eddcfae75889950427e71474c9e7840502 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Mon, 5 Jul 2021 11:17:16 +0200 Subject: [PATCH 3/3] [enclave] define EnclaveResult in error.rs and rename it to plain result. --- enclave/src/error.rs | 8 ++++++-- enclave/src/lib.rs | 25 ++++++++++++------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/enclave/src/error.rs b/enclave/src/error.rs index d508c2e330..e88c21237d 100644 --- a/enclave/src/error.rs +++ b/enclave/src/error.rs @@ -2,6 +2,10 @@ use derive_more::{Display, From}; use sgx_types::sgx_status_t; use crate::rpc; +use std::result::Result as StdResult; + +pub type Result = StdResult; + #[derive(Debug, Display, From)] pub enum Error { Rpc(rpc::error::Error), @@ -22,8 +26,8 @@ impl From for sgx_status_t { } } -impl From for Result { - fn from(error: Error) -> Result { +impl From for StdResult { + fn from(error: Error) -> StdResult { Err(error) } } \ No newline at end of file diff --git a/enclave/src/lib.rs b/enclave/src/lib.rs index e54049364d..943f397d1e 100644 --- a/enclave/src/lib.rs +++ b/enclave/src/lib.rs @@ -109,8 +109,7 @@ pub enum Timeout { pub type Hash = sp_core::H256; type BPool = BasicPool, Block>; -use crate::error::Error; -pub type EnclaveResult = Result; +use crate::error::{Error, Result}; #[no_mangle] pub unsafe extern "C" fn init() -> sgx_status_t { @@ -237,7 +236,7 @@ fn create_extrinsics( validator: LightValidation, calls_buffer: Vec, mut nonce: u32, -) -> EnclaveResult>> { +) -> Result>> { // get information for composing the extrinsic let signer = ed25519::unseal_pair()?; debug!("Restored ECC pubkey: {:?}", signer.public()); @@ -491,7 +490,7 @@ pub unsafe extern "C" fn produce_blocks( fn send_block_and_confirmation( confirmations: Vec>, signed_blocks: Vec, -) -> EnclaveResult<()> { +) -> Result<()> { let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; let res = unsafe { @@ -542,7 +541,7 @@ fn get_stf_state( fn execute_top_pool_calls( latest_onchain_header: Header, -) -> EnclaveResult<(Vec, Vec)> { +) -> Result<(Vec, Vec)> { debug!("Executing pending pool operations"); let mut calls = Vec::::new(); let mut blocks = Vec::::new(); @@ -704,7 +703,7 @@ pub fn compose_block_and_confirmation( shard: ShardIdentifier, state_hash_apriori: H256, state: &mut StfState, -) -> EnclaveResult<(OpaqueCall, SignedSidechainBlock)> { +) -> Result<(OpaqueCall, SignedSidechainBlock)> { let signer_pair = ed25519::unseal_pair()?; let layer_one_head = latest_onchain_header.hash(); @@ -749,7 +748,7 @@ pub fn compose_block_and_confirmation( Ok((opaque_call, signed_block)) } -pub fn update_states(header: Header) -> EnclaveResult<()> { +pub fn update_states(header: Header) -> Result<()> { debug!("Update STF storage upon block import!"); let requests: Vec = Stf::storage_hashes_to_update_on_block() .into_iter() @@ -804,7 +803,7 @@ pub fn update_states(header: Header) -> EnclaveResult<()> { /// Scans blocks for extrinsics that ask the enclave to execute some actions. /// Executes indirect invocation calls, aswell as shielding and unshielding calls /// Returns all unshielding call confirmations as opaque calls -pub fn scan_block_for_relevant_xt(block: &Block) -> EnclaveResult> { +pub fn scan_block_for_relevant_xt(block: &Block) -> Result> { debug!("Scanning block {} for relevant xt", block.header.number()); let mut opaque_calls = Vec::::new(); for xt_opaque in block.extrinsics.iter() { @@ -855,7 +854,7 @@ pub fn scan_block_for_relevant_xt(block: &Block) -> EnclaveResult, xt: UncheckedExtrinsicV4, -) -> EnclaveResult<()> { +) -> Result<()> { let (call, account_encrypted, amount, shard) = xt.function.clone(); info!("Found ShieldFunds extrinsic in block: \nCall: {:?} \nAccount Encrypted {:?} \nAmount: {} \nShard: {}", call, account_encrypted, amount, shard.encode().to_base58(), @@ -904,7 +903,7 @@ fn handle_shield_funds_xt( fn decrypt_unchecked_extrinsic( xt: UncheckedExtrinsicV4, -) -> EnclaveResult<(TrustedCallSigned, ShardIdentifier)> { +) -> Result<(TrustedCallSigned, ShardIdentifier)> { let (call, request) = xt.function; let (shard, cyphertext) = (request.shard, request.cyphertext); debug!("Found CallWorker extrinsic in block: \nCall: {:?} \nRequest: \nshard: {}\ncyphertext: {:?}", @@ -928,7 +927,7 @@ fn handle_trusted_worker_call( header: Header, shard: ShardIdentifier, author_pointer: Option>>, -) -> EnclaveResult> { +) -> Result> { debug!("query mrenclave of self"); let mrenclave = attestation::get_mrenclave_of_self()?; debug!("MRENCLAVE of self is {}", mrenclave.m.to_base58()); @@ -1013,7 +1012,7 @@ fn handle_trusted_worker_call( fn verify_worker_responses( responses: Vec>>, header: Header, -) -> EnclaveResult, Option>>> { +) -> Result, Option>>> { let mut update_map = HashMap::new(); for response in responses.iter() { match response { @@ -1093,7 +1092,7 @@ pub enum WorkerResponse { fn worker_request( req: Vec, -) -> EnclaveResult>> { +) -> Result>> { let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; let mut resp: Vec = vec![0; 4196 * 4];