diff --git a/Cargo.lock b/Cargo.lock index 9bd310699b..fbcda65eba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3692,6 +3692,7 @@ dependencies = [ name = "itp-stf-executor" version = "0.9.0" dependencies = [ + "hex", "ita-stf", "itc-parentchain-test", "itp-node-api", diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000000..8d579d96b7 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,72 @@ +# sidechain startup internal view +```mermaid +sequenceDiagram + participant integritee_network + participant service + participant slotworker + participant parentsync + participant enclave + participant enclave_rpc + participant provisioningserver + participant isinitializedserver + participant metrics + service ->> enclave: EnclaveBase.get_mrenclave + service ->> provisioningserver: spawn (`--mu-ra-port` | 3443) + activate provisioningserver + service ->> enclave: get_ecc_signing_pubkey + service ->> isinitializedserver: spawn (`--untrusted-http-port | 4545) + activate isinitializedserver + service ->> metrics: spawn (`--metrics-port`| 8787) + activate metrics + service ->> enclave_rpc: spawn (`--trusted-worker-port`| 2000) + activate enclave_rpc + + service ->> enclave: generate_dcap_ra_extrinsic + service ->> integritee_network: send register_sgx_enclave extrinsic + service ->> integritee_network: get ShardStatus + service ->> isinitializedserver: registered_on_parentchain +# schedule teeracle re-registration and updates + loop while blocks to sync + service ->> integritee_network: get_block + service ->> enclave: sync_parentchain(blocks, events, proofs) + end + service ->> enclave: init_enclave_sidechain_components + service ->> slotworker: spawn + loop forever + slotworker ->> enclave: execute_trusted_calls + activate enclave + enclave ->> enclave: propose_sidechain_block + enclave ->> integritee_network: send_extrinsics + deactivate enclave + end + service ->> parentsync: spawn + loop forever + parentsync ->> integritee_network: subscribe new headers + parentsync ->> enclave: sync_parentchain + end + service ->> service: poll worker_for_shard + service ->> isinitializedserver: worker_for_shard_registered + + deactivate enclave_rpc + deactivate metrics + deactivate isinitializedserver + deactivate provisioningserver +``` + +# sidechain lifetime external view + +```mermaid +sequenceDiagram + participant integritee_network + participant validateer_1 + participant validateer_2 + actor alice + + validateer_1 ->> integritee_network: register_sgx_enclave() + + validateer_2 ->> integritee_network: register_sgx_enclave() + + validateer_2 ->> validateer_1: sidechain_fetchBlocksFromPeer() + + validateer_1 ->> validateer_2: sidechain_importBlock() +``` diff --git a/app-libs/stf/src/trusted_call.rs b/app-libs/stf/src/trusted_call.rs index c81d21eadc..4f595ab3fe 100644 --- a/app-libs/stf/src/trusted_call.rs +++ b/app-libs/stf/src/trusted_call.rs @@ -22,26 +22,29 @@ use sp_core::{H160, H256, U256}; use std::vec::Vec; use crate::{helpers::ensure_enclave_signer_account, StfError, TrustedOperation}; -use codec::{Decode, Encode}; +use codec::{Compact, Decode, Encode}; use frame_support::{ensure, traits::UnfilteredDispatchable}; +#[cfg(feature = "evm")] +use ita_sgx_runtime::{AddressMapping, HashedAddressMapping}; pub use ita_sgx_runtime::{Balance, Index}; use ita_sgx_runtime::{Runtime, System}; use itp_node_api::metadata::{provider::AccessNodeMetadata, NodeMetadataTrait}; -use itp_node_api_metadata::pallet_enclave_bridge::EnclaveBridgeCallIndexes; -use itp_stf_interface::ExecuteCall; +use itp_node_api_metadata::{ + pallet_balances::BalancesCallIndexes, pallet_enclave_bridge::EnclaveBridgeCallIndexes, + pallet_proxy::ProxyCallIndexes, +}; +use itp_stf_interface::{ExecuteCall, SHARD_VAULT_KEY}; use itp_stf_primitives::types::{AccountId, KeyPair, ShardIdentifier, Signature}; -use itp_types::OpaqueCall; +use itp_types::{parentchain::ProxyType, Address, OpaqueCall}; use itp_utils::stringify::account_id_to_string; use log::*; use sp_io::hashing::blake2_256; use sp_runtime::{traits::Verify, MultiAddress}; use std::{format, prelude::v1::*, sync::Arc}; -#[cfg(feature = "evm")] -use ita_sgx_runtime::{AddressMapping, HashedAddressMapping}; - #[cfg(feature = "evm")] use crate::evm_helpers::{create_code_hash, evm_create2_address, evm_create_address}; +use crate::helpers::get_storage_by_key_hash; #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)] #[allow(non_camel_case_types)] @@ -242,13 +245,35 @@ where shard ); unshield_funds(account_incognito, value)?; + calls.push(OpaqueCall::from_tuple(&( node_metadata_repo.get_from_metadata(|m| m.unshield_funds_call_indexes())??, shard, - beneficiary, + beneficiary.clone(), value, call_hash, ))); + // todo: the following is a placeholder dummy which will replace the above with #1257. + // the extrinsic will be sent and potentially deplete the vault at the current state which + // is nothing to worry about before we solve mentioned issue. + let vault_pubkey: [u8; 32] = get_storage_by_key_hash(SHARD_VAULT_KEY.into()) + .ok_or_else(|| { + StfError::Dispatch("shard vault key hasn't been set".to_string()) + })?; + let vault_address = Address::from(AccountId::from(vault_pubkey)); + let vault_transfer_call = OpaqueCall::from_tuple(&( + node_metadata_repo + .get_from_metadata(|m| m.transfer_keep_alive_call_indexes())??, + Address::from(beneficiary), + Compact(value), + )); + let proxy_call = OpaqueCall::from_tuple(&( + node_metadata_repo.get_from_metadata(|m| m.proxy_call_indexes())??, + vault_address, + None::, + vault_transfer_call, + )); + calls.push(proxy_call); Ok(()) }, TrustedCall::balance_shield(enclave_account, who, value) => { diff --git a/core-primitives/attestation-handler/src/attestation_handler.rs b/core-primitives/attestation-handler/src/attestation_handler.rs index 91bfc77f3a..59e4988be2 100644 --- a/core-primitives/attestation-handler/src/attestation_handler.rs +++ b/core-primitives/attestation-handler/src/attestation_handler.rs @@ -279,6 +279,8 @@ where let _result = ecc_handle.open(); let (prv_k, pub_k) = ecc_handle.create_key_pair()?; info!("Enclave Attestation] Generated ephemeral ECDSA keypair:"); + debug!(" pubkey X is {:02x}", pub_k.gx.iter().format("")); + debug!(" pubkey Y is {:02x}", pub_k.gy.iter().format("")); let qe_quote = if !skip_ra { let qe_quote = match self.retrieve_qe_dcap_quote( diff --git a/core-primitives/attestation-handler/src/cert.rs b/core-primitives/attestation-handler/src/cert.rs index 99c0d8529b..7d1a2d6064 100644 --- a/core-primitives/attestation-handler/src/cert.rs +++ b/core-primitives/attestation-handler/src/cert.rs @@ -234,6 +234,31 @@ pub fn percent_decode(orig: String) -> EnclaveResult { Ok(ret) } +pub fn parse_cert_issuer(cert_der: &[u8]) -> SgxResult> { + // Before we reach here, Webpki already verified the cert is properly signed + + // Search for Public Key prime256v1 OID + let prime256v1_oid = &[0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07]; + let mut offset = cert_der + .windows(prime256v1_oid.len()) + .position(|window| window == prime256v1_oid) + .ok_or(sgx_status_t::SGX_ERROR_UNEXPECTED)?; + offset += 11; // 10 + TAG (0x03) + + // Obtain Public Key length + let mut len = cert_der[offset] as usize; + if len > 0x80 { + len = (cert_der[offset + 1] as usize) * 0x100 + (cert_der[offset + 2] as usize); + offset += 2; + } + + // Obtain Public Key + offset += 1; + let pub_k = cert_der[offset + 2..offset + len].to_vec(); // skip "00 04" + + Ok(pub_k) +} + // FIXME: This code is redundant with the host call of the integritee-node pub fn verify_mra_cert( cert_der: &[u8], @@ -346,6 +371,7 @@ where verify_attn_report(attn_report_raw, pub_k, attestation_ocall) } else { // TODO Refactor state provisioning to not use MURA #1385 + // TODO DCAP is currently just passed through! SECURITY!!! Ok(()) } } diff --git a/core-primitives/enclave-api/ffi/src/lib.rs b/core-primitives/enclave-api/ffi/src/lib.rs index cbdfcd09a0..12115521e1 100644 --- a/core-primitives/enclave-api/ffi/src/lib.rs +++ b/core-primitives/enclave-api/ffi/src/lib.rs @@ -57,6 +57,13 @@ extern "C" { shard_size: u32, ) -> sgx_status_t; + pub fn init_proxied_shard_vault( + eid: sgx_enclave_id_t, + retval: *mut sgx_status_t, + shard: *const u8, + shard_size: u32, + ) -> sgx_status_t; + pub fn trigger_parentchain_block_import( eid: sgx_enclave_id_t, retval: *mut sgx_status_t, @@ -110,6 +117,15 @@ extern "C" { pubkey_size: u32, ) -> sgx_status_t; + pub fn get_ecc_vault_pubkey( + eid: sgx_enclave_id_t, + retval: *mut sgx_status_t, + shard: *const u8, + shard_size: u32, + pubkey: *mut u8, + pubkey_size: u32, + ) -> sgx_status_t; + pub fn get_mrenclave( eid: sgx_enclave_id_t, retval: *mut sgx_status_t, diff --git a/core-primitives/enclave-api/src/enclave_base.rs b/core-primitives/enclave-api/src/enclave_base.rs index def5d3ee47..6ef543656c 100644 --- a/core-primitives/enclave-api/src/enclave_base.rs +++ b/core-primitives/enclave-api/src/enclave_base.rs @@ -25,6 +25,7 @@ use itp_enclave_api_ffi as ffi; use itp_settings::worker::{ HEADER_MAX_SIZE, MR_ENCLAVE_SIZE, SHIELDING_KEY_SIZE, SIGNING_KEY_SIZE, }; +use itp_types::ShardIdentifier; use log::*; use sgx_crypto_helper::rsa3072::Rsa3072PubKey; use sgx_types::*; @@ -56,6 +57,9 @@ pub trait EnclaveBase: Send + Sync + 'static { /// Initialize a new shard. fn init_shard(&self, shard: Vec) -> EnclaveResult<()>; + /// Initialize a new shard vault account and register enclave signer as its proxy. + fn init_proxied_shard_vault(&self, shard: &ShardIdentifier) -> EnclaveResult<()>; + /// Trigger the import of parentchain block explicitly. Used when initializing a light-client /// with a triggered import dispatcher. fn trigger_parentchain_block_import(&self, parentchain_id: &ParentchainId) @@ -73,6 +77,9 @@ pub trait EnclaveBase: Send + Sync + 'static { fn get_ecc_signing_pubkey(&self) -> EnclaveResult; + /// retrieve vault account from shard state + fn get_ecc_vault_pubkey(&self, shard: &ShardIdentifier) -> EnclaveResult; + fn get_fingerprint(&self) -> EnclaveResult; } @@ -164,6 +171,24 @@ impl EnclaveBase for Enclave { Ok(()) } + fn init_proxied_shard_vault(&self, shard: &ShardIdentifier) -> EnclaveResult<()> { + let mut retval = sgx_status_t::SGX_SUCCESS; + + let shard_bytes = shard.encode(); + let result = unsafe { + ffi::init_proxied_shard_vault( + self.eid, + &mut retval, + shard_bytes.as_ptr(), + shard_bytes.len() as u32, + ) + }; + + ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result)); + ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval)); + + Ok(()) + } fn trigger_parentchain_block_import( &self, parentchain_id: &ParentchainId, @@ -276,6 +301,28 @@ impl EnclaveBase for Enclave { Ok(ed25519::Public::from_raw(pubkey)) } + fn get_ecc_vault_pubkey(&self, shard: &ShardIdentifier) -> EnclaveResult { + let mut retval = sgx_status_t::SGX_SUCCESS; + let mut pubkey = [0u8; SIGNING_KEY_SIZE]; + let shard_bytes = shard.encode(); + + let result = unsafe { + ffi::get_ecc_vault_pubkey( + self.eid, + &mut retval, + shard_bytes.as_ptr(), + shard_bytes.len() as u32, + pubkey.as_mut_ptr(), + pubkey.len() as u32, + ) + }; + + ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result)); + ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval)); + + Ok(ed25519::Public::from_raw(pubkey)) + } + fn get_fingerprint(&self) -> EnclaveResult { let mut retval = sgx_status_t::SGX_SUCCESS; let mut mr_enclave = [0u8; MR_ENCLAVE_SIZE]; diff --git a/core-primitives/extrinsics-factory/src/lib.rs b/core-primitives/extrinsics-factory/src/lib.rs index 2b226510c8..0744d1b657 100644 --- a/core-primitives/extrinsics-factory/src/lib.rs +++ b/core-primitives/extrinsics-factory/src/lib.rs @@ -88,6 +88,15 @@ where ) -> Self { ExtrinsicsFactory { genesis_hash, signer, nonce_cache, node_metadata_repository } } + + pub fn with_signer(&self, signer: Signer, nonce_cache: Arc) -> Self { + ExtrinsicsFactory { + genesis_hash: self.genesis_hash, + signer, + nonce_cache, + node_metadata_repository: self.node_metadata_repository.clone(), + } + } } impl CreateExtrinsics @@ -170,6 +179,33 @@ pub mod tests { assert_eq!(nonce_cache.get_nonce().unwrap(), Nonce(opaque_calls.len() as NonceValue)); } + #[test] + pub fn with_signer_works() { + let nonce_cache1 = Arc::new(NonceCache::default()); + *nonce_cache1.load_for_mutation().unwrap() = Nonce(42); + + let node_metadata_repo = Arc::new(NodeMetadataRepository::new(NodeMetadata::default())); + let extrinsics_factory = ExtrinsicsFactory::new( + test_genesis_hash(), + StaticExtrinsicSigner::<_, PairSignature>::new(test_account()), + nonce_cache1.clone(), + node_metadata_repo, + ); + + let nonce_cache2 = Arc::new(NonceCache::default()); + let extrinsics_factory = extrinsics_factory.with_signer( + StaticExtrinsicSigner::<_, PairSignature>::new(test_account2()), + nonce_cache2.clone(), + ); + + let opaque_calls = [OpaqueCall(vec![3u8; 42]), OpaqueCall(vec![12u8, 78])]; + let xts = extrinsics_factory.create_extrinsics(&opaque_calls, None).unwrap(); + + assert_eq!(opaque_calls.len(), xts.len()); + assert_eq!(nonce_cache2.get_nonce().unwrap(), Nonce(opaque_calls.len() as NonceValue)); + assert_eq!(nonce_cache1.get_nonce().unwrap(), Nonce(42)); + } + // #[test] // pub fn xts_have_increasing_nonce() { // let nonce_cache = Arc::new(NonceCache::default()); @@ -194,6 +230,10 @@ pub mod tests { ed25519::Pair::from_seed(b"42315678901234567890123456789012") } + fn test_account2() -> ed25519::Pair { + ed25519::Pair::from_seed(b"12315678901234567890123456789012") + } + fn test_genesis_hash() -> H256 { H256::from_slice(&[56u8; 32]) } diff --git a/core-primitives/node-api/metadata/src/lib.rs b/core-primitives/node-api/metadata/src/lib.rs index 55f66e35dc..648876eb40 100644 --- a/core-primitives/node-api/metadata/src/lib.rs +++ b/core-primitives/node-api/metadata/src/lib.rs @@ -20,7 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use crate::{ - error::Result, pallet_enclave_bridge::EnclaveBridgeCallIndexes, + error::Result, pallet_balances::BalancesCallIndexes, + pallet_enclave_bridge::EnclaveBridgeCallIndexes, pallet_proxy::ProxyCallIndexes, pallet_sidechain::SidechainCallIndexes, pallet_teerex::TeerexCallIndexes, }; use codec::{Decode, Encode}; @@ -32,6 +33,7 @@ pub use itp_api_client_types::{Metadata, MetadataError}; pub mod error; pub mod pallet_balances; pub mod pallet_enclave_bridge; +pub mod pallet_proxy; pub mod pallet_sidechain; pub mod pallet_teeracle; pub mod pallet_teerex; @@ -40,11 +42,20 @@ pub mod pallet_teerex; pub mod metadata_mocks; pub trait NodeMetadataTrait: - TeerexCallIndexes + EnclaveBridgeCallIndexes + SidechainCallIndexes + TeerexCallIndexes + + EnclaveBridgeCallIndexes + + SidechainCallIndexes + + ProxyCallIndexes + + BalancesCallIndexes { } -impl NodeMetadataTrait - for T +impl< + T: TeerexCallIndexes + + EnclaveBridgeCallIndexes + + SidechainCallIndexes + + ProxyCallIndexes + + BalancesCallIndexes, + > NodeMetadataTrait for T { } diff --git a/core-primitives/node-api/metadata/src/metadata_mocks.rs b/core-primitives/node-api/metadata/src/metadata_mocks.rs index 57cf0fe327..8bf47298ec 100644 --- a/core-primitives/node-api/metadata/src/metadata_mocks.rs +++ b/core-primitives/node-api/metadata/src/metadata_mocks.rs @@ -16,11 +16,12 @@ */ use crate::{ - error::Result, pallet_sidechain::SidechainCallIndexes, pallet_teerex::TeerexCallIndexes, + error::Result, pallet_balances::BalancesCallIndexes, + pallet_enclave_bridge::EnclaveBridgeCallIndexes, pallet_proxy::ProxyCallIndexes, + pallet_sidechain::SidechainCallIndexes, pallet_teerex::TeerexCallIndexes, }; use codec::{Decode, Encode}; -use crate::pallet_enclave_bridge::EnclaveBridgeCallIndexes; use itp_api_client_types::Metadata; impl TryFrom for Metadata { @@ -48,6 +49,13 @@ pub struct NodeMetadataMock { update_shard_config: u8, sidechain_module: u8, imported_sidechain_block: u8, + proxy_module: u8, + add_proxy: u8, + proxy: u8, + balances_module: u8, + transfer: u8, + transfer_keep_alive: u8, + transfer_allow_death: u8, runtime_spec_version: u32, runtime_transaction_version: u32, } @@ -70,6 +78,13 @@ impl NodeMetadataMock { update_shard_config: 5u8, sidechain_module: 53u8, imported_sidechain_block: 0u8, + proxy_module: 7u8, + add_proxy: 1u8, + proxy: 0u8, + balances_module: 10u8, + transfer: 7u8, + transfer_keep_alive: 3u8, + transfer_allow_death: 0u8, runtime_spec_version: 25, runtime_transaction_version: 4, } @@ -129,3 +144,27 @@ impl SidechainCallIndexes for NodeMetadataMock { Ok([self.sidechain_module, self.imported_sidechain_block]) } } + +impl ProxyCallIndexes for NodeMetadataMock { + fn add_proxy_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.proxy_module, self.add_proxy]) + } + + fn proxy_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.proxy_module, self.proxy]) + } +} + +impl BalancesCallIndexes for NodeMetadataMock { + fn transfer_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.balances_module, self.transfer]) + } + + fn transfer_keep_alive_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.balances_module, self.transfer_keep_alive]) + } + + fn transfer_allow_death_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.balances_module, self.transfer_allow_death]) + } +} diff --git a/core-primitives/node-api/metadata/src/pallet_balances.rs b/core-primitives/node-api/metadata/src/pallet_balances.rs index 185f0efff3..9ae88dd742 100644 --- a/core-primitives/node-api/metadata/src/pallet_balances.rs +++ b/core-primitives/node-api/metadata/src/pallet_balances.rs @@ -21,17 +21,23 @@ use crate::{error::Result, NodeMetadata}; const BALANCES: &str = "Balances"; pub trait BalancesCallIndexes { - fn transfer_call_index(&self) -> Result<[u8; 2]>; + fn transfer_call_indexes(&self) -> Result<[u8; 2]>; - fn transfer_allow_death_call_index(&self) -> Result<[u8; 2]>; + fn transfer_keep_alive_call_indexes(&self) -> Result<[u8; 2]>; + + fn transfer_allow_death_call_indexes(&self) -> Result<[u8; 2]>; } impl BalancesCallIndexes for NodeMetadata { - fn transfer_call_index(&self) -> Result<[u8; 2]> { + fn transfer_call_indexes(&self) -> Result<[u8; 2]> { self.call_indexes(BALANCES, "transfer") } - fn transfer_allow_death_call_index(&self) -> Result<[u8; 2]> { + fn transfer_keep_alive_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(BALANCES, "transfer_keep_alive") + } + + fn transfer_allow_death_call_indexes(&self) -> Result<[u8; 2]> { self.call_indexes(BALANCES, "transfer_allow_death") } } diff --git a/core-primitives/node-api/metadata/src/pallet_proxy.rs b/core-primitives/node-api/metadata/src/pallet_proxy.rs new file mode 100644 index 0000000000..6a7aa14b08 --- /dev/null +++ b/core-primitives/node-api/metadata/src/pallet_proxy.rs @@ -0,0 +1,39 @@ +/* + Copyright 2021 Integritee AG and Supercomputing Systems AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +use crate::{error::Result, NodeMetadata}; + +/// Pallet name: +const PROXY: &str = "Proxy"; +/// the deposit needed to register up to 20 proxies in native parentchain token +pub const PROXY_DEPOSIT: u128 = 21_000_000_000_000; + +pub trait ProxyCallIndexes { + fn add_proxy_call_indexes(&self) -> Result<[u8; 2]>; + + fn proxy_call_indexes(&self) -> Result<[u8; 2]>; +} + +impl ProxyCallIndexes for NodeMetadata { + fn add_proxy_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(PROXY, "add_proxy") + } + + fn proxy_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(PROXY, "proxy") + } +} diff --git a/core-primitives/ocall-api/src/lib.rs b/core-primitives/ocall-api/src/lib.rs index 2bd1ca2104..503a4b5a4c 100644 --- a/core-primitives/ocall-api/src/lib.rs +++ b/core-primitives/ocall-api/src/lib.rs @@ -93,6 +93,7 @@ pub trait EnclaveOnChainOCallApi: Clone + Send + Sync { &self, extrinsics: Vec, parentchain_id: &ParentchainId, + await_each_inclusion: bool, ) -> SgxResult<()>; fn worker_request( diff --git a/core-primitives/stf-executor/Cargo.toml b/core-primitives/stf-executor/Cargo.toml index ee844db96f..da91248f70 100644 --- a/core-primitives/stf-executor/Cargo.toml +++ b/core-primitives/stf-executor/Cargo.toml @@ -5,6 +5,8 @@ authors = ["Integritee AG "] edition = "2021" [dependencies] +hex = { version = "0.4.3", default-features = false, features = ["alloc"] } + # sgx dependencies sgx-crypto-helper = { branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git", package = "sgx_crypto_helper", default-features = false, optional = true } sgx_tstd = { branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true, features = ["untrusted_time"] } diff --git a/core-primitives/stf-executor/src/executor.rs b/core-primitives/stf-executor/src/executor.rs index 3c5f53afb9..a40eb84445 100644 --- a/core-primitives/stf-executor/src/executor.rs +++ b/core-primitives/stf-executor/src/executor.rs @@ -127,6 +127,9 @@ where state.prune_state_diff(); } + for call in extrinsic_call_backs.clone() { + trace!("trusted_call wants to send encoded call: 0x{}", hex::encode(call.encode())); + } Ok(ExecutedOperation::success(operation_hash, top_or_hash, extrinsic_call_backs)) } } diff --git a/core-primitives/stf-interface/src/lib.rs b/core-primitives/stf-interface/src/lib.rs index 66ae77495b..e88104351e 100644 --- a/core-primitives/stf-interface/src/lib.rs +++ b/core-primitives/stf-interface/src/lib.rs @@ -33,6 +33,8 @@ pub mod parentchain_pallet; pub mod sudo_pallet; pub mod system_pallet; +pub const SHARD_VAULT_KEY: &str = "ShardVaultPubKey"; + /// Interface to initialize a new state. pub trait InitState { /// Initialize a new state for a given enclave account. diff --git a/core-primitives/test/src/mock/onchain_mock.rs b/core-primitives/test/src/mock/onchain_mock.rs index 1ed4efdc0f..4101636f93 100644 --- a/core-primitives/test/src/mock/onchain_mock.rs +++ b/core-primitives/test/src/mock/onchain_mock.rs @@ -180,6 +180,7 @@ impl EnclaveOnChainOCallApi for OnchainMock { &self, _extrinsics: Vec, _: &ParentchainId, + _: bool, ) -> SgxResult<()> { Ok(()) } diff --git a/core-primitives/types/src/parentchain.rs b/core-primitives/types/src/parentchain.rs index 32610d0aa9..6439929129 100644 --- a/core-primitives/types/src/parentchain.rs +++ b/core-primitives/types/src/parentchain.rs @@ -33,6 +33,15 @@ pub type AccountId = sp_core::crypto::AccountId32; pub type AccountData = pallet_balances::AccountData; pub type AccountInfo = frame_system::AccountInfo; pub type Address = MultiAddress; +// todo! make generic +/// The type used to represent the kinds of proxying allowed. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug)] +pub enum ProxyType { + Any, + NonTransfer, + Governance, + Staking, +} // Block Types pub type BlockNumber = u32; diff --git a/core/parentchain/indirect-calls-executor/src/filter_metadata.rs b/core/parentchain/indirect-calls-executor/src/filter_metadata.rs index dd95b8b0bf..a2adc3c891 100644 --- a/core/parentchain/indirect-calls-executor/src/filter_metadata.rs +++ b/core/parentchain/indirect-calls-executor/src/filter_metadata.rs @@ -174,10 +174,13 @@ where let index = xt.call_index; let call_args = &mut &xt.call_args[..]; log::trace!("[TransferToAliceShieldsFundsFilter] attempting to execute indirect call with index {:?}", index); - if index == metadata.transfer_call_index().ok()? - || index == metadata.transfer_allow_death_call_index().ok()? + if index == metadata.transfer_call_indexes().ok()? + || index == metadata.transfer_keep_alive_call_indexes().ok()? + || index == metadata.transfer_allow_death_call_indexes().ok()? { - log::debug!("found `transfer` or `transfer_allow_death` call."); + log::debug!( + "found `transfer` or `transfer_allow_death` or `transfer_keep_alive` call." + ); let args = decode_and_log_error::(call_args)?; if args.destination == ALICE_ACCOUNT_ID.into() { Some(IndirectCall::TransferToAliceShieldsFunds(args)) diff --git a/core/parentchain/light-client/src/light_validation.rs b/core/parentchain/light-client/src/light_validation.rs index 3eda5c8490..5da9db71d6 100644 --- a/core/parentchain/light-client/src/light_validation.rs +++ b/core/parentchain/light-client/src/light_validation.rs @@ -164,7 +164,7 @@ where { fn send_extrinsics(&mut self, extrinsics: Vec) -> Result<(), Error> { self.ocall_api - .send_to_parentchain(extrinsics, &self.parentchain_id) + .send_to_parentchain(extrinsics, &self.parentchain_id, false) .map_err(|e| { Error::Other( format!("[{:?}] Failed to send extrinsics: {}", self.parentchain_id, e).into(), diff --git a/enclave-runtime/Cargo.lock b/enclave-runtime/Cargo.lock index cbdc7d892f..29dd4bdf15 100644 --- a/enclave-runtime/Cargo.lock +++ b/enclave-runtime/Cargo.lock @@ -257,7 +257,7 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "hash-db 0.16.0", ] @@ -1083,7 +1083,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -1196,7 +1196,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sp-api", @@ -2185,6 +2185,7 @@ dependencies = [ name = "itp-stf-executor" version = "0.9.0" dependencies = [ + "hex", "ita-stf", "itc-parentchain-test", "itp-node-api", @@ -2960,7 +2961,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -2976,7 +2977,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -2990,7 +2991,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -3026,7 +3027,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -3048,7 +3049,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -3078,7 +3079,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -3098,7 +3099,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -3112,7 +3113,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -3128,7 +3129,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -3143,7 +3144,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -4218,7 +4219,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sp-api", @@ -4230,7 +4231,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", @@ -4246,7 +4247,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "finality-grandpa", "log", @@ -4262,7 +4263,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", @@ -4394,7 +4395,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "sp-api", "sp-core", @@ -4454,7 +4455,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", @@ -4495,7 +4496,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sp-inherents", @@ -4517,7 +4518,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "sp-api", "sp-runtime", @@ -4526,7 +4527,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#569aae5341ea0c1d10426fa1ec13a36c0b64393b" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "hash-db 0.16.0", "memory-db", diff --git a/enclave-runtime/Enclave.edl b/enclave-runtime/Enclave.edl index c8cf058ec1..544e988b1a 100644 --- a/enclave-runtime/Enclave.edl +++ b/enclave-runtime/Enclave.edl @@ -58,6 +58,10 @@ enclave { [in, size=shard_size] uint8_t* shard, uint32_t shard_size ); + public sgx_status_t init_proxied_shard_vault( + [in, size=shard_size] uint8_t* shard, uint32_t shard_size + ); + public sgx_status_t trigger_parentchain_block_import( [in, size=parentchain_id_size] uint8_t* parentchain_id, uint32_t parentchain_id_size ); @@ -87,6 +91,10 @@ enclave { public sgx_status_t get_ecc_signing_pubkey( [out, size=pubkey_size] uint8_t* pubkey, uint32_t pubkey_size); + public sgx_status_t get_ecc_vault_pubkey( + [in, size=shard_size] uint8_t* shard, uint32_t shard_size, + [out, size=pubkey_size] uint8_t* pubkey, uint32_t pubkey_size); + public sgx_status_t get_mrenclave( [out, size=mrenclave_size] uint8_t* mrenclave, uint32_t mrenclave_size); @@ -242,7 +250,8 @@ enclave { sgx_status_t ocall_send_to_parentchain( [in, size = extrinsics_size] uint8_t * extrinsics, uint32_t extrinsics_size, - [in, size=parentchain_id_size] uint8_t* parentchain_id, uint32_t parentchain_id_size + [in, size=parentchain_id_size] uint8_t* parentchain_id, uint32_t parentchain_id_size, + int await_each_inclusion ); }; }; diff --git a/enclave-runtime/src/attestation.rs b/enclave-runtime/src/attestation.rs index ae609f279b..857578c431 100644 --- a/enclave-runtime/src/attestation.rs +++ b/enclave-runtime/src/attestation.rs @@ -30,7 +30,7 @@ use crate::{ initialization::global_components::GLOBAL_ATTESTATION_HANDLER_COMPONENT, utils::{ - get_extrinsic_factory_from_solo_or_parachain, + get_extrinsic_factory_from_integritee_solo_or_parachain, get_node_metadata_repository_from_integritee_solo_or_parachain, }, Error as EnclaveError, Result as EnclaveResult, @@ -381,7 +381,7 @@ pub fn generate_ias_skip_ra_extrinsic_from_der_cert_internal( } fn create_extrinsics(call: OpaqueCall) -> EnclaveResult { - let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let extrinsics = extrinsics_factory.create_extrinsics(&[call], None)?; Ok(extrinsics[0].clone()) @@ -459,7 +459,7 @@ pub fn generate_generic_register_collateral_extrinsic( where F: Fn(&NodeMetadata) -> Result<[u8; 2], MetadataError>, { - let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let node_metadata_repo = get_node_metadata_repository_from_integritee_solo_or_parachain()?; let call_ids = node_metadata_repo diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index 0573c11c5c..cb65c12cfd 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -41,7 +41,7 @@ use crate::{ ocall::OcallApi, rpc::{rpc_response_channel::RpcResponseChannel, worker_api_direct::public_api_rpc_handler}, utils::{ - get_extrinsic_factory_from_solo_or_parachain, + get_extrinsic_factory_from_integritee_solo_or_parachain, get_node_metadata_repository_from_integritee_solo_or_parachain, get_triggered_dispatcher_from_solo_or_parachain, get_validator_accessor_from_solo_or_parachain, @@ -80,7 +80,6 @@ use its_sidechain::block_composer::BlockComposer; use log::*; use sp_core::crypto::Pair; use std::{collections::HashMap, path::PathBuf, string::String, sync::Arc}; - pub(crate) fn init_enclave( mu_ra_url: String, untrusted_worker_url: String, @@ -226,7 +225,7 @@ pub(crate) fn init_enclave_sidechain_components() -> EnclaveResult<()> { let sidechain_block_import_queue = GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT.get()?; let metadata_repository = get_node_metadata_repository_from_integritee_solo_or_parachain()?; - let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let validator_accessor = get_validator_accessor_from_solo_or_parachain()?; let sidechain_block_import_confirmation_handler = diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index 3379bcfe4b..7c375b8205 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -74,12 +74,12 @@ use std::{ string::{String, ToString}, vec::Vec, }; - mod attestation; mod empty_impls; mod initialization; mod ipfs; mod ocall; +mod shard_vault; mod utils; pub mod error; diff --git a/enclave-runtime/src/ocall/ffi.rs b/enclave-runtime/src/ocall/ffi.rs index 4db3bbbba4..acd63ffa46 100644 --- a/enclave-runtime/src/ocall/ffi.rs +++ b/enclave-runtime/src/ocall/ffi.rs @@ -113,6 +113,7 @@ extern "C" { extrinsics_size: u32, parentchain_id: *const u8, parentchain_id_size: u32, + await_each_inclusion: c_int, ) -> sgx_status_t; pub fn ocall_read_ipfs( diff --git a/enclave-runtime/src/ocall/on_chain_ocall.rs b/enclave-runtime/src/ocall/on_chain_ocall.rs index d79c5d5540..e71fb72618 100644 --- a/enclave-runtime/src/ocall/on_chain_ocall.rs +++ b/enclave-runtime/src/ocall/on_chain_ocall.rs @@ -33,6 +33,7 @@ impl EnclaveOnChainOCallApi for OcallApi { &self, extrinsics: Vec, parentchain_id: &ParentchainId, + await_each_inclusion: bool, ) -> SgxResult<()> { let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; let extrinsics_encoded = extrinsics.encode(); @@ -45,6 +46,7 @@ impl EnclaveOnChainOCallApi for OcallApi { extrinsics_encoded.len() as u32, parentchain_id_encoded.as_ptr(), parentchain_id_encoded.len() as u32, + await_each_inclusion.into(), ) }; diff --git a/enclave-runtime/src/shard_vault.rs b/enclave-runtime/src/shard_vault.rs new file mode 100644 index 0000000000..860f2ef56d --- /dev/null +++ b/enclave-runtime/src/shard_vault.rs @@ -0,0 +1,208 @@ +/* + Copyright 2021 Integritee AG + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +use crate::{ + error::{Error, Result as EnclaveResult}, + initialization::global_components::{ + GLOBAL_OCALL_API_COMPONENT, GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT, + GLOBAL_STATE_HANDLER_COMPONENT, + }, + utils::{ + get_extrinsic_factory_from_integritee_solo_or_parachain, + get_node_metadata_repository_from_integritee_solo_or_parachain, + }, +}; +use codec::{Compact, Decode, Encode}; +use itp_component_container::ComponentGetter; +use itp_extrinsics_factory::CreateExtrinsics; +use itp_node_api::{ + api_client::{PairSignature, StaticExtrinsicSigner}, + metadata::{ + pallet_proxy::PROXY_DEPOSIT, + provider::{AccessNodeMetadata, Error as MetadataProviderError}, + }, +}; +use itp_node_api_metadata::pallet_proxy::ProxyCallIndexes; +use itp_nonce_cache::NonceCache; +use itp_ocall_api::EnclaveOnChainOCallApi; +use itp_sgx_crypto::key_repository::AccessKey; +use itp_stf_interface::SHARD_VAULT_KEY; +use itp_stf_state_handler::{handle_state::HandleState, query_shard_state::QueryShardState}; +use itp_types::{ + parentchain::{AccountId, Address, ParentchainId, ProxyType}, + OpaqueCall, ShardIdentifier, +}; +use log::*; +use sgx_types::sgx_status_t; +use sp_core::crypto::{DeriveJunction, Pair}; +use std::{slice, sync::Arc, vec::Vec}; + +#[no_mangle] +pub unsafe extern "C" fn init_proxied_shard_vault( + shard: *const u8, + shard_size: u32, +) -> sgx_status_t { + let shard_identifier = + ShardIdentifier::from_slice(slice::from_raw_parts(shard, shard_size as usize)); + + if let Err(e) = init_proxied_shard_vault_internal(shard_identifier) { + error!("Failed to initialize proxied shard vault ({:?}): {:?}", shard_identifier, e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + } + + sgx_status_t::SGX_SUCCESS +} + +/// reads the shard vault account id form state if it has been initialized previously +#[no_mangle] +pub unsafe extern "C" fn get_ecc_vault_pubkey( + shard: *const u8, + shard_size: u32, + pubkey: *mut u8, + pubkey_size: u32, +) -> sgx_status_t { + let shard = ShardIdentifier::from_slice(slice::from_raw_parts(shard, shard_size as usize)); + + let shard_vault = match get_shard_vault_account(shard) { + Ok(account) => account, + Err(e) => { + error!("Failed to fetch shard vault account: {:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + }, + }; + + let pubkey_slice = slice::from_raw_parts_mut(pubkey, pubkey_size as usize); + pubkey_slice.clone_from_slice(shard_vault.encode().as_slice()); + sgx_status_t::SGX_SUCCESS +} + +/// reads the shard vault account id form state if it has been initialized previously +pub(crate) fn get_shard_vault_account(shard: ShardIdentifier) -> EnclaveResult { + let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; + + state_handler + .execute_on_current(&shard, |state, _| { + state + .state + .get::>(&SHARD_VAULT_KEY.into()) + .and_then(|v| Decode::decode(&mut v.clone().as_slice()).ok()) + })? + .ok_or_else(|| { + Error::Other("failed to fetch shard vault account. has it been initialized?".into()) + }) +} + +pub(crate) fn init_proxied_shard_vault_internal(shard: ShardIdentifier) -> EnclaveResult<()> { + let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; + if !state_handler.shard_exists(&shard).unwrap() { + return Err(Error::Other("shard not initialized".into())) + }; + + let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; + let enclave_signer = GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?; + let enclave_extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; + let node_metadata_repo = get_node_metadata_repository_from_integritee_solo_or_parachain()?; + let vault = enclave_signer + .derive(vec![DeriveJunction::hard(shard.encode())].into_iter(), None) + .map_err(|_| Error::Other("failed to derive shard vault keypair".into()))? + .0; + + info!("shard vault account derived pubkey: 0x{}", hex::encode(vault.public().0)); + + let (state_lock, mut state) = state_handler.load_for_mutation(&shard)?; + state.state.insert(SHARD_VAULT_KEY.into(), vault.public().0.to_vec()); + state_handler.write_after_mutation(state, state_lock, &shard)?; + + info!("send existential funds from enclave account to vault account"); + let call_ids = node_metadata_repo + .get_from_metadata(|m| m.call_indexes("Balances", "transfer_keep_alive"))? + .map_err(MetadataProviderError::MetadataError)?; + + let call = OpaqueCall::from_tuple(&( + call_ids, + Address::from(AccountId::from(vault.public().0)), + Compact(PROXY_DEPOSIT), + )); + + info!("vault funding call: 0x{}", hex::encode(call.0.clone())); + let xts = enclave_extrinsics_factory.create_extrinsics(&[call], None)?; + + //this extrinsic must be included in a block before we can move on. otherwise the next will fail + ocall_api.send_to_parentchain(xts, &ParentchainId::Integritee, true)?; + + // we are assuming nonce=0 here. + let nonce_cache = Arc::new(NonceCache::default()); + let vault_extrinsics_factory = enclave_extrinsics_factory + .with_signer(StaticExtrinsicSigner::<_, PairSignature>::new(vault), nonce_cache); + + info!("register enclave signer as proxy for shard vault"); + let call_ids = node_metadata_repo + .get_from_metadata(|m| m.call_indexes("Proxy", "add_proxy"))? + .map_err(MetadataProviderError::MetadataError)?; + + let call = OpaqueCall::from_tuple(&( + call_ids, + Address::from(AccountId::from(enclave_signer.public().0)), + ProxyType::Any, + 0u32, // delay + )); + + info!("add proxy call: 0x{}", hex::encode(call.0.clone())); + let xts = vault_extrinsics_factory.create_extrinsics(&[call], None)?; + + ocall_api.send_to_parentchain(xts, &ParentchainId::Integritee, false)?; + Ok(()) +} + +pub(crate) fn add_shard_vault_proxy( + shard: ShardIdentifier, + proxy: &AccountId, +) -> EnclaveResult<()> { + let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; + if !state_handler.shard_exists(&shard).unwrap() { + return Err(Error::Other("shard not initialized".into())) + }; + + let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; + let enclave_extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; + let node_metadata_repo = get_node_metadata_repository_from_integritee_solo_or_parachain()?; + let vault = get_shard_vault_account(shard)?; + + debug!( + "adding proxy 0x{} to shard vault account 0x{}", + hex::encode(proxy.clone()), + hex::encode(vault.clone()) + ); + + let add_proxy_call = OpaqueCall::from_tuple(&( + node_metadata_repo.get_from_metadata(|m| m.add_proxy_call_indexes())??, + Address::from(proxy.clone()), + ProxyType::Any, + 0u32, // delay + )); + let call = OpaqueCall::from_tuple(&( + node_metadata_repo.get_from_metadata(|m| m.proxy_call_indexes())??, + Address::from(vault), + None::, + add_proxy_call, + )); + + info!("proxied add proxy call: 0x{}", hex::encode(call.0.clone())); + let xts = enclave_extrinsics_factory.create_extrinsics(&[call], None)?; + + ocall_api.send_to_parentchain(xts, &ParentchainId::Integritee, false)?; + Ok(()) +} diff --git a/enclave-runtime/src/teeracle/mod.rs b/enclave-runtime/src/teeracle/mod.rs index 460357fc94..75f378c9a0 100644 --- a/enclave-runtime/src/teeracle/mod.rs +++ b/enclave-runtime/src/teeracle/mod.rs @@ -19,7 +19,7 @@ use crate::{ error::{Error, Result}, initialization::global_components::GLOBAL_OCALL_API_COMPONENT, utils::{ - get_extrinsic_factory_from_solo_or_parachain, + get_extrinsic_factory_from_integritee_solo_or_parachain, get_node_metadata_repository_from_integritee_solo_or_parachain, }, }; @@ -46,7 +46,7 @@ use sp_runtime::OpaqueExtrinsic; use std::{string::String, vec::Vec}; fn update_weather_data_internal(weather_info: WeatherInfo) -> Result> { - let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; let mut extrinsic_calls: Vec = Vec::new(); @@ -198,7 +198,7 @@ fn update_market_data_internal( crypto_currency: String, fiat_currency: String, ) -> Result> { - let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; let mut extrinsic_calls: Vec = Vec::new(); diff --git a/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs b/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs index ec543b1718..3078bb43c1 100644 --- a/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs +++ b/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs @@ -52,6 +52,7 @@ impl EnclaveOnChainOCallApi for ProposeToImportOCallApi { &self, _extrinsics: Vec, _: &ParentchainId, + _: bool, ) -> SgxResult<()> { Ok(()) } diff --git a/enclave-runtime/src/tls_ra/README.md b/enclave-runtime/src/tls_ra/README.md new file mode 100644 index 0000000000..3f4effa148 --- /dev/null +++ b/enclave-runtime/src/tls_ra/README.md @@ -0,0 +1,33 @@ +# provisioning + +each worker runs a provisioning server for other workers of the same MRENCLAVE and shard to get recent stf state and secrets from. + +Light client storage can also be provisioned to avoid re-synching the entire parentchains with each worker + +enclave instances are short-lived on both sides, just for a single request. + +```mermaid +sequenceDiagram +participant untrusted_server +participant enclave_server +participant enclave_client +participant untrusted_client +enclave_server ->> enclave_server: generate shielding & state encryption key +enclave_server ->> enclave_server: init_shard & sync parentchains +untrusted_client ->> untrusted_server: connect TCP +untrusted_client ->> enclave_client: request_state_provisioning +activate enclave_client +untrusted_server ->> enclave_server: run_state_provisioning_server +activate enclave_server +enclave_server ->> enclave_server: load state and secrets +enclave_client ->> enclave_server: open TLS session (including MU RA) +enclave_client ->> enclave_server: request_state_provisioning(shard, account) +enclave_server ->> enclave_client: write_provisioning_payloads +enclave_server ->> enclave_server: add client as vault proxy for shard +enclave_client ->> enclave_client: seal state and secrets to disk +enclave_client -->> untrusted_client: _ +deactivate enclave_client +enclave_server -->> untrusted_server: _ +deactivate enclave_server +untrusted_client --> untrusted_server: disconnect TCP +``` diff --git a/enclave-runtime/src/tls_ra/authentication.rs b/enclave-runtime/src/tls_ra/authentication.rs index d1f9633497..c2dbdd3e92 100644 --- a/enclave-runtime/src/tls_ra/authentication.rs +++ b/enclave-runtime/src/tls_ra/authentication.rs @@ -16,7 +16,6 @@ */ //! Remote attestation certificate authentication of server and client - use itp_attestation_handler::cert; use itp_ocall_api::EnclaveAttestationOCallApi; use log::*; @@ -52,6 +51,9 @@ where _sni: Option<&DNSName>, ) -> Result { debug!("client cert: {:?}", certs); + let issuer = cert::parse_cert_issuer(&certs[0].0).unwrap(); + info!("client signer (issuer) is: 0x{}", hex::encode(issuer)); + // This call will automatically verify cert is properly signed if self.skip_ra { warn!("Skip verifying ra-report"); @@ -104,6 +106,8 @@ where _ocsp: &[u8], ) -> Result { debug!("server cert: {:?}", certs); + let issuer = cert::parse_cert_issuer(&certs[0].0).unwrap(); + info!("server signer (issuer) is: 0x{}", hex::encode(issuer)); if self.skip_ra { warn!("Skip verifying ra-report"); diff --git a/enclave-runtime/src/tls_ra/mod.rs b/enclave-runtime/src/tls_ra/mod.rs index 90724cdfe5..07474f3f8b 100644 --- a/enclave-runtime/src/tls_ra/mod.rs +++ b/enclave-runtime/src/tls_ra/mod.rs @@ -19,6 +19,7 @@ //! including the remote attestation and tls / tcp connection part. use codec::{Decode, Encode, MaxEncodedLen}; +use itp_types::{AccountId, ShardIdentifier}; mod authentication; pub mod seal_handler; @@ -71,3 +72,10 @@ impl Opcode { (self as u8).to_be_bytes() } } + +/// The data structure to be sent by the client to request provisioning +#[derive(Clone, Debug, Eq, PartialEq, Decode, Encode, MaxEncodedLen)] +pub struct ClientProvisioningRequest { + pub shard: ShardIdentifier, + pub account: AccountId, +} diff --git a/enclave-runtime/src/tls_ra/tests.rs b/enclave-runtime/src/tls_ra/tests.rs index beae945656..37b69c64f7 100644 --- a/enclave-runtime/src/tls_ra/tests.rs +++ b/enclave-runtime/src/tls_ra/tests.rs @@ -72,6 +72,7 @@ fn server_addr(port: u16) -> String { pub fn test_tls_ra_server_client_networking() { let shard = ShardIdentifier::default(); + let client_account = AccountId::from([42; 32]); let shielding_key_encoded = vec![1, 2, 3]; let state_key_encoded = vec![5, 2, 3, 7]; let state_encoded = Vec::from([1u8; 26000]); // Have a decently sized state, so read() must be called multiple times. @@ -118,6 +119,7 @@ pub fn test_tls_ra_server_client_networking() { shard, SKIP_RA, client_seal_handler.clone(), + client_account, ); // Ensure server thread has finished. @@ -139,6 +141,7 @@ pub fn test_tls_ra_server_client_networking() { // Test state and key provisioning with 'real' data structures. pub fn test_state_and_key_provisioning() { + let client_account = AccountId::from([42; 32]); let state_key = Aes::new([3u8; 16], [0u8; 16]); let shielding_key = Rsa3072KeyPair::new().unwrap(); let initialized_state = EnclaveStf::init_state(AccountId::new([1u8; 32])); @@ -168,6 +171,7 @@ pub fn test_state_and_key_provisioning() { shard, SKIP_RA, client_seal_handler, + client_account, ); // Ensure server thread has finished. diff --git a/enclave-runtime/src/tls_ra/tls_ra_client.rs b/enclave-runtime/src/tls_ra/tls_ra_client.rs index 630f8877d3..428961da77 100644 --- a/enclave-runtime/src/tls_ra/tls_ra_client.rs +++ b/enclave-runtime/src/tls_ra/tls_ra_client.rs @@ -26,13 +26,15 @@ use crate::{ GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_KEY_REPOSITORY_COMPONENT, }, ocall::OcallApi, - tls_ra::seal_handler::SealStateAndKeys, - GLOBAL_STATE_HANDLER_COMPONENT, + tls_ra::{seal_handler::SealStateAndKeys, ClientProvisioningRequest}, + GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT, }; +use codec::Encode; use itp_attestation_handler::{RemoteAttestationType, DEV_HOSTNAME}; use itp_component_container::ComponentGetter; use itp_ocall_api::EnclaveAttestationOCallApi; -use itp_types::ShardIdentifier; +use itp_sgx_crypto::key_repository::AccessPubkey; +use itp_types::{AccountId, ShardIdentifier}; use log::*; use rustls::{ClientConfig, ClientSession, Stream}; use sgx_types::*; @@ -44,7 +46,6 @@ use std::{ sync::Arc, vec::Vec, }; - /// Client part of the TCP-level connection and the underlying TLS-level session. /// /// Includes a seal handler, which handles the storage part of the received data. @@ -73,17 +74,20 @@ where /// /// We trust here that the server sends us the correct data, as /// we do not have any way to test it. - fn read_shard(&mut self) -> EnclaveResult<()> { - debug!("read_shard called, about to call self.write_shard()."); - self.write_shard()?; - debug!("self.write_shard() succeeded."); + fn obtain_provisioning_for_shard(&mut self, account: AccountId) -> EnclaveResult<()> { + debug!( + "obtain_provisioning_for_shard called, about to call self.send_provisioning_request()." + ); + self.send_provisioning_request(account)?; + debug!("self.send_provisioning_request() succeeded."); self.read_and_seal_all() } /// Send the shard of the state we want to receive to the provisioning server. - fn write_shard(&mut self) -> EnclaveResult<()> { - debug!("self.write_shard() called."); - self.tls_stream.write_all(self.shard.as_bytes())?; + fn send_provisioning_request(&mut self, account: AccountId) -> EnclaveResult<()> { + debug!("self.send_provisioning_request() called."); + self.tls_stream + .write_all(&ClientProvisioningRequest { shard: self.shard, account }.encode())?; debug!("write_all succeeded."); Ok(()) } @@ -208,6 +212,19 @@ pub unsafe extern "C" fn request_state_provisioning( light_client_seal, ); + let signing_key_repository = match GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get() { + Ok(s) => s, + Err(e) => { + error!("{:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + }, + }; + + let client_account = match signing_key_repository.retrieve_pubkey() { + Ok(s) => AccountId::from(s), + Err(e) => return e.into(), + }; + if let Err(e) = request_state_provisioning_internal( socket_fd, sign_type, @@ -216,6 +233,7 @@ pub unsafe extern "C" fn request_state_provisioning( shard, skip_ra, seal_handler, + client_account, ) { error!("Failed to sync state due to: {:?}", e); return e.into() @@ -225,6 +243,8 @@ pub unsafe extern "C" fn request_state_provisioning( } /// Internal [`request_state_provisioning`] function to be able to use the handy `?` operator. +// allowing clippy rant because this fn will be refactored with MU RA deprecation +#[allow(clippy::too_many_arguments)] pub(crate) fn request_state_provisioning_internal( socket_fd: c_int, sign_type: sgx_quote_sign_type_t, @@ -233,6 +253,7 @@ pub(crate) fn request_state_provisioning_internal EnclaveResult<()> { debug!("Client config generate..."); let client_config = tls_client_config( @@ -253,7 +274,7 @@ pub(crate) fn request_state_provisioning_internal( @@ -268,6 +289,7 @@ fn tls_client_config( #[cfg(feature = "dcap")] let attestation_type = RemoteAttestationType::Dcap; + // report will be signed with client enclave ed25519 signing key let (key_der, cert_der) = create_ra_report_and_signature( skip_ra, attestation_type, @@ -282,6 +304,7 @@ fn tls_client_config( let privkey = rustls::PrivateKey(key_der); cfg.set_single_client_cert(certs, privkey).unwrap(); + // ServerAuth will perform MU RA as part of authentication process cfg.dangerous() .set_certificate_verifier(Arc::new(ServerAuth::new(true, skip_ra, ocall_api))); cfg.versions.clear(); diff --git a/enclave-runtime/src/tls_ra/tls_ra_server.rs b/enclave-runtime/src/tls_ra/tls_ra_server.rs index e47ca50ed8..b03c1f59ae 100644 --- a/enclave-runtime/src/tls_ra/tls_ra_server.rs +++ b/enclave-runtime/src/tls_ra/tls_ra_server.rs @@ -17,7 +17,7 @@ //! Implementation of the server part of the state provisioning. -use super::{authentication::ClientAuth, Opcode, TcpHeader}; +use super::{authentication::ClientAuth, ClientProvisioningRequest, Opcode, TcpHeader}; use crate::{ attestation::create_ra_report_and_signature, error::{Error as EnclaveError, Result as EnclaveResult}, @@ -26,9 +26,11 @@ use crate::{ GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_KEY_REPOSITORY_COMPONENT, }, ocall::OcallApi, + shard_vault::add_shard_vault_proxy, tls_ra::seal_handler::UnsealStateAndKeys, GLOBAL_STATE_HANDLER_COMPONENT, }; +use codec::Decode; use itp_attestation_handler::RemoteAttestationType; use itp_component_container::ComponentGetter; use itp_ocall_api::EnclaveAttestationOCallApi; @@ -82,25 +84,43 @@ where } /// Sends all relevant data of the specific shard to the client. - fn write_shard(&mut self) -> EnclaveResult<()> { - println!(" [Enclave] (MU-RA-Server) write_shard, calling read_shard()"); - let shard = self.read_shard()?; - println!(" [Enclave] (MU-RA-Server) write_shard, read_shard() OK"); - println!(" [Enclave] (MU-RA-Server) write_shard, write_all()"); - self.write_all(&shard) + fn handle_shard_request_from_client(&mut self) -> EnclaveResult<()> { + println!( + " [Enclave] (MU-RA-Server) handle_shard_request_from_client, calling read_shard()" + ); + let request = self.await_shard_request_from_client()?; + println!(" [Enclave] (MU-RA-Server) handle_shard_request_from_client, await_shard_request_from_client() OK"); + println!(" [Enclave] (MU-RA-Server) handle_shard_request_from_client, write_all()"); + self.write_provisioning_payloads(&request.shard)?; + + info!( + "will make client account 0x{} a proxy of vault for shard {:?}", + hex::encode(request.account.clone()), + request.shard + ); + if let Err(e) = add_shard_vault_proxy(request.shard, &request.account) { + // we can't be sure that registering the proxy will succeed onchain at this point, + // therefore we can accept an error here as the client has to verify anyway and + // retry if it failed + error!("failed to add shard vault proxy for {:?}: {:?}", request.account, e); + }; + Ok(()) } /// Read the shard of the state the client wants to receive. - fn read_shard(&mut self) -> EnclaveResult { - let mut shard_holder = ShardIdentifier::default(); - let shard = shard_holder.as_fixed_bytes_mut(); - println!(" [Enclave] (MU-RA-Server) read_shard, calling read_exact()"); - self.tls_stream.read_exact(shard)?; - Ok(shard.into()) + fn await_shard_request_from_client(&mut self) -> EnclaveResult { + let mut request = [0u8; std::mem::size_of::()]; + println!( + " [Enclave] (MU-RA-Server) await_shard_request_from_client, calling read_exact()" + ); + self.tls_stream.read_exact(&mut request)?; + let request: ClientProvisioningRequest = Decode::decode(&mut request.as_slice()) + .expect("matching byte size can't fail to decode"); + Ok(request) } /// Sends all relevant data to the client. - fn write_all(&mut self, shard: &ShardIdentifier) -> EnclaveResult<()> { + fn write_provisioning_payloads(&mut self, shard: &ShardIdentifier) -> EnclaveResult<()> { debug!("Provisioning is set to: {:?}", self.provisioning_payload); match self.provisioning_payload { ProvisioningPayload::Everything => { @@ -248,14 +268,20 @@ pub(crate) fn run_state_provisioning_server_internal< skip_ra == 1, )?; let (server_session, tcp_stream) = tls_server_session_stream(socket_fd, server_config)?; + let provisioning = ProvisioningPayload::from(WorkerModeProvider::worker_mode()); let mut server = TlsServer::new(StreamOwned::new(server_session, tcp_stream), seal_handler, provisioning); + // todo: verify client signer belongs to a registered enclave on integritee network with a + // matching or whitelisted MRENCLAVE as replacement for MU RA #1385 + println!(" [Enclave] (MU-RA-Server) MU-RA successful sending keys"); - println!(" [Enclave] (MU-RA-Server) MU-RA successful, calling write_shard()"); - server.write_shard() + println!( + " [Enclave] (MU-RA-Server) MU-RA successful, calling handle_shard_request_from_client()" + ); + server.handle_shard_request_from_client() } fn tls_server_session_stream( @@ -279,6 +305,7 @@ fn tls_server_config( #[cfg(feature = "dcap")] let attestation_type = RemoteAttestationType::Dcap; + // report will be signed with server enclave ed25519 signing key let (key_der, cert_der) = create_ra_report_and_signature( skip_ra, attestation_type, @@ -287,6 +314,7 @@ fn tls_server_config( quote_size, )?; + // ClientAuth will perform MU RA as part of authentication process let mut cfg = rustls::ServerConfig::new(Arc::new(ClientAuth::new(true, skip_ra, ocall_api))); let certs = vec![rustls::Certificate(cert_der)]; let privkey = rustls::PrivateKey(key_der); diff --git a/enclave-runtime/src/top_pool_execution.rs b/enclave-runtime/src/top_pool_execution.rs index fbcad96947..7fc1dd1541 100644 --- a/enclave-runtime/src/top_pool_execution.rs +++ b/enclave-runtime/src/top_pool_execution.rs @@ -24,8 +24,8 @@ use crate::{ }, sync::{EnclaveLock, EnclaveStateRWLock}, utils::{ - get_extrinsic_factory_from_solo_or_parachain, get_stf_executor_from_solo_or_parachain, - get_triggered_dispatcher_from_solo_or_parachain, + get_extrinsic_factory_from_integritee_solo_or_parachain, + get_stf_executor_from_solo_or_parachain, get_triggered_dispatcher_from_solo_or_parachain, get_validator_accessor_from_solo_or_parachain, }, }; @@ -123,7 +123,7 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { let block_composer = GLOBAL_SIDECHAIN_BLOCK_COMPOSER_COMPONENT.get()?; - let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; diff --git a/enclave-runtime/src/utils.rs b/enclave-runtime/src/utils.rs index 7635385d7c..4c58da0d01 100644 --- a/enclave-runtime/src/utils.rs +++ b/enclave-runtime/src/utils.rs @@ -147,8 +147,8 @@ pub(crate) fn get_node_metadata_repository_from_target_b_solo_or_parachain( Ok(metadata_repository) } -pub(crate) fn get_extrinsic_factory_from_solo_or_parachain() -> Result> -{ +pub(crate) fn get_extrinsic_factory_from_integritee_solo_or_parachain( +) -> Result> { let extrinsics_factory = if let Ok(solochain_handler) = GLOBAL_INTEGRITEE_SOLOCHAIN_HANDLER_COMPONENT.get() { solochain_handler.extrinsics_factory.clone() diff --git a/service/src/main.rs b/service/src/main.rs index 3fd1f3401c..750ff83507 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -593,6 +593,24 @@ fn start_worker( println!("[!] Parentchain block syncing has terminated"); }) .unwrap(); + + if WorkerModeProvider::worker_mode() == WorkerMode::OffChainWorker { + info!("skipping shard vault check because not yet supported for offchain worker"); + } else if let Ok(shard_vault) = enclave.get_ecc_vault_pubkey(shard) { + println!( + "shard vault account is already initialized in state: {}", + shard_vault.to_ss58check() + ); + } else if we_are_primary_validateer { + println!("initializing proxied shard vault account now"); + enclave.init_proxied_shard_vault(shard).unwrap(); + println!( + "initialized shard vault account: : {}", + enclave.get_ecc_vault_pubkey(shard).unwrap().to_ss58check() + ); + } else { + panic!("no vault account has been initialized and we are not the primary worker"); + } } // ------------------------------------------------------------------------ diff --git a/service/src/ocall_bridge/bridge_api.rs b/service/src/ocall_bridge/bridge_api.rs index 9fc3e8eeff..e91ca8409a 100644 --- a/service/src/ocall_bridge/bridge_api.rs +++ b/service/src/ocall_bridge/bridge_api.rs @@ -213,6 +213,7 @@ pub trait WorkerOnChainBridge { &self, extrinsics_encoded: Vec, parentchain_id: Vec, + await_each_inclusion: bool, ) -> OCallBridgeResult<()>; } diff --git a/service/src/ocall_bridge/ffi/send_to_parentchain.rs b/service/src/ocall_bridge/ffi/send_to_parentchain.rs index d9e5220507..d7e524a254 100644 --- a/service/src/ocall_bridge/ffi/send_to_parentchain.rs +++ b/service/src/ocall_bridge/ffi/send_to_parentchain.rs @@ -18,7 +18,7 @@ use crate::ocall_bridge::bridge_api::{Bridge, WorkerOnChainBridge}; use log::*; -use sgx_types::sgx_status_t; +use sgx_types::{c_int, sgx_status_t}; use std::{slice, sync::Arc, vec::Vec}; /// # Safety @@ -30,12 +30,14 @@ pub unsafe extern "C" fn ocall_send_to_parentchain( extrinsics_encoded_size: u32, parentchain_id: *const u8, parentchain_id_size: u32, + await_each_inclusion: c_int, ) -> sgx_status_t { send_to_parentchain( extrinsics_encoded, extrinsics_encoded_size, parentchain_id, parentchain_id_size, + await_each_inclusion == 1, Bridge::get_oc_api(), ) } @@ -45,6 +47,7 @@ fn send_to_parentchain( extrinsics_encoded_size: u32, parentchain_id: *const u8, parentchain_id_size: u32, + await_each_inclusion: bool, oc_api: Arc, ) -> sgx_status_t { let extrinsics_encoded_vec: Vec = unsafe { @@ -54,7 +57,7 @@ fn send_to_parentchain( let parentchain_id: Vec = unsafe { Vec::from(slice::from_raw_parts(parentchain_id, parentchain_id_size as usize)) }; - match oc_api.send_to_parentchain(extrinsics_encoded_vec, parentchain_id) { + match oc_api.send_to_parentchain(extrinsics_encoded_vec, parentchain_id, await_each_inclusion) { Ok(_) => sgx_status_t::SGX_SUCCESS, Err(e) => { error!("send extrinsics_encoded failed: {:?}", e); diff --git a/service/src/ocall_bridge/worker_on_chain_ocall.rs b/service/src/ocall_bridge/worker_on_chain_ocall.rs index 4fec834a7f..f322c6337f 100644 --- a/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -24,7 +24,9 @@ use itp_types::{parentchain::ParentchainId, WorkerRequest, WorkerResponse}; use log::*; use sp_runtime::OpaqueExtrinsic; use std::{sync::Arc, vec::Vec}; -use substrate_api_client::{ac_primitives::serde_impls::StorageKey, GetStorage, SubmitExtrinsic}; +use substrate_api_client::{ + ac_primitives::serde_impls::StorageKey, GetStorage, SubmitAndWatch, SubmitExtrinsic, XtStatus, +}; pub struct WorkerOnChainOCall { integritee_api_factory: Arc, @@ -107,6 +109,7 @@ where &self, extrinsics_encoded: Vec, parentchain_id: Vec, + await_each_inlcusion: bool, ) -> OCallBridgeResult<()> { // TODO: improve error handling, using a mut status is not good design? let mut status: OCallBridgeResult<()> = Ok(()); @@ -125,13 +128,24 @@ where if !extrinsics.is_empty() { let parentchain_id = ParentchainId::decode(&mut parentchain_id.as_slice())?; debug!( - "Enclave wants to send {} extrinsics to parentchain: {:?}", + "Enclave wants to send {} extrinsics to parentchain: {:?}. await each inclusion: {:?}", extrinsics.len(), - parentchain_id + parentchain_id, await_each_inlcusion ); let api = self.create_api(parentchain_id)?; for call in extrinsics.into_iter() { - if let Err(e) = api.submit_opaque_extrinsic(&call.encode().into()) { + if await_each_inlcusion { + if let Err(e) = api.submit_and_watch_opaque_extrinsic_until( + &call.encode().into(), + XtStatus::InBlock, + ) { + error!( + "Could not send extrinsic to node: {:?}, error: {:?}", + serde_json::to_string(&call), + e + ); + } + } else if let Err(e) = api.submit_opaque_extrinsic(&call.encode().into()) { error!( "Could not send extrinsic to node: {:?}, error: {:?}", serde_json::to_string(&call), @@ -140,7 +154,6 @@ where } } } - status } } diff --git a/service/src/tests/mocks/enclave_api_mock.rs b/service/src/tests/mocks/enclave_api_mock.rs index 7c93116273..bb7d47acde 100644 --- a/service/src/tests/mocks/enclave_api_mock.rs +++ b/service/src/tests/mocks/enclave_api_mock.rs @@ -25,6 +25,7 @@ use itc_parentchain::primitives::{ use itp_enclave_api::{enclave_base::EnclaveBase, sidechain::Sidechain, EnclaveResult}; use itp_settings::worker::MR_ENCLAVE_SIZE; use itp_storage::StorageProof; +use itp_types::ShardIdentifier; use sgx_crypto_helper::rsa3072::Rsa3072PubKey; use sp_core::ed25519; @@ -60,6 +61,10 @@ impl EnclaveBase for EnclaveMock { unimplemented!() } + fn init_proxied_shard_vault(&self, _shard: &ShardIdentifier) -> EnclaveResult<()> { + unimplemented!() + } + fn trigger_parentchain_block_import(&self, _: &ParentchainId) -> EnclaveResult<()> { unimplemented!() } @@ -80,6 +85,10 @@ impl EnclaveBase for EnclaveMock { unreachable!() } + fn get_ecc_vault_pubkey(&self, shard: &ShardIdentifier) -> EnclaveResult { + unreachable!() + } + fn get_fingerprint(&self) -> EnclaveResult { Ok([1u8; MR_ENCLAVE_SIZE].into()) }