diff --git a/Cargo.lock b/Cargo.lock index 54d5cddabd..b085c696ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2839,6 +2839,7 @@ dependencies = [ "parse_duration", "primitive-types", "prometheus", + "regex 1.9.5", "scale-info", "serde 1.0.188", "serde_derive 1.0.188", @@ -3892,6 +3893,7 @@ dependencies = [ "itp-time-utils", "itp-top-pool-author", "itp-types", + "itp-utils", "its-block-composer", "its-block-verification", "its-consensus-common", diff --git a/app-libs/parentchain-interface/src/integritee/event_handler.rs b/app-libs/parentchain-interface/src/integritee/event_handler.rs index 3711b861c0..198a4cad0e 100644 --- a/app-libs/parentchain-interface/src/integritee/event_handler.rs +++ b/app-libs/parentchain-interface/src/integritee/event_handler.rs @@ -69,8 +69,9 @@ where .filter(|&event| event.to == *vault_account) .try_for_each(|event| { info!("found transfer_event to vault account: {}", event); - //call = IndirectCall::ShieldFunds(ShieldFundsArgs{ }) + //debug!("shielding from Integritee suppressed"); Self::shield_funds(executor, &event.from, event.amount) + //Err(ParentchainError::FunctionalityDisabled) }) .map_err(|_| ParentchainError::ShieldFundsFailure)?; } diff --git a/app-libs/parentchain-interface/src/lib.rs b/app-libs/parentchain-interface/src/lib.rs index b1aff31ade..2aa70c6447 100644 --- a/app-libs/parentchain-interface/src/lib.rs +++ b/app-libs/parentchain-interface/src/lib.rs @@ -22,6 +22,7 @@ extern crate sgx_tstd as std; use codec::Decode; + pub mod indirect_calls; pub mod integritee; pub mod target_a; diff --git a/app-libs/parentchain-interface/src/target_a/event_handler.rs b/app-libs/parentchain-interface/src/target_a/event_handler.rs index 96cd3997ec..fc45a996b4 100644 --- a/app-libs/parentchain-interface/src/target_a/event_handler.rs +++ b/app-libs/parentchain-interface/src/target_a/event_handler.rs @@ -15,27 +15,64 @@ */ +use codec::Encode; pub use ita_sgx_runtime::{Balance, Index}; -use ita_stf::TrustedCallSigned; +use ita_stf::{Getter, TrustedCall, TrustedCallSigned}; use itc_parentchain_indirect_calls_executor::error::Error; -use itp_stf_primitives::traits::IndirectExecutor; -use itp_types::parentchain::{AccountId, FilterEvents, HandleParentchainEvents}; +use itp_stf_primitives::{traits::IndirectExecutor, types::TrustedOperation}; +use itp_types::parentchain::{AccountId, FilterEvents, HandleParentchainEvents, ParentchainError}; +use itp_utils::hex::hex_encode; use log::*; pub struct ParentchainEventHandler {} +impl ParentchainEventHandler { + fn shield_funds>( + executor: &Executor, + account: &AccountId, + amount: Balance, + ) -> Result<(), Error> { + trace!("[TargetA] shielding for {:?} amount {}", account, amount,); + let shard = executor.get_default_shard(); + let trusted_call = + TrustedCall::balance_shield(executor.get_enclave_account()?, account.clone(), amount); + let signed_trusted_call = executor.sign_call_with_self(&trusted_call, &shard)?; + let trusted_operation = + TrustedOperation::::indirect_call(signed_trusted_call); + + let encrypted_trusted_call = executor.encrypt(&trusted_operation.encode())?; + executor.submit_trusted_call(shard, encrypted_trusted_call); + + Ok(()) + } +} + impl HandleParentchainEvents for ParentchainEventHandler where Executor: IndirectExecutor, { fn handle_events( - _executor: &Executor, - _events: impl FilterEvents, - _vault_account: &AccountId, + executor: &Executor, + events: impl FilterEvents, + vault_account: &AccountId, ) -> Result<(), Error> { - debug!("not handling any events for target A"); + let filter_events = events.get_transfer_events(); + trace!( + "[TargetA] filtering transfer events to shard vault account: {}", + hex_encode(vault_account.encode().as_slice()) + ); + if let Ok(events) = filter_events { + events + .iter() + .filter(|&event| event.to == *vault_account) + .try_for_each(|event| { + std::println!("⣿TargetA⣿ 🛡 found transfer event to shard vault account: {} will shield to {}", event.amount, hex_encode(event.from.encode().as_ref())); + Self::shield_funds(executor, &event.from, event.amount) + }) + .map_err(|_| ParentchainError::ShieldFundsFailure)?; + } Ok(()) } } diff --git a/app-libs/parentchain-interface/src/target_a/mod.rs b/app-libs/parentchain-interface/src/target_a/mod.rs index e26d2e45c0..f35ca54159 100644 --- a/app-libs/parentchain-interface/src/target_a/mod.rs +++ b/app-libs/parentchain-interface/src/target_a/mod.rs @@ -37,7 +37,7 @@ use itc_parentchain_indirect_calls_executor::{ }; use itp_node_api::metadata::pallet_balances::BalancesCallIndexes; use itp_stf_primitives::traits::IndirectExecutor; -use log::trace; +use log::{debug, trace}; /// The default indirect call (extrinsic-triggered) of the Target-A-Parachain. #[derive(Debug, Clone, Encode, Decode, Eq, PartialEq)] @@ -48,11 +48,16 @@ pub enum IndirectCall { impl> IndirectDispatch for IndirectCall { - fn dispatch(&self, executor: &Executor) -> Result<()> { + fn dispatch(&self, _executor: &Executor) -> Result<()> { + debug!("shielding from TargetA extrinsic to Alice suppressed"); + /* trace!("dispatching indirect call {:?}", self); match self { IndirectCall::TransferToAliceShieldsFunds(args) => args.dispatch(executor), } + + */ + Ok(()) } } @@ -89,19 +94,17 @@ where }; let index = xt.call_index; let call_args = &mut &xt.call_args[..]; - log::trace!("[TransferToAliceShieldsFundsFilter] attempting to execute indirect call with index {:?}", index); + trace!("[TransferToAliceShieldsFundsFilter] attempting to execute indirect call with index {:?}", index); 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` or `transfer_keep_alive` call." - ); + 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)) } else { - log::debug!("Parentchain transfer was not for Alice; ignoring..."); + debug!("Parentchain transfer extrinsic was not for Alice; ignoring..."); // No need to put it into the top pool if it isn't executed in the first place. None } diff --git a/app-libs/sgx-runtime/src/lib.rs b/app-libs/sgx-runtime/src/lib.rs index 124ee255da..7f55c972cb 100644 --- a/app-libs/sgx-runtime/src/lib.rs +++ b/app-libs/sgx-runtime/src/lib.rs @@ -71,7 +71,7 @@ pub use frame_support::{ StorageValue, }; pub use pallet_balances::Call as BalancesCall; -pub use pallet_parentchain::Call as ParentchainCall; +pub use pallet_parentchain::Call as ParentchainPalletCall; pub use pallet_timestamp::Call as TimestampCall; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; diff --git a/app-libs/stf/src/getter.rs b/app-libs/stf/src/getter.rs index 23b9728019..77fe561e05 100644 --- a/app-libs/stf/src/getter.rs +++ b/app-libs/stf/src/getter.rs @@ -171,7 +171,7 @@ impl ExecuteGetter for TrustedGetterSigned { let info = System::account(&who); debug!("TrustedGetter free_balance"); debug!("AccountInfo for {} is {:?}", account_id_to_string(&who), info); - debug!("Account free balance is {}", info.data.free); + std::println!("⣿STF⣿ 🔍 TrustedGetter query: free balance for ⣿⣿⣿ is ⣿⣿⣿",); Some(info.data.free.encode()) }, TrustedGetter::reserved_balance(who) => { diff --git a/app-libs/stf/src/lib.rs b/app-libs/stf/src/lib.rs index 9a82d905fc..4b53d32148 100644 --- a/app-libs/stf/src/lib.rs +++ b/app-libs/stf/src/lib.rs @@ -44,3 +44,6 @@ pub mod test_genesis; pub mod trusted_call; pub(crate) const ENCLAVE_ACCOUNT_KEY: &str = "Enclave_Account_Key"; + +// fixme: this if a temporary hack only +pub const STF_TX_FEE: Balance = 100000000; diff --git a/app-libs/stf/src/stf_sgx.rs b/app-libs/stf/src/stf_sgx.rs index 2257dc6dc0..0eb5140d50 100644 --- a/app-libs/stf/src/stf_sgx.rs +++ b/app-libs/stf/src/stf_sgx.rs @@ -31,10 +31,7 @@ use itp_stf_interface::{ }; use itp_stf_primitives::{error::StfError, traits::TrustedCallVerification}; use itp_storage::storage_value_key; -use itp_types::{ - parentchain::{AccountId, ParentchainId}, - OpaqueCall, -}; +use itp_types::parentchain::{AccountId, ParentchainCall, ParentchainId}; use itp_utils::stringify::account_id_to_string; use log::*; use sp_runtime::traits::StaticLookup; @@ -147,7 +144,7 @@ where fn execute_call( state: &mut State, call: TCS, - calls: &mut Vec, + calls: &mut Vec, node_metadata_repo: Arc, ) -> Result<(), Self::Error> { state.execute_with(|| call.execute(calls, node_metadata_repo)) diff --git a/app-libs/stf/src/test_genesis.rs b/app-libs/stf/src/test_genesis.rs index d65cdef41e..161dec8e5e 100644 --- a/app-libs/stf/src/test_genesis.rs +++ b/app-libs/stf/src/test_genesis.rs @@ -42,9 +42,9 @@ const ENDOWED_SEED: Seed = *b"12345678901234567890123456789012"; const SECOND_ENDOWED_SEED: Seed = *b"22345678901234567890123456789012"; const UNENDOWED_SEED: Seed = *b"92345678901234567890123456789012"; -const ALICE_FUNDS: Balance = 1000000000000000; -pub const ENDOWED_ACC_FUNDS: Balance = 2000; -pub const SECOND_ENDOWED_ACC_FUNDS: Balance = 1000; +const ALICE_FUNDS: Balance = 10_000_000_000_000_000; +pub const ENDOWED_ACC_FUNDS: Balance = 2_000_000_000_000; +pub const SECOND_ENDOWED_ACC_FUNDS: Balance = 1_000_000_000_000; pub fn endowed_account() -> ed25519::Pair { ed25519::Pair::from_seed(&ENDOWED_SEED) diff --git a/app-libs/stf/src/trusted_call.rs b/app-libs/stf/src/trusted_call.rs index 75b73581f2..eba525d34a 100644 --- a/app-libs/stf/src/trusted_call.rs +++ b/app-libs/stf/src/trusted_call.rs @@ -24,7 +24,7 @@ use std::vec::Vec; #[cfg(feature = "evm")] use crate::evm_helpers::{create_code_hash, evm_create2_address, evm_create_address}; use crate::{ - helpers::{ensure_enclave_signer_account, get_storage_by_key_hash}, + helpers::{enclave_signer_account, ensure_enclave_signer_account, get_storage_by_key_hash}, Getter, }; use codec::{Compact, Decode, Encode}; @@ -44,7 +44,10 @@ use itp_stf_primitives::{ traits::{TrustedCallSigning, TrustedCallVerification}, types::{AccountId, KeyPair, ShardIdentifier, Signature, TrustedOperation}, }; -use itp_types::{parentchain::ProxyType, Address, OpaqueCall}; +use itp_types::{ + parentchain::{ParentchainCall, ProxyType}, + Address, OpaqueCall, +}; use itp_utils::stringify::account_id_to_string; use log::*; use sp_core::{ @@ -214,7 +217,7 @@ where fn execute( self, - calls: &mut Vec, + calls: &mut Vec, node_metadata_repo: Arc, ) -> Result<(), Self::Error> { let sender = self.call.sender_account().clone(); @@ -259,12 +262,26 @@ where }, TrustedCall::balance_transfer(from, to, value) => { let origin = ita_sgx_runtime::RuntimeOrigin::signed(from.clone()); - debug!( - "balance_transfer({}, {}, {})", + std::println!("⣿STF⣿ 🔄 balance_transfer from ⣿⣿⣿ to ⣿⣿⣿ amount ⣿⣿⣿"); + // endow fee to enclave (self) + let fee_recipient: AccountId = enclave_signer_account(); + // fixme: apply fees through standard frame process and tune it + let fee = crate::STF_TX_FEE; + info!( + "from {}, to {}, amount {}, fee {}", account_id_to_string(&from), account_id_to_string(&to), - value + value, + fee ); + ita_sgx_runtime::BalancesCall::::transfer { + dest: MultiAddress::Id(fee_recipient), + value: fee, + } + .dispatch_bypass_filter(origin.clone()) + .map_err(|e| { + Self::Error::Dispatch(format!("Balance Transfer error: {:?}", e.error)) + })?; ita_sgx_runtime::BalancesCall::::transfer { dest: MultiAddress::Id(to), value, @@ -276,28 +293,36 @@ where Ok(()) }, TrustedCall::balance_unshield(account_incognito, beneficiary, value, shard) => { - debug!( - "balance_unshield({}, {}, {}, {})", + std::println!( + "⣿STF⣿ 🛡👐 balance_unshield from ⣿⣿⣿ to {}, amount {}", + account_id_to_string(&beneficiary), + value + ); + // endow fee to enclave (self) + let fee_recipient: AccountId = enclave_signer_account(); + // fixme: apply fees through standard frame process and tune it. has to be at least two L1 transfer's fees + let fee = crate::STF_TX_FEE * 3; + + info!( + "balance_unshield(from (L2): {}, to (L1): {}, amount {} (+fee: {}), shard {})", account_id_to_string(&account_incognito), account_id_to_string(&beneficiary), value, + fee, shard ); - unshield_funds(account_incognito, value)?; - calls.push(OpaqueCall::from_tuple(&( - node_metadata_repo - .get_from_metadata(|m| m.unshield_funds_call_indexes()) - .map_err(|_| StfError::InvalidMetadata)? - .map_err(|_| StfError::InvalidMetadata)?, - shard, - 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 origin = ita_sgx_runtime::RuntimeOrigin::signed(account_incognito.clone()); + ita_sgx_runtime::BalancesCall::::transfer { + dest: MultiAddress::Id(fee_recipient), + value: fee, + } + .dispatch_bypass_filter(origin) + .map_err(|e| { + Self::Error::Dispatch(format!("Balance Unshielding error: {:?}", e.error)) + })?; + burn_funds(account_incognito, value)?; + 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()) @@ -320,7 +345,7 @@ where None::, vault_transfer_call, )); - calls.push(proxy_call); + calls.push(ParentchainCall::TargetA(proxy_call)); Ok(()) }, TrustedCall::balance_shield(enclave_account, who, value) => { @@ -329,7 +354,7 @@ where shield_funds(who, value)?; // Send proof of execution on chain. - calls.push(OpaqueCall::from_tuple(&( + calls.push(ParentchainCall::Integritee(OpaqueCall::from_tuple(&( node_metadata_repo .get_from_metadata(|m| m.publish_hash_call_indexes()) .map_err(|_| StfError::InvalidMetadata)? @@ -337,7 +362,7 @@ where call_hash, Vec::::new(), b"shielded some funds!".to_vec(), - ))); + )))); Ok(()) }, #[cfg(feature = "evm")] @@ -476,7 +501,7 @@ where } } -fn unshield_funds(account: AccountId, amount: u128) -> Result<(), StfError> { +fn burn_funds(account: AccountId, amount: u128) -> Result<(), StfError> { let account_info = System::account(&account); if account_info.data.free < amount { return Err(StfError::MissingFunds) @@ -487,15 +512,30 @@ fn unshield_funds(account: AccountId, amount: u128) -> Result<(), StfError> { new_free: account_info.data.free - amount, } .dispatch_bypass_filter(ita_sgx_runtime::RuntimeOrigin::root()) - .map_err(|e| StfError::Dispatch(format!("Unshield funds error: {:?}", e.error)))?; + .map_err(|e| StfError::Dispatch(format!("Burn funds error: {:?}", e.error)))?; Ok(()) } fn shield_funds(account: AccountId, amount: u128) -> Result<(), StfError> { + //fixme: make fee configurable and send fee to vault account on L2 + let fee = amount / 571; // approx 0.175% + + // endow fee to enclave (self) + let fee_recipient: AccountId = enclave_signer_account(); + + let account_info = System::account(&fee_recipient); + ita_sgx_runtime::BalancesCall::::force_set_balance { + who: MultiAddress::Id(fee_recipient), + new_free: account_info.data.free + fee, + } + .dispatch_bypass_filter(ita_sgx_runtime::RuntimeOrigin::root()) + .map_err(|e| StfError::Dispatch(format!("Shield funds error: {:?}", e.error)))?; + + // endow shieding amount - fee to beneficiary let account_info = System::account(&account); ita_sgx_runtime::BalancesCall::::force_set_balance { who: MultiAddress::Id(account), - new_free: account_info.data.free + amount, + new_free: account_info.data.free + amount - fee, } .dispatch_bypass_filter(ita_sgx_runtime::RuntimeOrigin::root()) .map_err(|e| StfError::Dispatch(format!("Shield funds error: {:?}", e.error)))?; diff --git a/cli/demo_shielding_unshielding.sh b/cli/demo_shielding_unshielding.sh index e65a749258..549d83a87f 100755 --- a/cli/demo_shielding_unshielding.sh +++ b/cli/demo_shielding_unshielding.sh @@ -70,6 +70,7 @@ echo "" # the parentchain token is 12 decimal UNIT=$(( 10 ** 12 )) +FEE_TOLERANCE=$((10 ** 11)) # make these amounts greater than ED AMOUNT_SHIELD=$(( 6 * UNIT )) @@ -100,14 +101,14 @@ function wait_assert_state() for i in $(seq 1 $WAIT_ROUNDS); do sleep $WAIT_INTERVAL_SECONDS state=$(${CLIENT} trusted --mrenclave "$1" "$3" "$2") - if [ $state -eq "$4" ]; then + if (( $4 >= state ? $4 - state < FEE_TOLERANCE : state - $4 < FEE_TOLERANCE)); then return else : fi done echo - echo "Assert $2 $3 failed, expected = $4, actual = $state" + echo "Assert $2 $3 failed, expected = $4, actual = $state, tolerance = $FEE_TOLERANCE" exit 1 } diff --git a/cli/demo_shielding_unshielding_using_shard_vault.sh b/cli/demo_shielding_unshielding_using_shard_vault.sh index 128a2fa162..9b4943dc2e 100755 --- a/cli/demo_shielding_unshielding_using_shard_vault.sh +++ b/cli/demo_shielding_unshielding_using_shard_vault.sh @@ -70,6 +70,7 @@ echo "" # the parentchain token is 12 decimal UNIT=$(( 10 ** 12 )) +FEE_TOLERANCE=$((10 ** 11)) # make these amounts greater than ED AMOUNT_SHIELD=$(( 6 * UNIT )) @@ -101,14 +102,14 @@ function wait_assert_state() for i in $(seq 1 $WAIT_ROUNDS); do sleep $WAIT_INTERVAL_SECONDS state=$(${CLIENT} trusted --mrenclave "$1" "$3" "$2") - if [ $state -eq "$4" ]; then + if (( $4 >= state ? $4 - state < FEE_TOLERANCE : state - $4 < FEE_TOLERANCE)); then return else : fi done echo - echo "Assert $2 $3 failed, expected = $4, actual = $state" + echo "Assert $2 $3 failed, expected = $4, actual = $state, tolerance = $FEE_TOLERANCE" exit 1 } diff --git a/cli/demo_shielding_unshielding_using_shard_vault_on_target_a.sh b/cli/demo_shielding_unshielding_using_shard_vault_on_target_a.sh new file mode 100755 index 0000000000..9ccf34c84d --- /dev/null +++ b/cli/demo_shielding_unshielding_using_shard_vault_on_target_a.sh @@ -0,0 +1,302 @@ +#!/bin/bash + +# to make sure the script aborts when (sub-)function exits abnormally +set -e + +# Demonstrates how to shield tokens from the parentchain into the sidechain. +# +# setup: +# run all on localhost: +# integritee-node purge-chain --dev +# integritee-node --dev -lruntime=debug +# rm light_client_db.bin +# export RUST_LOG=integritee_service=info,ita_stf=debug +# integritee-service init_shard +# integritee-service shielding-key +# integritee-service signing-key +# integritee-service run +# +# then run this script + +# usage: +# demo_shielding_unshielding.sh -p -P -t -m file +# +# TEST_BALANCE_RUN is either "first" or "second" +# if -m file is set, the mrenclave will be read from file + +while getopts ":m:p:P:t:u:V:C:a:A:" opt; do + case $opt in + t) + TEST=$OPTARG + ;; + m) + READ_MRENCLAVE=$OPTARG + ;; + p) + INTEGRITEE_RPC_PORT=$OPTARG + ;; + a) + TARGET_A_RPC_PORT=$OPTARG + ;; + P) + WORKER_1_PORT=$OPTARG + ;; + u) + INTEGRITEE_RPC_URL=$OPTARG + ;; + A) + TARGET_A_RPC_URL=$OPTARG + ;; + V) + WORKER_1_URL=$OPTARG + ;; + C) + CLIENT_BIN=$OPTARG + ;; + *) + echo "invalid arg ${OPTARG}" + exit 1 + esac +done + +# Using default port if none given as arguments. +INTEGRITEE_RPC_PORT=${INTEGRITEE_RPC_PORT:-9944} +INTEGRITEE_RPC_URL=${INTEGRITEE_RPC_URL:-"ws://127.0.0.1"} + +TARGET_A_RPC_PORT=${TARGET_A_RPC_PORT:-9954} +TARGET_A_RPC_URL=${TARGET_A_RPC_URL:-"ws://127.0.0.1"} + +WORKER_1_PORT=${WORKER_1_PORT:-2000} +WORKER_1_URL=${WORKER_1_URL:-"wss://127.0.0.1"} + +CLIENT_BIN=${CLIENT_BIN:-"./../bin/integritee-cli"} + +echo "Using client binary ${CLIENT_BIN}" +${CLIENT_BIN} --version +echo "Using integritee node uri ${INTEGRITEE_RPC_URL}:${INTEGRITEE_RPC_PORT}" +echo "Using target_a node uri ${TARGET_A_RPC_URL}:${TARGET_A_RPC_PORT}" +echo "Using trusted-worker uri ${WORKER_1_URL}:${WORKER_1_PORT}" +echo "" + +# the parentchain token is 12 decimal +UNIT=$(( 10 ** 12 )) +FEE_TOLERANCE=$((10 ** 11)) + +# make these amounts greater than ED +AMOUNT_SHIELD=$(( 6 * UNIT )) +AMOUNT_TRANSFER=$(( 2 * UNIT )) +AMOUNT_UNSHIELD=$(( 1 * UNIT )) + +CLIENT="${CLIENT_BIN} -p ${INTEGRITEE_RPC_PORT} -P ${WORKER_1_PORT} -u ${INTEGRITEE_RPC_URL} -U ${WORKER_1_URL}" + +# for talking to TARGET_A L1 +CLIENT_A="${CLIENT_BIN} -p ${TARGET_A_RPC_PORT} -P ${WORKER_1_PORT} -u ${TARGET_A_RPC_URL} -U ${WORKER_1_URL}" + +# offchain-worker only suppports indirect calls +CALLTYPE= +case "$FLAVOR_ID" in + sidechain) CALLTYPE="--direct" ;; + offchain-worker) : ;; + *) CALLTYPE="--direct" ;; +esac +echo "using call type: ${CALLTYPE} (empty means indirect)" + +# interval and max rounds to wait to check the given account balance in sidechain +WAIT_INTERVAL_SECONDS=6 +WAIT_ROUNDS=20 + +# Poll and assert the given account's state is equal to expected, +# with timeout WAIT_INTERVAL_SECONDS * WAIT_ROUNDS +# usage: +# wait_assert_state +# the `state-name` has to be the supported subcommand, e.g. `balance`, `nonce` +function wait_assert_state() +{ + for i in $(seq 1 $WAIT_ROUNDS); do + sleep $WAIT_INTERVAL_SECONDS + state=$(${CLIENT} trusted --mrenclave "$1" "$3" "$2") + if (( $4 >= state ? $4 - state < FEE_TOLERANCE : state - $4 < FEE_TOLERANCE)); then + return + else + echo -n "." + fi + done + echo + echo "Assert $2 $3 failed, expected = $4, actual = $state, tolerance = $FEE_TOLERANCE" + exit 1 +} + +function wait_assert_state_target_a() +{ + for i in $(seq 1 $WAIT_ROUNDS); do + sleep $WAIT_INTERVAL_SECONDS + state=$(${CLIENT_A} "$2" "$1") + if (( $4 >= state ? $4 - state < FEE_TOLERANCE : state - $4 < FEE_TOLERANCE)); then + return + else + echo -n "." + fi + done + echo + echo "Assert $2 $3 failed, expected = $4, actual = $state, tolerance = $FEE_TOLERANCE" + exit 1 +} +# Do a live query and assert the given account's state is equal to expected +# usage: +# assert_state +function assert_state() +{ + state=$(${CLIENT} trusted --mrenclave "$1" "$3" "$2") + if [ -z "$state" ]; then + echo "Query $2 $3 failed" + exit 1 + fi + + if [ $state -eq "$4" ]; then + return + fi + echo + echo "Assert $2 $3 failed, expected = $4, actual = $state" + exit 1 +} + +echo "* Query on-chain enclave registry:" +${CLIENT} list-workers +echo "" + +if [ "$READ_MRENCLAVE" = "file" ] +then + read MRENCLAVE <<< $(cat ~/mrenclave.b58) + echo "Reading MRENCLAVE from file: ${MRENCLAVE}" +else + # this will always take the first MRENCLAVE found in the registry !! + read MRENCLAVE <<< $($CLIENT list-workers | awk '/ MRENCLAVE: / { print $2; exit }') + echo "Reading MRENCLAVE from worker list: ${MRENCLAVE}" +fi +[[ -z $MRENCLAVE ]] && { echo "MRENCLAVE is empty. cannot continue" ; exit 1; } + + +echo "* Create a new incognito account for Bob" +ICGACCOUNTBOB=$(${CLIENT} trusted --mrenclave ${MRENCLAVE} new-account) +echo " Bob's incognito account = ${ICGACCOUNTBOB}" +echo "" + +echo "* Query shard vault account" +VAULT=$(${CLIENT} trusted get-shard-vault) +echo " shard vault account = ${VAULT}" +echo "" + +# Asssert the initial balance of Charlie incognito +# The initial balance of Bob incognito should always be 0, as Bob is newly created +BALANCE_INCOGNITO_CHARLIE=0 +BALANCE_A_FERDIE=$(${CLIENT_A} balance //Ferdie) + +case $TEST in + first) + wait_assert_state ${MRENCLAVE} //Charlie balance 0 ;; + second) + wait_assert_state ${MRENCLAVE} //Charlie balance $(( AMOUNT_SHIELD - AMOUNT_TRANSFER - AMOUNT_UNSHIELD )) + BALANCE_INCOGNITO_CHARLIE=$(( AMOUNT_SHIELD - AMOUNT_TRANSFER - AMOUNT_UNSHIELD )) ;; + *) + echo "assuming first run of test" + wait_assert_state ${MRENCLAVE} //Charlie balance 0 ;; +esac + +echo "* Shield ${AMOUNT_SHIELD} tokens from TARGET_A to Charlie's account on L2" +${CLIENT_A} transfer //Alice //Charlie $((AMOUNT_SHIELD * 2)) +${CLIENT_A} transfer //Charlie ${VAULT} ${AMOUNT_SHIELD} +echo "" + +echo "* Wait and assert Charlie's L2 account balance... " +wait_assert_state ${MRENCLAVE} //Charlie balance $(( BALANCE_INCOGNITO_CHARLIE + AMOUNT_SHIELD )) +echo "✔ ok" + +echo "* Wait and assert Bob's incognito account balance... " +wait_assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} balance 0 +echo "✔ ok" +echo "" + +echo "* Send ${AMOUNT_TRANSFER} funds from Charlie's L2 account to Bob's incognito account" +$CLIENT trusted $CALLTYPE --mrenclave ${MRENCLAVE} transfer //Charlie ${ICGACCOUNTBOB} ${AMOUNT_TRANSFER} +echo "" + +echo "* Wait and assert Charlie's L2 account balance... " +wait_assert_state ${MRENCLAVE} //Charlie balance $(( BALANCE_INCOGNITO_CHARLIE + AMOUNT_SHIELD - AMOUNT_TRANSFER )) +echo "✔ ok" + +echo "* Wait and assert Bob's incognito account balance... " +wait_assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} balance ${AMOUNT_TRANSFER} +echo "✔ ok" +echo "" + +echo "* Un-shield ${AMOUNT_UNSHIELD} tokens from Charlie's incognito account to Ferie's L1 account" +${CLIENT} trusted $CALLTYPE --mrenclave ${MRENCLAVE} unshield-funds //Charlie //Ferdie ${AMOUNT_UNSHIELD} +echo "" + +echo "* Wait and assert Charlie's incognito account balance... " +wait_assert_state ${MRENCLAVE} //Charlie balance $(( BALANCE_INCOGNITO_CHARLIE + AMOUNT_SHIELD - AMOUNT_TRANSFER - AMOUNT_UNSHIELD )) +echo "✔ ok" + +echo "* Wait and assert Ferdie's Target A account balance... " +wait_assert_state_target_a //Ferdie balance $(( BALANCE_A_FERDIE + AMOUNT_UNSHIELD )) +echo "✔ ok" + +echo "* Wait and assert Bob's incognito account balance... " +wait_assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} balance ${AMOUNT_TRANSFER} +echo "✔ ok" + +# Test the nonce handling, using Bob's incognito account as the sender as Charlie's +# balance needs to be verified in the second round while Bob is newly created each time + +echo "* Create a new incognito account for Charlie" +ICGACCOUNTCHARLIE=$(${CLIENT} trusted --mrenclave ${MRENCLAVE} new-account) +echo " Charlie's incognito account = ${ICGACCOUNTCHARLIE}" +echo "" + + +echo "* Assert Bob's incognito initial nonce..." +assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} nonce 0 +echo "✔ ok" +echo "" + +echo "* Send 3 consecutive 0.2 UNIT balance Transfer Bob -> Charlie" +for i in $(seq 1 3); do + # use direct calls so they are submitted to the top pool synchronously + $CLIENT trusted $CALLTYPE --mrenclave ${MRENCLAVE} transfer ${ICGACCOUNTBOB} ${ICGACCOUNTCHARLIE} $(( AMOUNT_TRANSFER / 10 )) +done +echo "" + +echo "* Assert Bob's incognito current nonce..." +wait_assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} nonce 3 +echo "✔ ok" +echo "" + +echo "* Send a 2 UNIT balance Transfer Bob -> Charlie (that will fail)" +$CLIENT trusted $CALLTYPE --mrenclave ${MRENCLAVE} transfer ${ICGACCOUNTBOB} ${ICGACCOUNTCHARLIE} ${AMOUNT_TRANSFER} +echo "" + +echo "* Assert Bob's incognito nonce..." +# the nonce should be increased nontheless, even for the failed tx +wait_assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} nonce 4 +echo "✔ ok" +echo "" + +echo "* Send another 0.2 UNIT balance Transfer Bob -> Charlie" +$CLIENT trusted $CALLTYPE --mrenclave ${MRENCLAVE} transfer ${ICGACCOUNTBOB} ${ICGACCOUNTCHARLIE} $(( AMOUNT_TRANSFER / 10 )) +echo "" + +echo "* Assert Bob's incognito nonce..." +wait_assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} nonce 5 +echo "✔ ok" +echo "" + +echo "* Wait and assert Bob's incognito account balance... " +# in total 4 balance transfer should go through => 1.2 UNIT remaining +wait_assert_state ${MRENCLAVE} ${ICGACCOUNTBOB} balance $(( AMOUNT_TRANSFER * 6 / 10 )) +echo "✔ ok" + +echo "" +echo "-----------------------" +echo "✔ The $TEST test passed!" +echo "-----------------------" +echo "" diff --git a/cli/demo_sidechain.sh b/cli/demo_sidechain.sh index 91aa437564..f4db542b76 100755 --- a/cli/demo_sidechain.sh +++ b/cli/demo_sidechain.sh @@ -75,8 +75,12 @@ echo "Using node uri ${INTEGRITEE_RPC_URL}:${INTEGRITEE_RPC_PORT}" echo "Using trusted-worker 1 uri ${WORKER_1_URL}:${WORKER_1_PORT}" echo "Using trusted-worker 2 uri ${WORKER_2_URL}:${WORKER_2_PORT}" -INITIALFUNDS=50000000000 -AMOUNTTRANSFER=20000000000 +# the parentchain token is 12 decimal +UNIT=$(( 10 ** 12 )) +FEE_TOLERANCE=$((10 ** 11)) + +INITIALFUNDS=$((5 * UNIT)) +AMOUNTTRANSFER=$((2 * UNIT)) CLIENTWORKER1="${CLIENT_BIN} -p ${INTEGRITEE_RPC_PORT} -P ${WORKER_1_PORT} -u ${INTEGRITEE_RPC_URL} -U ${WORKER_1_URL}" CLIENTWORKER2="${CLIENT_BIN} -p ${INTEGRITEE_RPC_PORT} -P ${WORKER_2_PORT} -u ${INTEGRITEE_RPC_URL} -U ${WORKER_2_URL}" @@ -141,12 +145,12 @@ BOB_BALANCE=$(${CLIENTWORKER2} trusted --mrenclave ${MRENCLAVE} balance ${ICGACC echo "$BOB_BALANCE" echo "" -ALICE_EXPECTED_BALANCE=10000000000 -BOB_EXPECTED_BALANCE=40000000000 +ALICE_EXPECTED_BALANCE=$(( 1 * UNIT )) +BOB_EXPECTED_BALANCE=$(( 4 * UNIT )) echo "* Verifying Alice's balance" -if [ "$ALICE_BALANCE" -ne "$ALICE_EXPECTED_BALANCE" ]; then - echo "Alice's balance is wrong (expected: $ALICE_EXPECTED_BALANCE, actual: $ALICE_BALANCE)" +if (( ALICE_BALANCE >= ALICE_EXPECTED_BALANCE ? ALICE_BALANCE - ALICE_EXPECTED_BALANCE > FEE_TOLERANCE : ALICE_EXPECTED_BALANCE - ALICE_BALANCE > FEE_TOLERANCE)); then + echo "Alice's balance is wrong (expected: $ALICE_EXPECTED_BALANCE, actual: $ALICE_BALANCE), tolerance = $FEE_TOLERANCE" exit 1 else echo "Alice's balance is correct ($ALICE_BALANCE)" diff --git a/cli/src/benchmark/mod.rs b/cli/src/benchmark/mod.rs index f549a27c3e..150f14032f 100644 --- a/cli/src/benchmark/mod.rs +++ b/cli/src/benchmark/mod.rs @@ -27,7 +27,7 @@ use crate::{ }; use codec::Decode; use hdrhistogram::Histogram; -use ita_stf::{Getter, Index, TrustedCall, TrustedCallSigned, TrustedGetter}; +use ita_stf::{Getter, Index, TrustedCall, TrustedCallSigned, TrustedGetter, STF_TX_FEE}; use itc_rpc_client::direct_client::{DirectApi, DirectClient}; use itp_stf_primitives::{ traits::TrustedCallSigning, @@ -66,7 +66,7 @@ pub struct BenchmarkCommand { /// The number of iterations to execute for each client #[clap(default_value_t = 30)] - number_iterations: u32, + number_iterations: u128, /// Adds a random wait before each transaction. This is the lower bound for the interval in ms. #[clap(default_value_t = 0)] @@ -138,16 +138,15 @@ impl BenchmarkCommand { println!("Nonce for account {}: {}", self.funding_account, nonce_start); let mut accounts = Vec::new(); - + let initial_balance = (self.number_iterations + 1) * (STF_TX_FEE + EXISTENTIAL_DEPOSIT); // Setup new accounts and initialize them with money from Alice. for i in 0..self.number_clients { let nonce = i + nonce_start; - println!("Initializing account {}", i); + println!("Initializing account {} with initial amount {:?}", i, initial_balance); // Create new account to use. let a = LocalKeystore::sr25519_generate_new(&store, SR25519_KEY_TYPE, None).unwrap(); let account = get_pair_from_str(trusted_args, a.to_string().as_str()); - let initial_balance = 10000000; // Transfer amount from Alice to new account. let top: TrustedOperation = TrustedCall::balance_transfer( @@ -233,7 +232,7 @@ impl BenchmarkCommand { output.push(result); // FIXME: We probably should re-fund the account in this case. - if client.current_balance <= EXISTENTIAL_DEPOSIT { + if client.current_balance <= EXISTENTIAL_DEPOSIT + STF_TX_FEE { error!("Account {:?} does not have enough balance anymore. Finishing benchmark early", client.account.public()); break; } diff --git a/cli/src/trusted_operation.rs b/cli/src/trusted_operation.rs index 2461d8b69d..32de4616a4 100644 --- a/cli/src/trusted_operation.rs +++ b/cli/src/trusted_operation.rs @@ -161,36 +161,42 @@ fn send_indirect_request( info!("Waiting for execution confirmation from enclave..."); let mut subscription = chain_api.subscribe_events().unwrap(); loop { - let event_records = subscription.next_events::().unwrap().unwrap(); - for event_record in event_records { - if let RuntimeEvent::EnclaveBridge(EnclaveBridgeEvent::ProcessedParentchainBlock { - shard, - block_hash: confirmed_block_hash, - trusted_calls_merkle_root, - block_number: confirmed_block_number, - }) = event_record.event - { - info!("Confirmation of ProcessedParentchainBlock received"); - debug!("shard: {:?}", shard); - debug!("confirmed parentchain block Hash: {:?}", block_hash); - debug!("trusted calls merkle root: {:?}", trusted_calls_merkle_root); - debug!("Confirmed stf block Hash: {:?}", confirmed_block_hash); - if let Err(e) = check_if_received_event_exceeds_expected( - &chain_api, - block_hash, - confirmed_block_hash, - confirmed_block_number, - ) { - error!("ProcessedParentchainBlock event: {:?}", e); - return Err(TrustedOperationError::Default { - msg: format!("ProcessedParentchainBlock event: {:?}", e), - }) - }; + let event_result = subscription.next_events::(); + if let Some(Ok(event_records)) = event_result { + for event_record in event_records { + if let RuntimeEvent::EnclaveBridge( + EnclaveBridgeEvent::ProcessedParentchainBlock { + shard, + block_hash: confirmed_block_hash, + trusted_calls_merkle_root, + block_number: confirmed_block_number, + }, + ) = event_record.event + { + info!("Confirmation of ProcessedParentchainBlock received"); + debug!("shard: {:?}", shard); + debug!("confirmed parentchain block Hash: {:?}", block_hash); + debug!("trusted calls merkle root: {:?}", trusted_calls_merkle_root); + debug!("Confirmed stf block Hash: {:?}", confirmed_block_hash); + if let Err(e) = check_if_received_event_exceeds_expected( + &chain_api, + block_hash, + confirmed_block_hash, + confirmed_block_number, + ) { + error!("ProcessedParentchainBlock event: {:?}", e); + return Err(TrustedOperationError::Default { + msg: format!("ProcessedParentchainBlock event: {:?}", e), + }) + }; - if confirmed_block_hash == block_hash { - return Ok(Some(block_hash.encode())) + if confirmed_block_hash == block_hash { + return Ok(Some(block_hash.encode())) + } } } + } else { + warn!("Error in event subscription: {:?}", event_result) } } } @@ -384,5 +390,6 @@ fn connection_can_be_closed(top_status: TrustedOperationStatus) -> bool { | TrustedOperationStatus::Future | TrustedOperationStatus::Ready | TrustedOperationStatus::Broadcast + | TrustedOperationStatus::Invalid ) } diff --git a/cli/test_auto_shielding_with_transfer_bob.sh b/cli/test_auto_shielding_with_transfer_bob.sh index 0917d54fa4..255d3f5bbc 100644 --- a/cli/test_auto_shielding_with_transfer_bob.sh +++ b/cli/test_auto_shielding_with_transfer_bob.sh @@ -53,6 +53,7 @@ echo "" # the parentchain token is 12 decimal UNIT=$(( 10 ** 12 )) +FEE_TOLERANCE=$((10 ** 11)) # make these amounts greater than ED AMOUNT_SHIELD=$(( 6 * UNIT )) @@ -74,14 +75,14 @@ function wait_assert_state() for i in $(seq 1 $WAIT_ROUNDS); do sleep $WAIT_INTERVAL_SECONDS state=$(${CLIENT} trusted --mrenclave "$1" "$3" "$2") - if [ $state -eq "$4" ]; then + if (( $4 >= state ? $4 - state < FEE_TOLERANCE : state - $4 < FEE_TOLERANCE)); then return else : fi done echo - echo "Assert $2 $3 failed, expected = $4, actual = $state" + echo "Assert $2 $3 failed, expected = $4, actual = $state, tolerance = $FEE_TOLERANCE" exit 1 } diff --git a/cli/test_shield_on_target_nodes_with_transfer_to_alice.sh b/cli/test_shield_on_target_nodes_with_transfer_to_alice.sh index b7d6f76a4b..9a3d10dfa3 100755 --- a/cli/test_shield_on_target_nodes_with_transfer_to_alice.sh +++ b/cli/test_shield_on_target_nodes_with_transfer_to_alice.sh @@ -64,6 +64,7 @@ echo "" # the parentchain token is 12 decimal UNIT=$(( 10 ** 12 )) +FEE_TOLERANCE=$((10 ** 11)) # make these amounts greater than ED AMOUNT_SHIELD=$(( 6 * UNIT )) @@ -86,14 +87,14 @@ function wait_assert_state() for i in $(seq 1 $WAIT_ROUNDS); do sleep $WAIT_INTERVAL_SECONDS state=$(${CLIENT} trusted --mrenclave "$1" "$3" "$2") - if [ $state -eq "$4" ]; then + if (( $4 >= state ? $4 - state < FEE_TOLERANCE : state - $4 < FEE_TOLERANCE)); then return else : fi done echo - echo "Assert $2 $3 failed, expected = $4, actual = $state" + echo "Assert $2 $3 failed, expected = $4, actual = $state, tolerance = $FEE_TOLERANCE" exit 1 } diff --git a/core-primitives/enclave-api/ffi/src/lib.rs b/core-primitives/enclave-api/ffi/src/lib.rs index 12115521e1..67f2a174a0 100644 --- a/core-primitives/enclave-api/ffi/src/lib.rs +++ b/core-primitives/enclave-api/ffi/src/lib.rs @@ -62,6 +62,8 @@ extern "C" { retval: *mut sgx_status_t, shard: *const u8, shard_size: u32, + parentchain_id: *const u8, + parentchain_id_size: u32, ) -> sgx_status_t; pub fn trigger_parentchain_block_import( diff --git a/core-primitives/enclave-api/src/enclave_base.rs b/core-primitives/enclave-api/src/enclave_base.rs index 05df752cab..abf676cd62 100644 --- a/core-primitives/enclave-api/src/enclave_base.rs +++ b/core-primitives/enclave-api/src/enclave_base.rs @@ -51,7 +51,11 @@ pub trait EnclaveBase: Send + Sync + 'static { 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<()>; + fn init_proxied_shard_vault( + &self, + shard: &ShardIdentifier, + parentchain_id: &ParentchainId, + ) -> EnclaveResult<()>; /// Trigger the import of parentchain block explicitly. Used when initializing a light-client /// with a triggered import dispatcher. @@ -184,9 +188,13 @@ mod impl_ffi { Ok(()) } - fn init_proxied_shard_vault(&self, shard: &ShardIdentifier) -> EnclaveResult<()> { + fn init_proxied_shard_vault( + &self, + shard: &ShardIdentifier, + parentchain_id: &ParentchainId, + ) -> EnclaveResult<()> { let mut retval = sgx_status_t::SGX_SUCCESS; - + let parentchain_id_enc = parentchain_id.encode(); let shard_bytes = shard.encode(); let result = unsafe { ffi::init_proxied_shard_vault( @@ -194,6 +202,8 @@ mod impl_ffi { &mut retval, shard_bytes.as_ptr(), shard_bytes.len() as u32, + parentchain_id_enc.as_ptr(), + parentchain_id_enc.len() as u32, ) }; diff --git a/core-primitives/stf-executor/src/executor.rs b/core-primitives/stf-executor/src/executor.rs index e44b6eb059..ca3c33cf8b 100644 --- a/core-primitives/stf-executor/src/executor.rs +++ b/core-primitives/stf-executor/src/executor.rs @@ -34,9 +34,9 @@ use itp_stf_primitives::{ use itp_stf_state_handler::{handle_state::HandleState, query_shard_state::QueryShardState}; use itp_time_utils::duration_now; use itp_types::{ - parentchain::{Header as ParentchainHeader, ParentchainId}, + parentchain::{Header as ParentchainHeader, ParentchainCall, ParentchainId}, storage::StorageEntryVerified, - OpaqueCall, H256, + H256, }; use log::*; use sp_runtime::traits::Header as HeaderTrait; @@ -44,6 +44,7 @@ use std::{ collections::BTreeMap, fmt::Debug, marker::PhantomData, sync::Arc, time::Duration, vec, vec::Vec, }; + pub struct StfExecutor where TCS: PartialEq + Encode + Decode + Debug + Clone + Send + Sync + TrustedCallVerification, @@ -117,7 +118,7 @@ where } debug!("execute on STF, call with nonce {}", trusted_call.nonce()); - let mut extrinsic_call_backs: Vec = Vec::new(); + let mut extrinsic_call_backs: Vec = Vec::new(); if let Err(e) = Stf::execute_call( state, trusted_call.clone(), @@ -136,7 +137,20 @@ where } for call in extrinsic_call_backs.clone() { - trace!("trusted_call wants to send encoded call: 0x{}", hex::encode(call.encode())); + match call { + ParentchainCall::Integritee(opaque_call) => trace!( + "trusted_call wants to send encoded call to [Integritee] parentchain: 0x{}", + hex::encode(opaque_call.encode()) + ), + ParentchainCall::TargetA(opaque_call) => trace!( + "trusted_call wants to send encoded call to [TargetA] parentchain: 0x{}", + hex::encode(opaque_call.encode()) + ), + ParentchainCall::TargetB(opaque_call) => trace!( + "trusted_call wants to send encoded call to [TargetB] parentchain: 0x{}", + hex::encode(opaque_call.encode()) + ), + } } Ok(ExecutedOperation::success(operation_hash, top_or_hash, extrinsic_call_backs)) } diff --git a/core-primitives/stf-executor/src/lib.rs b/core-primitives/stf-executor/src/lib.rs index ecc93e5c9a..08d9c9125e 100644 --- a/core-primitives/stf-executor/src/lib.rs +++ b/core-primitives/stf-executor/src/lib.rs @@ -28,7 +28,7 @@ use codec::{Decode, Encode}; use core::fmt::Debug; use itp_sgx_externalities::SgxExternalitiesTrait; use itp_stf_primitives::types::TrustedOperationOrHash; -use itp_types::{OpaqueCall, H256}; +use itp_types::{parentchain::ParentchainCall, H256}; use std::vec::Vec; // re-export module to properly feature gate sgx and regular std environment @@ -60,12 +60,12 @@ pub mod mocks; /// any extrinsic callbacks (e.g. unshield extrinsics) that need to be executed on-chain #[derive(Clone, Debug, PartialEq)] pub enum ExecutionStatus { - Success(H256, Vec), + Success(H256, Vec), Failure, } impl ExecutionStatus { - pub fn get_extrinsic_callbacks(&self) -> Vec { + pub fn get_extrinsic_callbacks(&self) -> Vec { match self { ExecutionStatus::Success(_, opaque_calls) => opaque_calls.clone(), _ => Vec::new(), @@ -102,7 +102,7 @@ where pub fn success( operation_hash: H256, trusted_operation_or_hash: TrustedOperationOrHash, - extrinsic_call_backs: Vec, + extrinsic_call_backs: Vec, ) -> Self { ExecutedOperation { status: ExecutionStatus::Success(operation_hash, extrinsic_call_backs), @@ -141,7 +141,7 @@ where TCS: PartialEq + Encode + Decode + Debug + Clone + Send + Sync, G: PartialEq + Encode + Decode + Debug + Clone + Send + Sync, { - pub fn get_extrinsic_callbacks(&self) -> Vec { + pub fn get_extrinsic_callbacks(&self) -> Vec { self.executed_operations .iter() .flat_map(|e| e.status.get_extrinsic_callbacks()) @@ -173,6 +173,7 @@ mod tests { use super::*; use itp_sgx_externalities::SgxExternalities; use itp_test::mock::stf_mock::{GetterMock, TrustedCallSignedMock}; + use itp_types::OpaqueCall; #[test] fn is_success_works() { @@ -233,7 +234,8 @@ mod tests { int: u8, ) -> (ExecutedOperation, H256) { let hash = H256::from([int; 32]); - let opaque_call: Vec = vec![OpaqueCall(vec![int; 10])]; + let opaque_call: Vec = + vec![ParentchainCall::Integritee(OpaqueCall(vec![int; 10]))]; let operation = ExecutedOperation::success(hash, TrustedOperationOrHash::Hash(hash), opaque_call); (operation, hash) diff --git a/core-primitives/stf-interface/src/lib.rs b/core-primitives/stf-interface/src/lib.rs index bdcf00238e..39fb373e49 100644 --- a/core-primitives/stf-interface/src/lib.rs +++ b/core-primitives/stf-interface/src/lib.rs @@ -28,10 +28,7 @@ use core::fmt::Debug; use itp_node_api_metadata::NodeMetadataTrait; use itp_node_api_metadata_provider::AccessNodeMetadata; use itp_stf_primitives::traits::TrustedCallVerification; -use itp_types::{ - parentchain::{AccountId, ParentchainId}, - OpaqueCall, -}; +use itp_types::parentchain::{AccountId, ParentchainCall, ParentchainId}; #[cfg(feature = "mocks")] pub mod mocks; @@ -73,7 +70,7 @@ where fn execute_call( state: &mut State, call: TCS, - calls: &mut Vec, + calls: &mut Vec, node_metadata_repo: Arc, ) -> Result<(), Self::Error>; } @@ -95,7 +92,7 @@ where /// Execute a call. Callbacks are added as an `OpaqueCall`. fn execute( self, - calls: &mut Vec, + calls: &mut Vec, node_metadata_repo: Arc, ) -> Result<(), Self::Error>; diff --git a/core-primitives/stf-interface/src/mocks.rs b/core-primitives/stf-interface/src/mocks.rs index 0156cb5c08..892819a5d9 100644 --- a/core-primitives/stf-interface/src/mocks.rs +++ b/core-primitives/stf-interface/src/mocks.rs @@ -28,7 +28,10 @@ use core::{fmt::Debug, marker::PhantomData}; use itp_node_api_metadata::metadata_mocks::NodeMetadataMock; use itp_node_api_metadata_provider::NodeMetadataRepository; use itp_stf_primitives::traits::TrustedCallVerification; -use itp_types::{parentchain::ParentchainId, AccountId, Index, OpaqueCall}; +use itp_types::{ + parentchain::{ParentchainCall, ParentchainId}, + AccountId, Index, +}; #[derive(Default)] pub struct StateInterfaceMock { @@ -63,7 +66,7 @@ where fn execute_call( _state: &mut State, _call: TCS, - _calls: &mut Vec, + _calls: &mut Vec, _node_metadata_repo: Arc>, ) -> Result<(), Self::Error> { unimplemented!() @@ -99,7 +102,7 @@ impl ExecuteCall> for CallExecutorMock fn execute( self, - _calls: &mut Vec, + _calls: &mut Vec, _node_metadata_repo: Arc>, ) -> Result<(), Self::Error> { unimplemented!() diff --git a/core-primitives/test/src/mock/stf_mock.rs b/core-primitives/test/src/mock/stf_mock.rs index cbb37c19ea..1b1cec4278 100644 --- a/core-primitives/test/src/mock/stf_mock.rs +++ b/core-primitives/test/src/mock/stf_mock.rs @@ -30,7 +30,8 @@ use itp_stf_primitives::{ types::{KeyPair, Nonce, TrustedOperation}, }; use itp_types::{ - parentchain::ParentchainId, AccountId, Balance, Index, OpaqueCall, ShardIdentifier, Signature, + parentchain::{ParentchainCall, ParentchainId}, + AccountId, Balance, Index, ShardIdentifier, Signature, }; use log::*; use sp_core::{sr25519, Pair}; @@ -39,6 +40,7 @@ use sp_runtime::transaction_validity::{ }; use sp_std::{vec, vec::Vec}; use std::{thread::sleep, time::Duration}; + // a few dummy types type NodeMetadataRepositoryMock = NodeMetadataRepository; @@ -67,7 +69,7 @@ impl StateCallInterface, + calls: &mut Vec, node_metadata_repo: Arc, ) -> Result<(), Self::Error> { state.execute_with(|| call.execute(calls, node_metadata_repo)) @@ -161,7 +163,7 @@ impl ExecuteCall for TrustedCallSignedMock { fn execute( self, - _calls: &mut Vec, + _calls: &mut Vec, _node_metadata_repo: Arc, ) -> Result<(), Self::Error> { match self.call { diff --git a/core-primitives/types/src/parentchain.rs b/core-primitives/types/src/parentchain.rs index 80e2485ea5..b8bdef8147 100644 --- a/core-primitives/types/src/parentchain.rs +++ b/core-primitives/types/src/parentchain.rs @@ -15,6 +15,7 @@ */ +use crate::OpaqueCall; use alloc::{format, vec::Vec}; use codec::{Decode, Encode}; use core::fmt::Debug; @@ -64,6 +65,18 @@ pub enum ParentchainId { TargetB, } +#[cfg(feature = "std")] +impl std::fmt::Display for ParentchainId { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let message = match self { + ParentchainId::Integritee => "L1:Integritee", + ParentchainId::TargetA => "L1:AssetHub", + ParentchainId::TargetB => "L1:UNDEFINED", + }; + write!(f, "{}", message) + } +} + pub trait IdentifyParentchain { fn parentchain_id(&self) -> ParentchainId; } @@ -136,12 +149,14 @@ where #[derive(Debug)] pub enum ParentchainError { ShieldFundsFailure, + FunctionalityDisabled, } impl core::fmt::Display for ParentchainError { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { let message = match &self { ParentchainError::ShieldFundsFailure => "Parentchain Error: ShieldFundsFailure", + ParentchainError::FunctionalityDisabled => "Parentchain Error: FunctionalityDisabled", }; write!(f, "{}", message) } @@ -150,3 +165,57 @@ impl core::fmt::Display for ParentchainError { impl From for () { fn from(_: ParentchainError) -> Self {} } + +/// a wrapper to target calls to specific parentchains +#[derive(Encode, Debug, Clone, PartialEq, Eq)] +pub enum ParentchainCall { + Integritee(OpaqueCall), + TargetA(OpaqueCall), + TargetB(OpaqueCall), +} + +impl ParentchainCall { + pub fn as_integritee(&self) -> Option { + if let Self::Integritee(call) = self { + Some(call.clone()) + } else { + None + } + } + pub fn as_target_a(&self) -> Option { + if let Self::TargetA(call) = self { + Some(call.clone()) + } else { + None + } + } + pub fn as_target_b(&self) -> Option { + if let Self::TargetB(call) = self { + Some(call.clone()) + } else { + None + } + } + pub fn as_opaque_call_for(&self, parentchain_id: ParentchainId) -> Option { + match parentchain_id { + ParentchainId::Integritee => + if let Self::Integritee(call) = self { + Some(call.clone()) + } else { + None + }, + ParentchainId::TargetA => + if let Self::TargetA(call) = self { + Some(call.clone()) + } else { + None + }, + ParentchainId::TargetB => + if let Self::TargetB(call) = self { + Some(call.clone()) + } else { + None + }, + } + } +} diff --git a/core-primitives/utils/src/stringify.rs b/core-primitives/utils/src/stringify.rs index 378128891f..7018038ad8 100644 --- a/core-primitives/utils/src/stringify.rs +++ b/core-primitives/utils/src/stringify.rs @@ -28,5 +28,5 @@ pub fn public_to_string(t: &T) -> String { } pub fn account_id_to_string(account: &AccountId) -> String { - format!("{}", HexDisplay::from(&account.encode())) + format!("0x{}", HexDisplay::from(&account.encode())) } diff --git a/core/offchain-worker-executor/src/executor.rs b/core/offchain-worker-executor/src/executor.rs index 7b2f5b4df3..5c6d500cf7 100644 --- a/core/offchain-worker-executor/src/executor.rs +++ b/core/offchain-worker-executor/src/executor.rs @@ -28,7 +28,7 @@ use itp_stf_interface::system_pallet::SystemPalletEventInterface; use itp_stf_primitives::{traits::TrustedCallVerification, types::TrustedOperationOrHash}; use itp_stf_state_handler::{handle_state::HandleState, query_shard_state::QueryShardState}; use itp_top_pool_author::traits::AuthorApi; -use itp_types::{OpaqueCall, ShardIdentifier, H256}; +use itp_types::{parentchain::ParentchainCall, OpaqueCall, ShardIdentifier, H256}; use log::*; use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc, time::Duration, vec::Vec}; @@ -114,7 +114,7 @@ impl< let max_duration = Duration::from_secs(5); let latest_parentchain_header = self.get_latest_parentchain_header()?; - let mut parentchain_effects: Vec = Vec::new(); + let mut parentchain_effects: Vec = Vec::new(); let shards = self.state_handler.list_shards()?; trace!("Executing calls on {} shard(s)", shards.len()); @@ -184,10 +184,34 @@ impl< Ok(()) } - fn send_parentchain_effects(&self, parentchain_effects: Vec) -> Result<()> { - let extrinsics = self - .extrinsics_factory - .create_extrinsics(parentchain_effects.as_slice(), None)?; + fn send_parentchain_effects(&self, parentchain_effects: Vec) -> Result<()> { + let integritee_calls: Vec = parentchain_effects + .iter() + .filter_map(|parentchain_call| parentchain_call.as_integritee()) + .collect(); + let target_a_calls: Vec = parentchain_effects + .iter() + .filter_map(|parentchain_call| parentchain_call.as_target_a()) + .collect(); + let target_b_calls: Vec = parentchain_effects + .iter() + .filter_map(|parentchain_call| parentchain_call.as_target_b()) + .collect(); + debug!( + "stf wants to send calls to parentchains: Integritee: {} TargetA: {} TargetB: {}", + integritee_calls.len(), + target_a_calls.len(), + target_b_calls.len() + ); + if !target_a_calls.is_empty() { + warn!("sending extrinsics to target A unimplemented") + }; + if !target_b_calls.is_empty() { + warn!("sending extrinsics to target B unimplemented") + }; + + let extrinsics = + self.extrinsics_factory.create_extrinsics(integritee_calls.as_slice(), None)?; self.validator_accessor .execute_mut_on_validator(|v| v.send_extrinsics(extrinsics))?; Ok(()) diff --git a/core/parentchain/block-import-dispatcher/src/lib.rs b/core/parentchain/block-import-dispatcher/src/lib.rs index fc4a000178..a368066283 100644 --- a/core/parentchain/block-import-dispatcher/src/lib.rs +++ b/core/parentchain/block-import-dispatcher/src/lib.rs @@ -99,15 +99,15 @@ where fn dispatch_import(&self, blocks: Vec, events: Vec>) -> Result<()> { match self { BlockImportDispatcher::TriggeredDispatcher(dispatcher) => { - log::info!("TRIGGERED DISPATCHER MATCH"); + log::trace!("TRIGGERED DISPATCHER MATCH"); dispatcher.dispatch_import(blocks, events) }, BlockImportDispatcher::ImmediateDispatcher(dispatcher) => { - log::info!("IMMEDIATE DISPATCHER MATCH"); + log::trace!("IMMEDIATE DISPATCHER MATCH"); dispatcher.dispatch_import(blocks, events) }, BlockImportDispatcher::EmptyDispatcher => { - log::info!("EMPTY DISPATCHER DISPATCHER MATCH"); + log::trace!("EMPTY DISPATCHER DISPATCHER MATCH"); Err(Error::NoDispatcherAssigned) }, } diff --git a/core/parentchain/block-import-dispatcher/src/triggered_dispatcher.rs b/core/parentchain/block-import-dispatcher/src/triggered_dispatcher.rs index 2438a07350..d4ec052a2f 100644 --- a/core/parentchain/block-import-dispatcher/src/triggered_dispatcher.rs +++ b/core/parentchain/block-import-dispatcher/src/triggered_dispatcher.rs @@ -101,8 +101,10 @@ where blocks: Vec, events: Vec, ) -> Result<()> { + let parentchain_id = self.block_importer.parentchain_id(); trace!( - "Pushing parentchain block(s) and event(s) ({}) ({}) to import queue", + "[{:?}] Pushing parentchain block(s) and event(s) ({}) ({}) to import queue", + parentchain_id, blocks.len(), events.len() ); @@ -130,9 +132,10 @@ where let events_to_import = self.events_queue.pop_all().map_err(Error::ImportQueue)?; let latest_imported_block = blocks_to_import.last().map(|b| (*b).clone()); - + let parentchain_id = self.block_importer.parentchain_id(); trace!( - "Trigger import of all parentchain blocks and events in queue ({}) ({})", + "[{:?}] Trigger import of all parentchain blocks and events in queue ({}) ({})", + parentchain_id, blocks_to_import.len(), events_to_import.len() ); @@ -147,9 +150,10 @@ where fn import_all_but_latest(&self) -> Result<()> { let blocks_to_import = self.import_queue.pop_all_but_last().map_err(Error::ImportQueue)?; let events_to_import = self.events_queue.pop_all_but_last().map_err(Error::ImportQueue)?; - + let parentchain_id = self.block_importer.parentchain_id(); trace!( - "Trigger import of all parentchain blocks and events, except the latest, from queue ({}) ({})", + "[{:?}] Trigger import of all parentchain blocks and events, except the latest, from queue ({}) ({})", + parentchain_id, blocks_to_import.len(), events_to_import.len() ); @@ -172,9 +176,10 @@ where .map_err(Error::ImportQueue)?; let latest_imported_block = blocks_to_import.last().map(|b| (*b).clone()); - + let parentchain_id = self.block_importer.parentchain_id(); trace!( - "Import of parentchain blocks and events has been triggered, importing {} blocks and {} events from queue", + "[{:?}] Import of parentchain blocks and events has been triggered, importing {} blocks and {} events from queue", + parentchain_id, blocks_to_import.len(), events_to_import.len(), ); @@ -190,16 +195,20 @@ where &self, predicate: impl Fn(&BlockImporter::SignedBlockType) -> bool, ) -> Result> { + let parentchain_id = self.block_importer.parentchain_id(); trace!( - "Peek find parentchain import queue (currently has {} elements)", + "[{:?}] Peek find parentchain import queue (currently has {} elements)", + parentchain_id, self.import_queue.peek_queue_size().unwrap_or(0) ); self.import_queue.peek_find(predicate).map_err(Error::ImportQueue) } fn peek_latest(&self) -> Result> { + let parentchain_id = self.block_importer.parentchain_id(); trace!( - "Peek latest parentchain import queue (currently has {} elements)", + "[{:?}] Peek latest parentchain import queue (currently has {} elements)", + parentchain_id, self.import_queue.peek_queue_size().unwrap_or(0) ); self.import_queue.peek_last().map_err(Error::ImportQueue) diff --git a/core/parentchain/block-importer/src/block_importer.rs b/core/parentchain/block-importer/src/block_importer.rs index 63e76e9210..83118c216a 100644 --- a/core/parentchain/block-importer/src/block_importer.rs +++ b/core/parentchain/block-importer/src/block_importer.rs @@ -44,7 +44,7 @@ pub struct ParentchainBlockImporter< ExtrinsicsFactory, IndirectCallsExecutor, > { - validator_accessor: Arc, + pub validator_accessor: Arc, stf_executor: Arc, extrinsics_factory: Arc, pub indirect_calls_executor: Arc, @@ -165,4 +165,8 @@ impl< Ok(()) } + + fn parentchain_id(&self) -> ParentchainId { + self.validator_accessor.parentchain_id() + } } diff --git a/core/parentchain/block-importer/src/block_importer_mock.rs b/core/parentchain/block-importer/src/block_importer_mock.rs index 5308ef4e71..2f1da14500 100644 --- a/core/parentchain/block-importer/src/block_importer_mock.rs +++ b/core/parentchain/block-importer/src/block_importer_mock.rs @@ -21,6 +21,7 @@ use crate::{ error::{Error, Result}, ImportParentchainBlocks, }; +use itp_types::parentchain::ParentchainId; use std::{sync::RwLock, vec::Vec}; /// Mock implementation for the block importer. @@ -58,4 +59,7 @@ where imported_blocks_lock.extend(blocks_to_import); Ok(()) } + fn parentchain_id(&self) -> ParentchainId { + ParentchainId::Integritee + } } diff --git a/core/parentchain/block-importer/src/lib.rs b/core/parentchain/block-importer/src/lib.rs index 98ecb2e6a0..3f2fd695bc 100644 --- a/core/parentchain/block-importer/src/lib.rs +++ b/core/parentchain/block-importer/src/lib.rs @@ -39,6 +39,7 @@ pub mod block_importer_mock; pub use block_importer::*; use error::Result; +use itp_types::parentchain::ParentchainId; use std::vec::Vec; /// Block import from the parentchain. @@ -55,4 +56,6 @@ pub trait ImportParentchainBlocks { blocks_to_import: Vec, events_to_import: Vec>, ) -> Result<()>; + + fn parentchain_id(&self) -> ParentchainId; } diff --git a/enclave-runtime/Cargo.lock b/enclave-runtime/Cargo.lock index 700a33fbc5..072a6e19b0 100644 --- a/enclave-runtime/Cargo.lock +++ b/enclave-runtime/Cargo.lock @@ -2423,6 +2423,7 @@ dependencies = [ "itp-time-utils", "itp-top-pool-author", "itp-types", + "itp-utils", "its-block-composer", "its-block-verification", "its-consensus-common", diff --git a/enclave-runtime/Enclave.edl b/enclave-runtime/Enclave.edl index 544e988b1a..098a346b09 100644 --- a/enclave-runtime/Enclave.edl +++ b/enclave-runtime/Enclave.edl @@ -59,7 +59,8 @@ enclave { ); public sgx_status_t init_proxied_shard_vault( - [in, size=shard_size] uint8_t* shard, uint32_t shard_size + [in, size=shard_size] uint8_t* shard, uint32_t shard_size, + [in, size=parentchain_id_size] uint8_t* parentchain_id, uint32_t parentchain_id_size ); public sgx_status_t trigger_parentchain_block_import( diff --git a/enclave-runtime/src/initialization/global_components.rs b/enclave-runtime/src/initialization/global_components.rs index e051b947e2..0425b1c3af 100644 --- a/enclave-runtime/src/initialization/global_components.rs +++ b/enclave-runtime/src/initialization/global_components.rs @@ -152,12 +152,16 @@ pub type EnclaveValidatorAccessor = ValidatorAccessor< EnclaveLightClientSeal, >; -pub type EnclaveParentchainBlockImportQueue = ImportQueue; +pub type IntegriteeParentchainBlockImportQueue = ImportQueue; +pub type TargetAParentchainBlockImportQueue = ImportQueue; +pub type TargetBParentchainBlockImportQueue = ImportQueue; /// Import queue for the events /// /// Note: `Vec` is correct. It should not be `Vec` -pub type EnclaveParentchainEventImportQueue = ImportQueue>; +pub type IntegriteeParentchainEventImportQueue = ImportQueue>; +pub type TargetAParentchainEventImportQueue = ImportQueue>; +pub type TargetBParentchainEventImportQueue = ImportQueue>; // Stuff for the integritee parentchain @@ -183,8 +187,8 @@ pub type IntegriteeParentchainBlockImporter = ParentchainBlockImporter< pub type IntegriteeParentchainTriggeredBlockImportDispatcher = TriggeredDispatcher< IntegriteeParentchainBlockImporter, - EnclaveParentchainBlockImportQueue, - EnclaveParentchainEventImportQueue, + IntegriteeParentchainBlockImportQueue, + IntegriteeParentchainEventImportQueue, >; pub type IntegriteeParentchainImmediateBlockImportDispatcher = @@ -225,8 +229,8 @@ pub type TargetAParentchainBlockImporter = ParentchainBlockImporter< pub type TargetAParentchainTriggeredBlockImportDispatcher = TriggeredDispatcher< TargetAParentchainBlockImporter, - EnclaveParentchainBlockImportQueue, - EnclaveParentchainEventImportQueue, + TargetAParentchainBlockImportQueue, + TargetAParentchainEventImportQueue, >; pub type TargetAParentchainImmediateBlockImportDispatcher = @@ -267,8 +271,8 @@ pub type TargetBParentchainBlockImporter = ParentchainBlockImporter< pub type TargetBParentchainTriggeredBlockImportDispatcher = TriggeredDispatcher< TargetBParentchainBlockImporter, - EnclaveParentchainBlockImportQueue, - EnclaveParentchainEventImportQueue, + TargetBParentchainBlockImportQueue, + TargetBParentchainEventImportQueue, >; pub type TargetBParentchainImmediateBlockImportDispatcher = diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index 018cf0d719..abe3e51768 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -42,8 +42,8 @@ use crate::{ utils::{ 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, + get_triggered_dispatcher_from_integritee_solo_or_parachain, + get_validator_accessor_from_integritee_solo_or_parachain, }, Hash, }; @@ -211,7 +211,8 @@ pub(crate) fn init_enclave_sidechain_components() -> EnclaveResult<()> { let top_pool_author = GLOBAL_TOP_POOL_AUTHOR_COMPONENT.get()?; let state_key_repository = GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.get()?; - let parentchain_block_import_dispatcher = get_triggered_dispatcher_from_solo_or_parachain()?; + let parentchain_block_import_dispatcher = + get_triggered_dispatcher_from_integritee_solo_or_parachain()?; let signer = GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?; @@ -226,7 +227,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_integritee_solo_or_parachain()?; - let validator_accessor = get_validator_accessor_from_solo_or_parachain()?; + let validator_accessor = get_validator_accessor_from_integritee_solo_or_parachain()?; let sidechain_block_import_confirmation_handler = Arc::new(EnclaveBlockImportConfirmationHandler::new( diff --git a/enclave-runtime/src/initialization/parentchain/common.rs b/enclave-runtime/src/initialization/parentchain/common.rs index 077a59217e..8e19c24d2f 100644 --- a/enclave-runtime/src/initialization/parentchain/common.rs +++ b/enclave-runtime/src/initialization/parentchain/common.rs @@ -20,17 +20,22 @@ use crate::{ initialization::{ global_components::{ EnclaveExtrinsicsFactory, EnclaveNodeMetadataRepository, EnclaveOffchainWorkerExecutor, - EnclaveParentchainBlockImportQueue, EnclaveParentchainEventImportQueue, EnclaveParentchainSigner, EnclaveStfExecutor, EnclaveValidatorAccessor, - IntegriteeParentchainBlockImportDispatcher, IntegriteeParentchainBlockImporter, + IntegriteeParentchainBlockImportDispatcher, IntegriteeParentchainBlockImportQueue, + IntegriteeParentchainBlockImporter, IntegriteeParentchainEventImportQueue, IntegriteeParentchainImmediateBlockImportDispatcher, IntegriteeParentchainIndirectCallsExecutor, IntegriteeParentchainTriggeredBlockImportDispatcher, - TargetAParentchainBlockImportDispatcher, TargetAParentchainBlockImporter, + TargetAParentchainBlockImportDispatcher, TargetAParentchainBlockImportQueue, + TargetAParentchainBlockImporter, TargetAParentchainEventImportQueue, TargetAParentchainImmediateBlockImportDispatcher, - TargetAParentchainIndirectCallsExecutor, TargetBParentchainBlockImportDispatcher, - TargetBParentchainBlockImporter, TargetBParentchainImmediateBlockImportDispatcher, - TargetBParentchainIndirectCallsExecutor, GLOBAL_OCALL_API_COMPONENT, + TargetAParentchainIndirectCallsExecutor, + TargetAParentchainTriggeredBlockImportDispatcher, + TargetBParentchainBlockImportDispatcher, TargetBParentchainBlockImportQueue, + TargetBParentchainBlockImporter, TargetBParentchainEventImportQueue, + TargetBParentchainImmediateBlockImportDispatcher, + TargetBParentchainIndirectCallsExecutor, + TargetBParentchainTriggeredBlockImportDispatcher, GLOBAL_OCALL_API_COMPONENT, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT, GLOBAL_STATE_OBSERVER_COMPONENT, GLOBAL_TOP_POOL_AUTHOR_COMPONENT, @@ -246,8 +251,8 @@ pub(crate) fn create_target_b_offchain_immediate_import_dispatcher( pub(crate) fn create_sidechain_triggered_import_dispatcher( block_importer: IntegriteeParentchainBlockImporter, ) -> Arc { - let parentchain_block_import_queue = EnclaveParentchainBlockImportQueue::default(); - let parentchain_event_import_queue = EnclaveParentchainEventImportQueue::default(); + let parentchain_block_import_queue = IntegriteeParentchainBlockImportQueue::default(); + let parentchain_event_import_queue = IntegriteeParentchainEventImportQueue::default(); let triggered_dispatcher = IntegriteeParentchainTriggeredBlockImportDispatcher::new( block_importer, parentchain_block_import_queue, @@ -257,3 +262,33 @@ pub(crate) fn create_sidechain_triggered_import_dispatcher( triggered_dispatcher, ))) } + +pub(crate) fn create_sidechain_triggered_import_dispatcher_for_target_a( + block_importer: TargetAParentchainBlockImporter, +) -> Arc { + let parentchain_block_import_queue = TargetAParentchainBlockImportQueue::default(); + let parentchain_event_import_queue = TargetAParentchainEventImportQueue::default(); + let triggered_dispatcher = TargetAParentchainTriggeredBlockImportDispatcher::new( + block_importer, + parentchain_block_import_queue, + parentchain_event_import_queue, + ); + Arc::new(TargetAParentchainBlockImportDispatcher::new_triggered_dispatcher(Arc::new( + triggered_dispatcher, + ))) +} + +pub(crate) fn create_sidechain_triggered_import_dispatcher_for_target_b( + block_importer: TargetBParentchainBlockImporter, +) -> Arc { + let parentchain_block_import_queue = TargetBParentchainBlockImportQueue::default(); + let parentchain_event_import_queue = TargetBParentchainEventImportQueue::default(); + let triggered_dispatcher = TargetBParentchainTriggeredBlockImportDispatcher::new( + block_importer, + parentchain_block_import_queue, + parentchain_event_import_queue, + ); + Arc::new(TargetBParentchainBlockImportDispatcher::new_triggered_dispatcher(Arc::new( + triggered_dispatcher, + ))) +} diff --git a/enclave-runtime/src/initialization/parentchain/target_a_parachain.rs b/enclave-runtime/src/initialization/parentchain/target_a_parachain.rs index 56bb011919..bf24f6fdd4 100644 --- a/enclave-runtime/src/initialization/parentchain/target_a_parachain.rs +++ b/enclave-runtime/src/initialization/parentchain/target_a_parachain.rs @@ -31,19 +31,19 @@ use crate::{ GLOBAL_TARGET_A_PARENTCHAIN_LIGHT_CLIENT_SEAL, GLOBAL_TARGET_A_PARENTCHAIN_NONCE_CACHE, }, parentchain::common::{ - create_extrinsics_factory, create_target_a_offchain_immediate_import_dispatcher, + create_extrinsics_factory, create_sidechain_triggered_import_dispatcher_for_target_a, + create_target_a_offchain_immediate_import_dispatcher, create_target_a_parentchain_block_importer, }, }, }; use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, LightClientState}; +pub use itc_parentchain::primitives::{ParachainBlock, ParachainHeader, ParachainParams}; use itp_component_container::ComponentGetter; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode}; use itp_types::parentchain::ParentchainId; use std::{path::PathBuf, sync::Arc}; -pub use itc_parentchain::primitives::{ParachainBlock, ParachainHeader, ParachainParams}; - #[derive(Clone)] pub struct TargetAParachainHandler { pub genesis_header: ParachainHeader, @@ -103,7 +103,7 @@ impl TargetAParachainHandler { extrinsics_factory.clone(), )?, WorkerMode::Sidechain => - unimplemented!("Can't run target a chain in sidechain mode yet."), + create_sidechain_triggered_import_dispatcher_for_target_a(block_importer), WorkerMode::Teeracle => Arc::new(TargetAParentchainBlockImportDispatcher::new_empty_dispatcher()), }; diff --git a/enclave-runtime/src/initialization/parentchain/target_a_solochain.rs b/enclave-runtime/src/initialization/parentchain/target_a_solochain.rs index 60259eedbe..f5cf2ae8ff 100644 --- a/enclave-runtime/src/initialization/parentchain/target_a_solochain.rs +++ b/enclave-runtime/src/initialization/parentchain/target_a_solochain.rs @@ -25,19 +25,19 @@ use crate::{ GLOBAL_TARGET_A_PARENTCHAIN_LIGHT_CLIENT_SEAL, GLOBAL_TARGET_A_PARENTCHAIN_NONCE_CACHE, }, parentchain::common::{ - create_extrinsics_factory, create_target_a_offchain_immediate_import_dispatcher, + create_extrinsics_factory, create_sidechain_triggered_import_dispatcher_for_target_a, + create_target_a_offchain_immediate_import_dispatcher, create_target_a_parentchain_block_importer, }, }, }; use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, LightClientState}; +pub use itc_parentchain::primitives::{SolochainBlock, SolochainHeader, SolochainParams}; use itp_component_container::ComponentGetter; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode}; use itp_types::parentchain::ParentchainId; use std::{path::PathBuf, sync::Arc}; -pub use itc_parentchain::primitives::{SolochainBlock, SolochainHeader, SolochainParams}; - pub struct TargetASolochainHandler { pub genesis_header: SolochainHeader, pub node_metadata_repository: Arc, @@ -96,7 +96,7 @@ impl TargetASolochainHandler { extrinsics_factory.clone(), )?, WorkerMode::Sidechain => - unimplemented!("Can't run target a chain in sidechain mode yet."), + create_sidechain_triggered_import_dispatcher_for_target_a(block_importer), WorkerMode::Teeracle => Arc::new(TargetAParentchainBlockImportDispatcher::new_empty_dispatcher()), }; diff --git a/enclave-runtime/src/initialization/parentchain/target_b_parachain.rs b/enclave-runtime/src/initialization/parentchain/target_b_parachain.rs index bd1b628b06..be44224c65 100644 --- a/enclave-runtime/src/initialization/parentchain/target_b_parachain.rs +++ b/enclave-runtime/src/initialization/parentchain/target_b_parachain.rs @@ -31,19 +31,19 @@ use crate::{ GLOBAL_TARGET_B_PARENTCHAIN_LIGHT_CLIENT_SEAL, GLOBAL_TARGET_B_PARENTCHAIN_NONCE_CACHE, }, parentchain::common::{ - create_extrinsics_factory, create_target_b_offchain_immediate_import_dispatcher, + create_extrinsics_factory, create_sidechain_triggered_import_dispatcher_for_target_b, + create_target_b_offchain_immediate_import_dispatcher, create_target_b_parentchain_block_importer, }, }, }; use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, LightClientState}; +pub use itc_parentchain::primitives::{ParachainBlock, ParachainHeader, ParachainParams}; use itp_component_container::ComponentGetter; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode}; use itp_types::parentchain::ParentchainId; use std::{path::PathBuf, sync::Arc}; -pub use itc_parentchain::primitives::{ParachainBlock, ParachainHeader, ParachainParams}; - #[derive(Clone)] pub struct TargetBParachainHandler { pub genesis_header: ParachainHeader, @@ -103,7 +103,7 @@ impl TargetBParachainHandler { extrinsics_factory.clone(), )?, WorkerMode::Sidechain => - unimplemented!("Can't run target B chain in sidechain mode yet."), + create_sidechain_triggered_import_dispatcher_for_target_b(block_importer), WorkerMode::Teeracle => Arc::new(TargetBParentchainBlockImportDispatcher::new_empty_dispatcher()), }; diff --git a/enclave-runtime/src/initialization/parentchain/target_b_solochain.rs b/enclave-runtime/src/initialization/parentchain/target_b_solochain.rs index d3ec66beae..842baa8129 100644 --- a/enclave-runtime/src/initialization/parentchain/target_b_solochain.rs +++ b/enclave-runtime/src/initialization/parentchain/target_b_solochain.rs @@ -25,19 +25,19 @@ use crate::{ GLOBAL_TARGET_B_PARENTCHAIN_LIGHT_CLIENT_SEAL, GLOBAL_TARGET_B_PARENTCHAIN_NONCE_CACHE, }, parentchain::common::{ - create_extrinsics_factory, create_target_b_offchain_immediate_import_dispatcher, + create_extrinsics_factory, create_sidechain_triggered_import_dispatcher_for_target_b, + create_target_b_offchain_immediate_import_dispatcher, create_target_b_parentchain_block_importer, }, }, }; use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, LightClientState}; +pub use itc_parentchain::primitives::{SolochainBlock, SolochainHeader, SolochainParams}; use itp_component_container::ComponentGetter; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode}; use itp_types::parentchain::ParentchainId; use std::{path::PathBuf, sync::Arc}; -pub use itc_parentchain::primitives::{SolochainBlock, SolochainHeader, SolochainParams}; - pub struct TargetBSolochainHandler { pub genesis_header: SolochainHeader, pub node_metadata_repository: Arc, @@ -96,7 +96,7 @@ impl TargetBSolochainHandler { extrinsics_factory.clone(), )?, WorkerMode::Sidechain => - unimplemented!("Can't run target B chain in sidechain mode yet."), + create_sidechain_triggered_import_dispatcher_for_target_b(block_importer), WorkerMode::Teeracle => Arc::new(TargetBParentchainBlockImportDispatcher::new_empty_dispatcher()), }; diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index 111324f0bb..881abb0e69 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -503,7 +503,12 @@ fn dispatch_parentchain_blocks_for_import trace!("Not importing any parentchain blocks"); return Ok(()) } - + trace!( + "[{:?}] Dispatching Import of {} blocks and {} events", + id, + blocks_to_sync.len(), + events_to_sync.len() + ); match id { ParentchainId::Integritee => { if let Ok(handler) = GLOBAL_INTEGRITEE_SOLOCHAIN_HANDLER_COMPONENT.get() { diff --git a/enclave-runtime/src/rpc/worker_api_direct.rs b/enclave-runtime/src/rpc/worker_api_direct.rs index 9c99f99b6d..6c3084c77e 100644 --- a/enclave-runtime/src/rpc/worker_api_direct.rs +++ b/enclave-runtime/src/rpc/worker_api_direct.rs @@ -22,7 +22,7 @@ use crate::{ }, utils::{ get_stf_enclave_signer_from_solo_or_parachain, - get_validator_accessor_from_solo_or_parachain, + get_validator_accessor_from_integritee_solo_or_parachain, }, }; use codec::Encode; @@ -280,7 +280,7 @@ fn forward_dcap_quote_inner(params: Params) -> Result { let ext = generate_dcap_ra_extrinsic_from_quote_internal(url, &encoded_quote_to_forward) .map_err(|e| format!("{:?}", e))?; - let validator_access = get_validator_accessor_from_solo_or_parachain().unwrap(); + let validator_access = get_validator_accessor_from_integritee_solo_or_parachain().unwrap(); validator_access .execute_mut_on_validator(|v| v.send_extrinsics(vec![ext.clone()])) .unwrap(); @@ -308,7 +308,7 @@ fn attesteer_forward_ias_attestation_report_inner( let ext = generate_ias_ra_extrinsic_from_der_cert_internal(url, &ias_attestation_report) .map_err(|e| format!("{:?}", e))?; - let validator_access = get_validator_accessor_from_solo_or_parachain().unwrap(); + let validator_access = get_validator_accessor_from_integritee_solo_or_parachain().unwrap(); validator_access .execute_mut_on_validator(|v| v.send_extrinsics(vec![ext.clone()])) .unwrap(); diff --git a/enclave-runtime/src/shard_vault.rs b/enclave-runtime/src/shard_vault.rs index c7daebb591..af8bbfbfdd 100644 --- a/enclave-runtime/src/shard_vault.rs +++ b/enclave-runtime/src/shard_vault.rs @@ -22,7 +22,11 @@ use crate::{ }, utils::{ get_extrinsic_factory_from_integritee_solo_or_parachain, + get_extrinsic_factory_from_target_a_solo_or_parachain, + get_extrinsic_factory_from_target_b_solo_or_parachain, get_node_metadata_repository_from_integritee_solo_or_parachain, + get_node_metadata_repository_from_target_a_solo_or_parachain, + get_node_metadata_repository_from_target_b_solo_or_parachain, DecodeRaw, }, }; use codec::{Compact, Decode, Encode}; @@ -54,11 +58,21 @@ use std::{slice, sync::Arc, vec::Vec}; pub unsafe extern "C" fn init_proxied_shard_vault( shard: *const u8, shard_size: u32, + parentchain_id: *const u8, + parentchain_id_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) { + let parentchain_id = + match ParentchainId::decode_raw(parentchain_id, parentchain_id_size as usize) { + Ok(id) => id, + Err(e) => { + error!("Could not decode parentchain id: {:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + }, + }; + + if let Err(e) = init_proxied_shard_vault_internal(shard_identifier, parentchain_id) { error!("Failed to initialize proxied shard vault ({:?}): {:?}", shard_identifier, e); return sgx_status_t::SGX_ERROR_UNEXPECTED } @@ -79,11 +93,10 @@ pub unsafe extern "C" fn get_ecc_vault_pubkey( let shard_vault = match get_shard_vault_account(shard) { Ok(account) => account, Err(e) => { - error!("Failed to fetch shard vault account: {:?}", e); + warn!("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 @@ -105,7 +118,10 @@ pub(crate) fn get_shard_vault_account(shard: ShardIdentifier) -> EnclaveResult EnclaveResult<()> { +pub(crate) fn init_proxied_shard_vault_internal( + shard: ShardIdentifier, + parentchain_id: ParentchainId, +) -> EnclaveResult<()> { let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; if !state_handler .shard_exists(&shard) @@ -116,20 +132,41 @@ pub(crate) fn init_proxied_shard_vault_internal(shard: ShardIdentifier) -> Encla 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)?; + let (enclave_extrinsics_factory, node_metadata_repo) = match parentchain_id { + ParentchainId::Integritee => { + 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)?; + 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()?; + (enclave_extrinsics_factory, node_metadata_repo) + }, + ParentchainId::TargetA => { + let enclave_extrinsics_factory = + get_extrinsic_factory_from_target_a_solo_or_parachain()?; + let node_metadata_repo = + get_node_metadata_repository_from_target_a_solo_or_parachain()?; + (enclave_extrinsics_factory, node_metadata_repo) + }, + ParentchainId::TargetB => { + let enclave_extrinsics_factory = + get_extrinsic_factory_from_target_b_solo_or_parachain()?; + let node_metadata_repo = + get_node_metadata_repository_from_target_b_solo_or_parachain()?; + (enclave_extrinsics_factory, node_metadata_repo) + }, + }; - info!("send existential funds from enclave account to vault account"); + info!("[{:?}] send existential funds from enclave account to vault account", parentchain_id); let call_ids = node_metadata_repo .get_from_metadata(|m| m.call_indexes("Balances", "transfer_keep_alive"))? .map_err(MetadataProviderError::MetadataError)?; @@ -140,18 +177,18 @@ pub(crate) fn init_proxied_shard_vault_internal(shard: ShardIdentifier) -> Encla Compact(PROXY_DEPOSIT), )); - info!("vault funding call: 0x{}", hex::encode(call.0.clone())); + info!("[{:?}] vault funding call: 0x{}", parentchain_id, 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)?; + ocall_api.send_to_parentchain(xts, &parentchain_id, 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"); + info!("[{:?}] register enclave signer as proxy for shard vault", parentchain_id); let call_ids = node_metadata_repo .get_from_metadata(|m| m.call_indexes("Proxy", "add_proxy"))? .map_err(MetadataProviderError::MetadataError)?; @@ -163,10 +200,10 @@ pub(crate) fn init_proxied_shard_vault_internal(shard: ShardIdentifier) -> Encla 0u32, // delay )); - info!("add proxy call: 0x{}", hex::encode(call.0.clone())); + info!("[{:?}] add proxy call: 0x{}", parentchain_id, hex::encode(call.0.clone())); let xts = vault_extrinsics_factory.create_extrinsics(&[call], None)?; - ocall_api.send_to_parentchain(xts, &ParentchainId::Integritee, false)?; + ocall_api.send_to_parentchain(xts, &parentchain_id, false)?; Ok(()) } diff --git a/enclave-runtime/src/test/cert_tests.rs b/enclave-runtime/src/test/cert_tests.rs index c5eaab9f89..ad3b78df76 100644 --- a/enclave-runtime/src/test/cert_tests.rs +++ b/enclave-runtime/src/test/cert_tests.rs @@ -28,6 +28,7 @@ const TEST4_CERT: &[u8] = include_bytes!("fixtures/ra_dump_cert_TEST4.der"); const TEST4_MRENCLAVE: &str = "7a3454ec8f42e265cb5be7dfd111e1d95ac6076ed82a0948b2e2a45cf17b62a0"; +#[allow(clippy::octal_escapes)] const CERT_WRONG_PLATFORM_BLOB: &[u8] = b"0\x82\x0c\x8c0\x82\x0c2\xa0\x03\x02\x01\x02\x02\x01\x010\n\x06\x08*\x86H\xce=\x04\x03\x020\x121\x100\x0e\x06\x03U\x04\x03\x0c\x07MesaTEE0\x1e\x17\r190617124609Z\x17\r190915124609Z0\x121\x100\x0e\x06\x03U\x04\x03\x0c\x07MesaTEE0Y0\x13\x06\x07*\x86H\xce=\x02\x01\x06\x08*\x86H\xce=\x03\x01\x07\x03B\0\x04RT\x16\x16 \xef_\xd8\xe7\xc3\xb7\x03\x1d\xd6:\x1fF\xe3\xf2b!\xa9/\x8b\xd4\x82\x8f\xd1\xff[\x9c\x97\xbc\xf27\xb8,L\x8a\x01\xb0r;;\xa9\x83\xdc\x86\x9f\x1d%y\xf4;I\xe4Y\xc80'$K[\xd6\xa3\x82\x0bw0\x82\x0bs0\x82\x0bo\x06\t`\x86H\x01\x86\xf8B\x01\r\x04\x82\x0b`{\"id\":\"117077750682263877593646412006783680848\",\"timestamp\":\"2019-06-17T12:46:04.002066\",\"version\":3,\"isvEnclaveQuoteStatus\":\"GROUP_OUT_OF_DATE\",\"platformInfoBlob\":\"1602006504000900000909020401800000000000000000000008000009000000020000000000000B401A355B313FC939B4F48A54349C914A32A3AE2C4871BFABF22E960C55635869FC66293A3D9B2D58ED96CA620B65D669A444C80291314EF691E896F664317CF80C\",\"isvEnclaveQuoteBody\":\"AgAAAEALAAAIAAcAAAAAAOE6wgoHKsZsnVWSrsWX9kky0kWt9K4xcan0fQ996Ct+CAj//wGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAHAAAAAAAAAFJJYIbPVot9NzRCjW2z9+k+9K8BsHQKzVMEHOR14hNbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACD1xnnferKFHD2uvYqTXdDA8iZ22kCD5xw7h38CMfOngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSVBYWIO9f2OfDtwMd1jofRuPyYiGpL4vUgo/R/1ucl7zyN7gsTIoBsHI7O6mD3IafHSV59DtJ5FnIMCckS1vW\"}|EbPFH/ThUaS/dMZoDKC5EgmdUXUORFtQzF49Umi1P55oeESreJaUvmA0sg/ATSTn5t2e+e6ZoBQIUbLHjcWLMLzK4pJJUeHhok7EfVgoQ378i+eGR9v7ICNDGX7a1rroOe0s1OKxwo/0hid2KWvtAUBvf1BDkqlHy025IOiXWhXFLkb/qQwUZDWzrV4dooMfX5hfqJPi1q9s18SsdLPmhrGBheh9keazeCR9hiLhRO9TbnVgR9zJk43SPXW+pHkbNigW+2STpVAi5ugWaSwBOdK11ZjaEU1paVIpxQnlW1D6dj1Zc3LibMH+ly9ZGrbYtuJks4eRnjPhroPXxlJWpQ==|MIIEoTCCAwmgAwIBAgIJANEHdl0yo7CWMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMTAwLgYDVQQDDCdJbnRlbCBTR1ggQXR0ZXN0YXRpb24gUmVwb3J0IFNpZ25pbmcgQ0EwHhcNMTYxMTIyMDkzNjU4WhcNMjYxMTIwMDkzNjU4WjB7MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEtMCsGA1UEAwwkSW50ZWwgU0dYIEF0dGVzdGF0aW9uIFJlcG9ydCBTaWduaW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqXot4OZuphR8nudFrAFiaGxxkgma/Es/BA+tbeCTUR106AL1ENcWA4FX3K+E9BBL0/7X5rj5nIgX/R/1ubhkKWw9gfqPG3KeAtIdcv/uTO1yXv50vqaPvE1CRChvzdS/ZEBqQ5oVvLTPZ3VEicQjlytKgN9cLnxbwtuvLUK7eyRPfJW/ksddOzP8VBBniolYnRCD2jrMRZ8nBM2ZWYwnXnwYeOAHV+W9tOhAImwRwKF/95yAsVwd21ryHMJBcGH70qLagZ7Ttyt++qO/6+KAXJuKwZqjRlEtSEz8gZQeFfVYgcwSfo96oSMAzVr7V0L6HSDLRnpb6xxmbPdqNol4tQIDAQABo4GkMIGhMB8GA1UdIwQYMBaAFHhDe3amfrzQr35CN+s1fDuHAVE8MA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMGAGA1UdHwRZMFcwVaBToFGGT2h0dHA6Ly90cnVzdGVkc2VydmljZXMuaW50ZWwuY29tL2NvbnRlbnQvQ1JML1NHWC9BdHRlc3RhdGlvblJlcG9ydFNpZ25pbmdDQS5jcmwwDQYJKoZIhvcNAQELBQADggGBAGcIthtcK9IVRz4rRq+ZKE+7k50/OxUsmW8aavOzKb0iCx07YQ9rzi5nU73tME2yGRLzhSViFs/LpFa9lpQL6JL1aQwmDR74TxYGBAIi5f4I5TJoCCEqRHz91kpG6Uvyn2tLmnIdJbPE4vYvWLrtXXfFBSSPD4Afn7+3/XUggAlc7oCTizOfbbtOFlYA4g5KcYgS1J2ZAeMQqbUdZseZCcaZZZn65tdqee8UXZlDvx0+NdO0LR+5pFy+juM0wWbu59MvzcmTXbjsi7HY6zd53Yq5K244fwFHRQ8eOB0IWB+4PfM7FeAApZvlfqlKOlLcZL2uyVmzRkyR5yW72uo9mehX44CiPJ2fse9Y6eQtcfEhMPkmHXI01sN+KwPbpA39+xOsStjhP9N1Y1a2tQAVo+yVgLgV2Hws73Fc0o3wC78qPEA+v2aRs/Be3ZFDgDyghc/1fgU+7C+P6kbqd4poyb6IW8KCJbxfMJvkordNOgOUUxndPHEi/tb/U7uLjLOgPA==0\n\x06\x08*\x86H\xce=\x04\x03\x02\x03H\00E\x02!\0\xae6\x06\t@Sy\x8f\x8ec\x9d\xdci^Ex*\x92}\xdcG\x15A\x97\xd7\xd7\xd1\xccx\xe0\x1e\x08\x02 \x15Q\xa0BT\xde'~\xec\xbd\x027\xd3\xd8\x83\xf7\xe6Z\xc5H\xb4D\xf7\xe2\r\xa7\xe4^f\x10\x85p"; pub fn test_verify_mra_cert_should_work() { diff --git a/enclave-runtime/src/test/evm_pallet_tests.rs b/enclave-runtime/src/test/evm_pallet_tests.rs index fef912a289..228555bfab 100644 --- a/enclave-runtime/src/test/evm_pallet_tests.rs +++ b/enclave-runtime/src/test/evm_pallet_tests.rs @@ -29,7 +29,7 @@ use itp_node_api::metadata::{metadata_mocks::NodeMetadataMock, provider::NodeMet use itp_sgx_externalities::SgxExternalitiesTrait; use itp_stf_interface::StateCallInterface; use itp_stf_primitives::{traits::TrustedCallSigning, types::KeyPair}; -use itp_types::{AccountId, OpaqueCall, ShardIdentifier}; +use itp_types::{parentchain::ParentchainCall, AccountId, ShardIdentifier}; use primitive_types::H256; use sp_core::{crypto::Pair, H160, U256}; use std::{sync::Arc, vec::Vec}; @@ -37,7 +37,7 @@ use std::{sync::Arc, vec::Vec}; pub fn test_evm_call() { // given let (_, mut state, shard, mrenclave, ..) = test_setup(); - let mut opaque_vec = Vec::new(); + let mut parentchain_calls = Vec::new(); // Create the sender account. let sender = funded_pair(); @@ -74,11 +74,11 @@ pub fn test_evm_call() { Some(U256::from(0)), Vec::new(), ) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); // when let repo = Arc::new(NodeMetadataRepository::::default()); - TestStf::execute_call(&mut state, trusted_call, &mut opaque_vec, repo).unwrap(); + TestStf::execute_call(&mut state, trusted_call, &mut parentchain_calls, repo).unwrap(); // then assert_eq!( @@ -90,7 +90,7 @@ pub fn test_evm_call() { pub fn test_evm_counter() { // given let (_, mut state, shard, mrenclave, ..) = test_setup(); - let mut opaque_vec = Vec::new(); + let mut parentchain_calls = Vec::new(); // Create the sender account. let sender = funded_pair(); @@ -118,12 +118,12 @@ pub fn test_evm_counter() { Some(U256::from(0)), Vec::new(), ) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); // when let execution_address = evm_create_address(sender_evm_acc, 0); let repo = Arc::new(NodeMetadataRepository::::default()); - TestStf::execute_call(&mut state, trusted_call, &mut opaque_vec, repo).unwrap(); + TestStf::execute_call(&mut state, trusted_call, &mut parentchain_calls, repo).unwrap(); // then assert_eq!( @@ -155,11 +155,11 @@ pub fn test_evm_counter() { inc_function_input.to_vec(), 1, 1, - sender.clone().into(), + sender.into(), &mrenclave, &shard, &mut state, - &mut opaque_vec, + &mut parentchain_calls, 2, ); @@ -171,11 +171,11 @@ pub fn test_evm_counter() { Vec::new(), // Empty input calls the fallback function. 2, 2, - sender.clone().into(), + sender.into(), &mrenclave, &shard, &mut state, - &mut opaque_vec, + &mut parentchain_calls, 5, ); @@ -188,11 +188,11 @@ pub fn test_evm_counter() { inc_function_input, 3, 3, - sender.clone().into(), + sender.into(), &mrenclave, &shard, &mut state, - &mut opaque_vec, + &mut parentchain_calls, 6, ); @@ -205,21 +205,22 @@ pub fn test_evm_counter() { array_bytes::hex2bytes(&format!("{}{}", function_hash, add_value)).unwrap(); execute_and_verify_evm_call( - sender_acc.clone(), + sender_acc, sender_evm_acc, execution_address, add_function_input, 4, 4, - sender.clone().into(), + sender.into(), &mrenclave, &shard, &mut state, - &mut opaque_vec, + &mut parentchain_calls, 8, ); } +#[allow(clippy::too_many_arguments)] fn execute_and_verify_evm_call( sender_acc: AccountId, sender_evm_acc: H160, @@ -231,7 +232,7 @@ fn execute_and_verify_evm_call( mrenclave: &[u8; 32], shard: &ShardIdentifier, state: &mut State, - calls: &mut Vec, + calls: &mut Vec, counter_expected: u64, ) { let inc_call = TrustedCall::evm_call( @@ -246,7 +247,7 @@ fn execute_and_verify_evm_call( Some(U256::from(evm_nonce)), Vec::new(), ) - .sign(&pair, nonce, &mrenclave, &shard); + .sign(&pair, nonce, mrenclave, shard); let repo = Arc::new(NodeMetadataRepository::::default()); TestStf::execute_call(state, inc_call, calls, repo).unwrap(); @@ -259,7 +260,7 @@ fn execute_and_verify_evm_call( pub fn test_evm_create() { // given let (_, mut state, shard, mrenclave, ..) = test_setup(); - let mut opaque_vec = Vec::new(); + let mut parentchain_calls = Vec::new(); // Create the sender account. let sender = funded_pair(); @@ -277,7 +278,7 @@ pub fn test_evm_create() { let smart_contract = array_bytes::hex2bytes(smart_contract).unwrap(); let trusted_call = TrustedCall::evm_create( - sender_acc.clone(), + sender_acc, sender_evm_acc, smart_contract, U256::from(0), // value @@ -287,14 +288,14 @@ pub fn test_evm_create() { Some(U256::from(0)), Vec::new(), ) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); // Should be the first call of the evm account let nonce = state.execute_with(|| System::account_nonce(&sender_evm_substrate_addr)); assert_eq!(nonce, 0); let execution_address = evm_create_address(sender_evm_acc, nonce); let repo = Arc::new(NodeMetadataRepository::::default()); - TestStf::execute_call(&mut state, trusted_call, &mut opaque_vec, repo).unwrap(); + TestStf::execute_call(&mut state, trusted_call, &mut parentchain_calls, repo).unwrap(); assert_eq!( execution_address, @@ -313,7 +314,7 @@ pub fn test_evm_create() { pub fn test_evm_create2() { // given let (_, mut state, shard, mrenclave, ..) = test_setup(); - let mut opaque_vec = Vec::new(); + let mut parentchain_calls = Vec::new(); // Create the sender account. let sender = funded_pair(); @@ -332,7 +333,7 @@ pub fn test_evm_create2() { let smart_contract = array_bytes::hex2bytes(smart_contract).unwrap(); let trusted_call = TrustedCall::evm_create2( - sender_acc.clone(), + sender_acc, sender_evm_acc, smart_contract.clone(), salt, @@ -343,13 +344,13 @@ pub fn test_evm_create2() { Some(U256::from(0)), Vec::new(), ) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); // when let code_hash = create_code_hash(&smart_contract); let execution_address = evm_create2_address(sender_evm_acc, salt, code_hash); let repo = Arc::new(NodeMetadataRepository::::default()); - TestStf::execute_call(&mut state, trusted_call, &mut opaque_vec, repo).unwrap(); + TestStf::execute_call(&mut state, trusted_call, &mut parentchain_calls, repo).unwrap(); // then assert_eq!( diff --git a/enclave-runtime/src/test/fixtures/test_setup.rs b/enclave-runtime/src/test/fixtures/test_setup.rs index a1deee2443..27d6df863c 100644 --- a/enclave-runtime/src/test/fixtures/test_setup.rs +++ b/enclave-runtime/src/test/fixtures/test_setup.rs @@ -111,10 +111,7 @@ pub fn test_setup() -> ( pub fn test_top_pool() -> TestTopPool { let chain_api = Arc::new(SidechainApi::::new()); - let top_pool = - BasicPool::create(Default::default(), chain_api, Arc::new(TestRpcResponder::new())); - - top_pool + BasicPool::create(Default::default(), chain_api, Arc::new(TestRpcResponder::new())) } pub fn enclave_call_signer(key_source: &Source) -> spEd25519::Pair { diff --git a/enclave-runtime/src/test/ipfs_tests.rs b/enclave-runtime/src/test/ipfs_tests.rs index 27b187a047..f1f94d3696 100644 --- a/enclave-runtime/src/test/ipfs_tests.rs +++ b/enclave-runtime/src/test/ipfs_tests.rs @@ -31,7 +31,7 @@ fn test_ocall_read_write_ipfs() { OcallApi.read_ipfs(&cid).unwrap(); let cid_str = std::str::from_utf8(&cid.0).unwrap(); - let mut f = File::open(&cid_str).unwrap(); + let mut f = File::open(cid_str).unwrap(); let mut content_buf = Vec::new(); f.read_to_end(&mut content_buf).unwrap(); info!("reading file {:?} of size {} bytes", f, &content_buf.len()); diff --git a/enclave-runtime/src/test/mocks/rpc_responder_mock.rs b/enclave-runtime/src/test/mocks/rpc_responder_mock.rs index 74e22a29e1..3628f1480c 100644 --- a/enclave-runtime/src/test/mocks/rpc_responder_mock.rs +++ b/enclave-runtime/src/test/mocks/rpc_responder_mock.rs @@ -28,6 +28,11 @@ impl RpcResponderMock { RpcResponderMock { _hash: PhantomData } } } +impl Default for RpcResponderMock { + fn default() -> Self { + Self::new() + } +} impl SendRpcResponse for RpcResponderMock where diff --git a/enclave-runtime/src/test/sidechain_aura_tests.rs b/enclave-runtime/src/test/sidechain_aura_tests.rs index fa52b8aae5..14420a6500 100644 --- a/enclave-runtime/src/test/sidechain_aura_tests.rs +++ b/enclave-runtime/src/test/sidechain_aura_tests.rs @@ -34,9 +34,7 @@ use ita_stf::{ test_genesis::{endowed_account, second_endowed_account, unendowed_account}, Balance, Getter, TrustedCall, TrustedCallSigned, }; -use itc_parentchain::light_client::mocks::validator_access_mock::ValidatorAccessMock; use itc_parentchain_test::ParentchainHeaderBuilder; -use itp_extrinsics_factory::mock::ExtrinsicsFactoryMock; use itp_node_api::metadata::{metadata_mocks::NodeMetadataMock, provider::NodeMetadataRepository}; use itp_ocall_api::EnclaveAttestationOCallApi; use itp_settings::{ @@ -97,7 +95,7 @@ pub fn produce_sidechain_block_and_import_it() { let stf_executor = Arc::new(TestStfExecutor::new( ocall_api.clone(), state_handler.clone(), - node_metadata_repo.clone(), + node_metadata_repo, )); let top_pool = create_top_pool(); @@ -116,11 +114,9 @@ pub fn produce_sidechain_block_and_import_it() { parentchain_block_import_trigger.clone(), ocall_api.clone(), )); - let block_composer = Arc::new(TestBlockComposer::new(signer.clone(), state_key_repo.clone())); + let block_composer = Arc::new(TestBlockComposer::new(signer, state_key_repo)); let proposer_environment = - ProposerFactory::new(top_pool_author.clone(), stf_executor.clone(), block_composer); - let extrinsics_factory = ExtrinsicsFactoryMock::default(); - let validator_access = ValidatorAccessMock::default(); + ProposerFactory::new(top_pool_author.clone(), stf_executor, block_composer); info!("Create trusted operations.."); let sender = endowed_account(); @@ -141,7 +137,7 @@ pub fn produce_sidechain_block_and_import_it() { &shielding_key, sender_with_low_balance, receiver.public().into(), - 200000, + ita_stf::test_genesis::SECOND_ENDOWED_ACC_FUNDS + 1, ); info!("Add trusted operations to TOP pool.."); executor::block_on(top_pool_author.submit_top(trusted_operation, shard_id)).unwrap(); @@ -155,8 +151,15 @@ pub fn produce_sidechain_block_and_import_it() { let timestamp = duration_now(); let slot = slot_from_timestamp_and_duration(duration_now(), SLOT_DURATION); let ends_at = timestamp + SLOT_DURATION; - let slot_info = - SlotInfo::new(slot, timestamp, SLOT_DURATION, ends_at, parentchain_header.clone()); + let slot_info = SlotInfo::new( + slot, + timestamp, + SLOT_DURATION, + ends_at, + parentchain_header.clone(), + None, + None, + ); info!("Test setup is done."); @@ -164,11 +167,13 @@ pub fn produce_sidechain_block_and_import_it() { info!("Executing AURA on slot.."); let (blocks, opaque_calls) = - exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _>( + exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _, _, _>( slot_info, signer, - ocall_api.clone(), + ocall_api, parentchain_block_import_trigger.clone(), + None::>, + None::>, proposer_environment, shards, ) @@ -195,12 +200,10 @@ pub fn produce_sidechain_block_and_import_it() { let propose_to_block_import_ocall_api = Arc::new(ProposeToImportOCallApi::new(parentchain_header, block_importer)); - send_blocks_and_extrinsics::( + send_blocks_and_extrinsics::( blocks, opaque_calls, propose_to_block_import_ocall_api, - &validator_access, - &extrinsics_factory, ) .unwrap(); @@ -219,7 +222,7 @@ pub fn produce_sidechain_block_and_import_it() { let free_balance = TestStf::get_account_data(&mut state, &receiver.public().into()).free; assert_eq!(free_balance, transfered_amount); assert!(TestStf::get_event_count(&mut state) > 0); - assert!(TestStf::get_events(&mut state).len() > 0); + assert!(!TestStf::get_events(&mut state).is_empty()); } fn encrypted_trusted_operation_transfer_balance< diff --git a/enclave-runtime/src/test/sidechain_event_tests.rs b/enclave-runtime/src/test/sidechain_event_tests.rs index bf83f551f6..ef291bf849 100644 --- a/enclave-runtime/src/test/sidechain_event_tests.rs +++ b/enclave-runtime/src/test/sidechain_event_tests.rs @@ -29,9 +29,7 @@ use crate::{ }; use ita_sgx_runtime::Runtime; use ita_stf::{helpers::set_block_number, Getter, TrustedCallSigned}; -use itc_parentchain::light_client::mocks::validator_access_mock::ValidatorAccessMock; use itc_parentchain_test::ParentchainHeaderBuilder; -use itp_extrinsics_factory::mock::ExtrinsicsFactoryMock; use itp_node_api::metadata::{metadata_mocks::NodeMetadataMock, provider::NodeMetadataRepository}; use itp_settings::{ sidechain::SLOT_DURATION, @@ -85,7 +83,7 @@ pub fn ensure_events_get_reset_upon_block_proposal() { let stf_executor = Arc::new(TestStfExecutor::new( ocall_api.clone(), state_handler.clone(), - node_metadata_repo.clone(), + node_metadata_repo, )); let top_pool = create_top_pool(); @@ -104,11 +102,8 @@ pub fn ensure_events_get_reset_upon_block_proposal() { parentchain_block_import_trigger.clone(), ocall_api.clone(), )); - let block_composer = Arc::new(TestBlockComposer::new(signer.clone(), state_key_repo.clone())); - let proposer_environment = - ProposerFactory::new(top_pool_author.clone(), stf_executor.clone(), block_composer); - let extrinsics_factory = ExtrinsicsFactoryMock::default(); - let validator_access = ValidatorAccessMock::default(); + let block_composer = Arc::new(TestBlockComposer::new(signer, state_key_repo)); + let proposer_environment = ProposerFactory::new(top_pool_author, stf_executor, block_composer); // Add some events to the state. let topic_hash = H256::from([7; 32]); @@ -133,16 +128,25 @@ pub fn ensure_events_get_reset_upon_block_proposal() { let timestamp = duration_now(); let slot = slot_from_timestamp_and_duration(duration_now(), SLOT_DURATION); let ends_at = timestamp + SLOT_DURATION; - let slot_info = - SlotInfo::new(slot, timestamp, SLOT_DURATION, ends_at, parentchain_header.clone()); + let slot_info = SlotInfo::new( + slot, + timestamp, + SLOT_DURATION, + ends_at, + parentchain_header.clone(), + None, + None, + ); info!("Executing AURA on slot.."); let (blocks, opaque_calls) = - exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _>( + exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _, _, _>( slot_info, signer, - ocall_api.clone(), - parentchain_block_import_trigger.clone(), + ocall_api, + parentchain_block_import_trigger, + None::>, + None::>, proposer_environment, shards, ) @@ -152,12 +156,10 @@ pub fn ensure_events_get_reset_upon_block_proposal() { let propose_to_block_import_ocall_api = Arc::new(ProposeToImportOCallApi::new(parentchain_header, block_importer)); - send_blocks_and_extrinsics::( + send_blocks_and_extrinsics::( blocks, opaque_calls, propose_to_block_import_ocall_api, - &validator_access, - &extrinsics_factory, ) .unwrap(); diff --git a/enclave-runtime/src/test/tests_main.rs b/enclave-runtime/src/test/tests_main.rs index be88d19a8a..e18cccde1d 100644 --- a/enclave-runtime/src/test/tests_main.rs +++ b/enclave-runtime/src/test/tests_main.rs @@ -57,7 +57,7 @@ use itp_stf_primitives::{ use itp_stf_state_handler::handle_state::HandleState; use itp_test::mock::handle_state_mock; use itp_top_pool_author::{test_utils::submit_operation_to_top_pool, traits::AuthorApi}; -use itp_types::{AccountId, Block, Header}; +use itp_types::{AccountId, Balance, Block, Header}; use its_primitives::{ traits::{ Block as BlockTrait, BlockData, Header as SidechainHeaderTrait, @@ -290,12 +290,11 @@ fn test_differentiate_getter_and_call_works() { // create accounts let sender = funded_pair(); - let signed_getter = - TrustedGetter::free_balance(sender.public().into()).sign(&sender.clone().into()); + let signed_getter = TrustedGetter::free_balance(sender.public().into()).sign(&sender.into()); let signed_call = TrustedCall::balance_set_balance(sender.public().into(), sender.public().into(), 42, 42) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); let trusted_operation = direct_top(signed_call); // when @@ -352,8 +351,7 @@ fn test_create_block_and_confirmation_works() { // when let execution_result = execute_trusted_calls(&shard, stf_executor.as_ref(), &top_pool_author); - let executed_operation_hashes = - execution_result.get_executed_operation_hashes().iter().copied().collect(); + let executed_operation_hashes = execution_result.get_executed_operation_hashes().to_vec(); let signed_block = block_composer .compose_block( @@ -382,9 +380,13 @@ fn test_create_state_diff() { let sender = funded_pair(); let receiver = unfunded_public(); - - let signed_call = TrustedCall::balance_transfer(sender.public().into(), receiver.into(), 1000) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + const TX_AMOUNT: Balance = 1_000_000_000_000; + let signed_call = TrustedCall::balance_transfer( + sender.public().into(), + receiver.into(), + TX_AMOUNT, + ) + .sign(&sender.into(), 0, &mrenclave, &shard); let trusted_operation = direct_top(signed_call); submit_operation_to_top_pool( @@ -398,8 +400,7 @@ fn test_create_state_diff() { // when let execution_result = execute_trusted_calls(&shard, stf_executor.as_ref(), &top_pool_author); - let executed_operation_hashes = - execution_result.get_executed_operation_hashes().iter().copied().collect(); + let executed_operation_hashes = execution_result.get_executed_operation_hashes().to_vec(); let signed_block = block_composer .compose_block( @@ -418,16 +419,19 @@ fn test_create_state_diff() { // then let sender_acc_info: AccountInfo = - get_from_state_diff(&state_diff, &account_key_hash::(&sender.public().into())); + get_from_state_diff(state_diff, &account_key_hash::(&sender.public().into())); let receiver_acc_info: AccountInfo = - get_from_state_diff(&state_diff, &account_key_hash::(&receiver.into())); + get_from_state_diff(state_diff, &account_key_hash::(&receiver.into())); // state diff should consist of the following updates: - // (last_hash, sidechain block_number, sender_funds, receiver_funds, [no clear, after polkadot_v0.9.26 update], events) - assert_eq!(state_diff.len(), 6); - assert_eq!(receiver_acc_info.data.free, 1000); - assert_eq!(sender_acc_info.data.free, 1000); + // (last_hash, sidechain block_number, sender_funds, receiver_funds, fee_recipient account [no clear, after polkadot_v0.9.26 update], events) + assert_eq!(state_diff.len(), 7); + assert_eq!(receiver_acc_info.data.free, TX_AMOUNT); + assert_eq!( + sender_acc_info.data.free, + ita_stf::test_genesis::ENDOWED_ACC_FUNDS - TX_AMOUNT - ita_stf::STF_TX_FEE + ); } fn test_executing_call_updates_account_nonce() { @@ -439,7 +443,7 @@ fn test_executing_call_updates_account_nonce() { let trusted_operation = TrustedCall::balance_transfer(sender.public().into(), receiver.into(), 1000) - .sign(&sender.clone().into(), 0, &mrenclave, &shard) + .sign(&sender.into(), 0, &mrenclave, &shard) .into_trusted_operation(false); submit_operation_to_top_pool( @@ -478,9 +482,9 @@ fn test_call_set_update_parentchain_block() { TestStf::update_parentchain_block(&mut state, header.clone()).unwrap(); - assert_eq!(header.hash(), state.execute_with(|| Parentchain::block_hash())); - assert_eq!(parent_hash, state.execute_with(|| Parentchain::parent_hash())); - assert_eq!(block_number, state.execute_with(|| Parentchain::block_number())); + assert_eq!(header.hash(), state.execute_with(Parentchain::block_hash)); + assert_eq!(parent_hash, state.execute_with(Parentchain::parent_hash)); + assert_eq!(block_number, state.execute_with(Parentchain::block_number)); } fn test_signature_must_match_public_sender_in_call() { @@ -493,7 +497,7 @@ fn test_signature_must_match_public_sender_in_call() { let trusted_operation = TrustedCall::balance_transfer(victim.into(), receiver.public().into(), 1000) - .sign(&receiver.clone().into(), 10, &mrenclave, &shard) + .sign(&receiver.into(), 10, &mrenclave, &shard) .into_trusted_operation(true); submit_operation_to_top_pool( @@ -520,7 +524,7 @@ fn test_invalid_nonce_call_is_not_executed() { let trusted_operation = TrustedCall::balance_transfer(sender.public().into(), receiver.into(), 1000) - .sign(&sender.clone().into(), 10, &mrenclave, &shard) + .sign(&sender.into(), 10, &mrenclave, &shard) .into_trusted_operation(true); submit_operation_to_top_pool( @@ -544,8 +548,12 @@ fn test_non_root_shielding_call_is_not_executed() { let sender = funded_pair(); let sender_acc: AccountId = sender.public().into(); - let signed_call = TrustedCall::balance_shield(sender_acc.clone(), sender_acc.clone(), 1000) - .sign(&sender.into(), 0, &mrenclave, &shard); + let signed_call = TrustedCall::balance_shield(sender_acc.clone(), sender_acc, 1000).sign( + &sender.into(), + 0, + &mrenclave, + &shard, + ); submit_operation_to_top_pool( top_pool_author.as_ref(), @@ -569,12 +577,9 @@ fn test_shielding_call_with_enclave_self_is_executed() { let sender_account: AccountId = sender.public().into(); let enclave_call_signer = enclave_call_signer(&shielding_key); - let signed_call = TrustedCall::balance_shield( - enclave_call_signer.public().into(), - sender_account.clone(), - 1000, - ) - .sign(&enclave_call_signer.into(), 0, &mrenclave, &shard); + let signed_call = + TrustedCall::balance_shield(enclave_call_signer.public().into(), sender_account, 1000) + .sign(&enclave_call_signer.into(), 0, &mrenclave, &shard); let trusted_operation = TrustedOperation::::indirect_call(signed_call); @@ -611,11 +616,11 @@ pub fn test_retrieve_events() { receiver.public().into(), transfer_value, ) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); let repo = Arc::new(NodeMetadataRepository::::default()); TestStf::execute_call(&mut state, trusted_call, &mut opaque_vec, repo).unwrap(); - assert_eq!(TestStf::get_events(&mut state).len(), 3); + assert_eq!(TestStf::get_events(&mut state).len(), 4); } pub fn test_retrieve_event_count() { @@ -633,14 +638,14 @@ pub fn test_retrieve_event_count() { receiver.public().into(), transfer_value, ) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); // when let repo = Arc::new(NodeMetadataRepository::::default()); TestStf::execute_call(&mut state, trusted_call, &mut opaque_vec, repo).unwrap(); let event_count = TestStf::get_event_count(&mut state); - assert_eq!(event_count, 3); + assert_eq!(event_count, 4); } pub fn test_reset_events() { @@ -657,13 +662,13 @@ pub fn test_reset_events() { receiver.public().into(), transfer_value, ) - .sign(&sender.clone().into(), 0, &mrenclave, &shard); + .sign(&sender.into(), 0, &mrenclave, &shard); let repo = Arc::new(NodeMetadataRepository::::default()); TestStf::execute_call(&mut state, trusted_call, &mut opaque_vec, repo).unwrap(); let receiver_acc_info = TestStf::get_account_data(&mut state, &receiver.public().into()); assert_eq!(receiver_acc_info.free, transfer_value); // Ensure that there really have been events generated. - assert_eq!(TestStf::get_events(&mut state).len(), 3); + assert_eq!(TestStf::get_events(&mut state).len(), 4); // Remove the events. TestStf::reset_events(&mut state); @@ -678,19 +683,18 @@ fn execute_trusted_calls( top_pool_author: &TestTopPoolAuthor, ) -> BatchExecutionResult { let top_pool_calls = top_pool_author.get_pending_trusted_calls(*shard); - let execution_result = stf_executor + stf_executor .propose_state_update( &top_pool_calls, &latest_parentchain_header(), - &shard, + shard, Duration::from_millis(600), |mut s| { s.set_block_number(&s.get_block_number().map_or(1, |n| n + 1)); s }, ) - .unwrap(); - execution_result + .unwrap() } // helper functions diff --git a/enclave-runtime/src/test/top_pool_tests.rs b/enclave-runtime/src/test/top_pool_tests.rs index 9e9eee6217..70cb92cfb3 100644 --- a/enclave-runtime/src/test/top_pool_tests.rs +++ b/enclave-runtime/src/test/top_pool_tests.rs @@ -81,7 +81,7 @@ pub fn process_indirect_call_in_top_pool() { let top_pool_author = Arc::new(TestTopPoolAuthor::new( top_pool, AllowAllTopsFilter::::new(), - state_handler.clone(), + state_handler, shielding_key_repo, Arc::new(MetricsOCallMock::default()), )); @@ -99,7 +99,7 @@ pub fn submit_shielding_call_to_top_pool() { let signer = TestSigner::from_seed(b"42315678901234567890123456789012"); let shielding_key = TestShieldingKey::new().unwrap(); - let shielding_key_repo = Arc::new(TestShieldingKeyRepo::new(shielding_key.clone())); + let shielding_key_repo = Arc::new(TestShieldingKeyRepo::new(shielding_key)); let header = ParentchainHeaderBuilder::default().build(); let ocall_api = create_ocall_api(&header, &signer); @@ -122,7 +122,7 @@ pub fn submit_shielding_call_to_top_pool() { let enclave_signer = Arc::new(StfEnclaveSigner::<_, _, _, TestStf, _, TrustedCallSigned, Getter>::new( state_observer, - ocall_api.clone(), + ocall_api, shielding_key_repo.clone(), top_pool_author.clone(), )); @@ -196,7 +196,12 @@ fn create_shielding_call_extrinsic( let shield_funds_indexes = dummy_node_metadata.shield_funds_call_indexes().unwrap(); let opaque_extrinsic = OpaqueExtrinsic::from_bytes( ParentchainUncheckedExtrinsic::::new_signed( - (shield_funds_indexes, shard, target_account, 1000u128), + ( + shield_funds_indexes, + shard, + target_account, + ita_stf::test_genesis::SECOND_ENDOWED_ACC_FUNDS, + ), Address::Address32([1u8; 32]), MultiSignature::Ed25519(signature), default_extra_for_test.signed_extra(), diff --git a/enclave-runtime/src/tls_ra/tests.rs b/enclave-runtime/src/tls_ra/tests.rs index 37b69c64f7..5cdbd2a184 100644 --- a/enclave-runtime/src/tls_ra/tests.rs +++ b/enclave-runtime/src/tls_ra/tests.rs @@ -90,8 +90,7 @@ pub fn test_tls_ra_server_client_networking() { let client_shielding_key = Arc::new(RwLock::new(Vec::new())); let client_state_key = Arc::new(RwLock::new(initial_client_state_key.clone())); let client_state = Arc::new(RwLock::new(initial_client_state.clone())); - let client_light_client_state = - Arc::new(RwLock::new(initial_client_light_client_state.clone())); + let client_light_client_state = Arc::new(RwLock::new(initial_client_light_client_state)); let client_seal_handler = SealHandlerMock::new( client_shielding_key.clone(), @@ -118,7 +117,7 @@ pub fn test_tls_ra_server_client_networking() { Some("E_SIZE), shard, SKIP_RA, - client_seal_handler.clone(), + client_seal_handler, client_account, ); diff --git a/enclave-runtime/src/top_pool_execution.rs b/enclave-runtime/src/top_pool_execution.rs index 7fc1dd1541..7ff928c864 100644 --- a/enclave-runtime/src/top_pool_execution.rs +++ b/enclave-runtime/src/top_pool_execution.rs @@ -25,8 +25,15 @@ use crate::{ sync::{EnclaveLock, EnclaveStateRWLock}, utils::{ 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, + get_extrinsic_factory_from_target_a_solo_or_parachain, + get_extrinsic_factory_from_target_b_solo_or_parachain, + get_stf_executor_from_solo_or_parachain, + get_triggered_dispatcher_from_integritee_solo_or_parachain, + get_triggered_dispatcher_from_target_a_solo_or_parachain, + get_triggered_dispatcher_from_target_b_solo_or_parachain, + get_validator_accessor_from_integritee_solo_or_parachain, + get_validator_accessor_from_target_a_solo_or_parachain, + get_validator_accessor_from_target_b_solo_or_parachain, }, }; use codec::Encode; @@ -44,7 +51,7 @@ use itp_settings::sidechain::SLOT_DURATION; use itp_sgx_crypto::key_repository::AccessKey; use itp_stf_state_handler::query_shard_state::QueryShardState; use itp_time_utils::duration_now; -use itp_types::{Block, OpaqueCall, H256}; +use itp_types::{parentchain::ParentchainCall, Block, OpaqueCall, H256}; use its_primitives::{ traits::{ Block as SidechainBlockTrait, Header as HeaderTrait, ShardIdentifierFor, SignedBlock, @@ -92,25 +99,53 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { let slot_beginning_timestamp = duration_now(); - let parentchain_import_dispatcher = get_triggered_dispatcher_from_solo_or_parachain()?; - - let validator_access = get_validator_accessor_from_solo_or_parachain()?; + let integritee_parentchain_import_dispatcher = + get_triggered_dispatcher_from_integritee_solo_or_parachain()?; + let maybe_target_a_parentchain_import_dispatcher = + get_triggered_dispatcher_from_target_a_solo_or_parachain().ok(); + let maybe_target_b_parentchain_import_dispatcher = + get_triggered_dispatcher_from_target_b_solo_or_parachain().ok(); + + let maybe_latest_target_a_parentchain_header = + if let Some(ref _triggered_dispatcher) = maybe_target_a_parentchain_import_dispatcher { + let validator_access = get_validator_accessor_from_target_a_solo_or_parachain()?; + Some(validator_access.execute_on_validator(|v| { + let latest_parentchain_header = v.latest_finalized_header()?; + Ok(latest_parentchain_header) + })?) + } else { + None + }; + + let maybe_latest_target_b_parentchain_header = + if let Some(ref _triggered_dispatcher) = maybe_target_b_parentchain_import_dispatcher { + let validator_access = get_validator_accessor_from_target_b_solo_or_parachain()?; + Some(validator_access.execute_on_validator(|v| { + let latest_parentchain_header = v.latest_finalized_header()?; + Ok(latest_parentchain_header) + })?) + } else { + None + }; + + let integritee_validator_access = get_validator_accessor_from_integritee_solo_or_parachain()?; // This gets the latest imported block. We accept that all of AURA, up until the block production // itself, will operate on a parentchain block that is potentially outdated by one block // (in case we have a block in the queue, but not imported yet). - let current_parentchain_header = validator_access.execute_on_validator(|v| { - let latest_parentchain_header = v.latest_finalized_header()?; - Ok(latest_parentchain_header) - })?; + let current_integritee_parentchain_header = + integritee_validator_access.execute_on_validator(|v| { + let latest_parentchain_header = v.latest_finalized_header()?; + Ok(latest_parentchain_header) + })?; // Import any sidechain blocks that are in the import queue. In case we are missing blocks, // a peer sync will happen. If that happens, the slot time might already be used up just by this import. let sidechain_block_import_queue_worker = GLOBAL_SIDECHAIN_IMPORT_QUEUE_WORKER_COMPONENT.get()?; - let latest_parentchain_header = - sidechain_block_import_queue_worker.process_queue(¤t_parentchain_header)?; + let latest_integritee_parentchain_header = sidechain_block_import_queue_worker + .process_queue(¤t_integritee_parentchain_header)?; trace!( "Elapsed time to process sidechain block import queue: {} ms", @@ -123,8 +158,6 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { let block_composer = GLOBAL_SIDECHAIN_BLOCK_COMPOSER_COMPONENT.get()?; - let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; - let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; @@ -134,7 +167,9 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { match yield_next_slot( slot_beginning_timestamp, SLOT_DURATION, - latest_parentchain_header, + latest_integritee_parentchain_header, + maybe_latest_target_a_parentchain_header, + maybe_latest_target_b_parentchain_header, &mut LastSlot, )? { Some(slot) => { @@ -152,14 +187,17 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { block_composer, ); - let (blocks, opaque_calls) = exec_aura_on_slot::<_, _, SignedSidechainBlock, _, _, _>( - slot.clone(), - authority, - ocall_api.clone(), - parentchain_import_dispatcher, - env, - shards, - )?; + let (blocks, parentchain_calls) = + exec_aura_on_slot::<_, _, SignedSidechainBlock, _, _, _, _, _>( + slot.clone(), + authority, + ocall_api.clone(), + integritee_parentchain_import_dispatcher, + maybe_target_a_parentchain_import_dispatcher, + maybe_target_b_parentchain_import_dispatcher, + env, + shards, + )?; debug!("Aura executed successfully"); @@ -168,13 +206,7 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { log_remaining_slot_duration(&slot, "After AURA"); - send_blocks_and_extrinsics::( - blocks, - opaque_calls, - ocall_api, - validator_access.as_ref(), - extrinsics_factory.as_ref(), - )?; + send_blocks_and_extrinsics::(blocks, parentchain_calls, ocall_api)?; log_remaining_slot_duration(&slot, "After broadcasting and sending extrinsic"); }, @@ -189,21 +221,26 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { } /// Executes aura for the given `slot`. +#[allow(clippy::too_many_arguments)] pub(crate) fn exec_aura_on_slot< Authority, ParentchainBlock, SignedSidechainBlock, OCallApi, PEnvironment, - BlockImportTrigger, + IntegriteeBlockImportTrigger, + TargetABlockImportTrigger, + TargetBBlockImportTrigger, >( slot: SlotInfo, authority: Authority, ocall_api: Arc, - block_import_trigger: Arc, + integritee_block_import_trigger: Arc, + maybe_target_a_block_import_trigger: Option>, + maybe_target_b_block_import_trigger: Option>, proposer_environment: PEnvironment, shards: Vec>, -) -> Result<(Vec, Vec)> +) -> Result<(Vec, Vec)> where ParentchainBlock: BlockTrait, SignedSidechainBlock: @@ -218,58 +255,84 @@ where NumberFor: BlockNumberOps, PEnvironment: Environment + Send + Sync, - BlockImportTrigger: + IntegriteeBlockImportTrigger: + TriggerParentchainBlockImport>, + TargetABlockImportTrigger: + TriggerParentchainBlockImport>, + TargetBBlockImportTrigger: TriggerParentchainBlockImport>, { debug!("[Aura] Executing aura for slot: {:?}", slot); - let mut aura = Aura::<_, ParentchainBlock, SignedSidechainBlock, PEnvironment, _, _>::new( - authority, - ocall_api.as_ref().clone(), - block_import_trigger, - proposer_environment, - ) - .with_claim_strategy(SlotClaimStrategy::RoundRobin); - - let (blocks, xts): (Vec<_>, Vec<_>) = + let mut aura = + Aura::<_, ParentchainBlock, SignedSidechainBlock, PEnvironment, _, _, _, _>::new( + authority, + ocall_api.as_ref().clone(), + integritee_block_import_trigger, + maybe_target_a_block_import_trigger, + maybe_target_b_block_import_trigger, + proposer_environment, + ) + .with_claim_strategy(SlotClaimStrategy::RoundRobin); + + let (blocks, pxts): (Vec<_>, Vec<_>) = PerShardSlotWorkerScheduler::on_slot(&mut aura, slot, shards) .into_iter() .map(|r| (r.block, r.parentchain_effects)) .unzip(); - let opaque_calls: Vec = xts.into_iter().flatten().collect(); + let opaque_calls: Vec = pxts.into_iter().flatten().collect(); Ok((blocks, opaque_calls)) } /// Broadcasts sidechain blocks to fellow peers and sends opaque calls as extrinsic to the parentchain. -pub(crate) fn send_blocks_and_extrinsics< - ParentchainBlock, - SignedSidechainBlock, - OCallApi, - ValidatorAccessor, - ExtrinsicsFactory, ->( +pub(crate) fn send_blocks_and_extrinsics( blocks: Vec, - opaque_calls: Vec, + parentchain_calls: Vec, ocall_api: Arc, - validator_access: &ValidatorAccessor, - extrinsics_factory: &ExtrinsicsFactory, ) -> Result<()> where ParentchainBlock: BlockTrait, SignedSidechainBlock: SignedBlock + 'static, OCallApi: EnclaveSidechainOCallApi, - ValidatorAccessor: ValidatorAccess + Send + Sync + 'static, NumberFor: BlockNumberOps, - ExtrinsicsFactory: CreateExtrinsics, { debug!("Proposing {} sidechain block(s) (broadcasting to peers)", blocks.len()); ocall_api.propose_sidechain_blocks(blocks)?; - let xts = extrinsics_factory.create_extrinsics(opaque_calls.as_slice(), None)?; - - debug!("Sending sidechain block(s) confirmation extrinsic.. "); - validator_access.execute_mut_on_validator(|v| v.send_extrinsics(xts))?; + let calls: Vec = parentchain_calls + .iter() + .filter_map(|parentchain_call| parentchain_call.as_integritee()) + .collect(); + debug!("Enclave wants to send {} extrinsics to Integritee Parentchain", calls.len()); + if !calls.is_empty() { + let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; + let xts = extrinsics_factory.create_extrinsics(calls.as_slice(), None)?; + let validator_access = get_validator_accessor_from_integritee_solo_or_parachain()?; + validator_access.execute_mut_on_validator(|v| v.send_extrinsics(xts))?; + } + let calls: Vec = parentchain_calls + .iter() + .filter_map(|parentchain_call| parentchain_call.as_target_a()) + .collect(); + debug!("Enclave wants to send {} extrinsics to TargetA Parentchain", calls.len()); + if !calls.is_empty() { + let extrinsics_factory = get_extrinsic_factory_from_target_a_solo_or_parachain()?; + let xts = extrinsics_factory.create_extrinsics(calls.as_slice(), None)?; + let validator_access = get_validator_accessor_from_target_a_solo_or_parachain()?; + validator_access.execute_mut_on_validator(|v| v.send_extrinsics(xts))?; + } + let calls: Vec = parentchain_calls + .iter() + .filter_map(|parentchain_call| parentchain_call.as_target_b()) + .collect(); + debug!("Enclave wants to send {} extrinsics to TargetB Parentchain", calls.len()); + if !calls.is_empty() { + let extrinsics_factory = get_extrinsic_factory_from_target_b_solo_or_parachain()?; + let xts = extrinsics_factory.create_extrinsics(calls.as_slice(), None)?; + let validator_access = get_validator_accessor_from_target_b_solo_or_parachain()?; + validator_access.execute_mut_on_validator(|v| v.send_extrinsics(xts))?; + } Ok(()) } diff --git a/enclave-runtime/src/utils.rs b/enclave-runtime/src/utils.rs index 62c12ab93e..d1b9702ecc 100644 --- a/enclave-runtime/src/utils.rs +++ b/enclave-runtime/src/utils.rs @@ -18,8 +18,10 @@ use crate::{ error::{Error, Result}, initialization::global_components::{ EnclaveExtrinsicsFactory, EnclaveNodeMetadataRepository, EnclaveStfEnclaveSigner, - EnclaveStfExecutor, EnclaveValidatorAccessor, IntegriteeParentchainBlockImportDispatcher, + EnclaveStfExecutor, EnclaveValidatorAccessor, IntegriteeParentchainTriggeredBlockImportDispatcher, + TargetAParentchainTriggeredBlockImportDispatcher, + TargetBParentchainTriggeredBlockImportDispatcher, GLOBAL_INTEGRITEE_PARACHAIN_HANDLER_COMPONENT, GLOBAL_INTEGRITEE_SOLOCHAIN_HANDLER_COMPONENT, GLOBAL_TARGET_A_PARACHAIN_HANDLER_COMPONENT, GLOBAL_TARGET_A_SOLOCHAIN_HANDLER_COMPONENT, GLOBAL_TARGET_B_PARACHAIN_HANDLER_COMPONENT, @@ -74,7 +76,7 @@ pub unsafe fn utf8_str_from_raw<'a>( // FIXME: When solving #1080, these helper functions should be obsolete, because no dynamic allocation // is necessary anymore. -pub(crate) fn get_triggered_dispatcher_from_solo_or_parachain( +pub(crate) fn get_triggered_dispatcher_from_integritee_solo_or_parachain( ) -> Result> { let dispatcher = if let Ok(solochain_handler) = GLOBAL_INTEGRITEE_SOLOCHAIN_HANDLER_COMPONENT.get() { @@ -87,16 +89,42 @@ pub(crate) fn get_triggered_dispatcher_from_solo_or_parachain( Ok(dispatcher) } -pub(crate) fn get_triggered_dispatcher( - dispatcher: Arc, -) -> Result> { +pub(crate) fn get_triggered_dispatcher_from_target_a_solo_or_parachain( +) -> Result> { + let dispatcher = + if let Ok(solochain_handler) = GLOBAL_TARGET_A_SOLOCHAIN_HANDLER_COMPONENT.get() { + get_triggered_dispatcher(solochain_handler.import_dispatcher.clone())? + } else if let Ok(parachain_handler) = GLOBAL_TARGET_A_PARACHAIN_HANDLER_COMPONENT.get() { + get_triggered_dispatcher(parachain_handler.import_dispatcher.clone())? + } else { + return Err(Error::NoTargetAParentchainAssigned) + }; + Ok(dispatcher) +} + +pub(crate) fn get_triggered_dispatcher_from_target_b_solo_or_parachain( +) -> Result> { + let dispatcher = + if let Ok(solochain_handler) = GLOBAL_TARGET_B_SOLOCHAIN_HANDLER_COMPONENT.get() { + get_triggered_dispatcher(solochain_handler.import_dispatcher.clone())? + } else if let Ok(parachain_handler) = GLOBAL_TARGET_B_PARACHAIN_HANDLER_COMPONENT.get() { + get_triggered_dispatcher(parachain_handler.import_dispatcher.clone())? + } else { + return Err(Error::NoTargetBParentchainAssigned) + }; + Ok(dispatcher) +} + +pub(crate) fn get_triggered_dispatcher( + dispatcher: Arc>, +) -> Result> { let triggered_dispatcher = dispatcher .triggered_dispatcher() .ok_or(Error::ExpectedTriggeredImportDispatcher)?; Ok(triggered_dispatcher) } -pub(crate) fn get_validator_accessor_from_solo_or_parachain( +pub(crate) fn get_validator_accessor_from_integritee_solo_or_parachain( ) -> Result> { let validator_accessor = if let Ok(solochain_handler) = GLOBAL_INTEGRITEE_SOLOCHAIN_HANDLER_COMPONENT.get() { @@ -109,6 +137,32 @@ pub(crate) fn get_validator_accessor_from_solo_or_parachain( Ok(validator_accessor) } +pub(crate) fn get_validator_accessor_from_target_a_solo_or_parachain( +) -> Result> { + let validator_accessor = + if let Ok(solochain_handler) = GLOBAL_TARGET_A_SOLOCHAIN_HANDLER_COMPONENT.get() { + solochain_handler.validator_accessor.clone() + } else if let Ok(parachain_handler) = GLOBAL_TARGET_A_PARACHAIN_HANDLER_COMPONENT.get() { + parachain_handler.validator_accessor.clone() + } else { + return Err(Error::NoTargetAParentchainAssigned) + }; + Ok(validator_accessor) +} + +pub(crate) fn get_validator_accessor_from_target_b_solo_or_parachain( +) -> Result> { + let validator_accessor = + if let Ok(solochain_handler) = GLOBAL_TARGET_B_SOLOCHAIN_HANDLER_COMPONENT.get() { + solochain_handler.validator_accessor.clone() + } else if let Ok(parachain_handler) = GLOBAL_TARGET_B_PARACHAIN_HANDLER_COMPONENT.get() { + parachain_handler.validator_accessor.clone() + } else { + return Err(Error::NoTargetBParentchainAssigned) + }; + Ok(validator_accessor) +} + pub(crate) fn get_node_metadata_repository_from_integritee_solo_or_parachain( ) -> Result> { let metadata_repository = @@ -161,6 +215,32 @@ pub(crate) fn get_extrinsic_factory_from_integritee_solo_or_parachain( Ok(extrinsics_factory) } +pub(crate) fn get_extrinsic_factory_from_target_a_solo_or_parachain( +) -> Result> { + let extrinsics_factory = + if let Ok(solochain_handler) = GLOBAL_TARGET_A_SOLOCHAIN_HANDLER_COMPONENT.get() { + solochain_handler.extrinsics_factory.clone() + } else if let Ok(parachain_handler) = GLOBAL_TARGET_A_PARACHAIN_HANDLER_COMPONENT.get() { + parachain_handler.extrinsics_factory.clone() + } else { + return Err(Error::NoTargetAParentchainAssigned) + }; + Ok(extrinsics_factory) +} + +pub(crate) fn get_extrinsic_factory_from_target_b_solo_or_parachain( +) -> Result> { + let extrinsics_factory = + if let Ok(solochain_handler) = GLOBAL_TARGET_B_SOLOCHAIN_HANDLER_COMPONENT.get() { + solochain_handler.extrinsics_factory.clone() + } else if let Ok(parachain_handler) = GLOBAL_TARGET_B_PARACHAIN_HANDLER_COMPONENT.get() { + parachain_handler.extrinsics_factory.clone() + } else { + return Err(Error::NoTargetBParentchainAssigned) + }; + Ok(extrinsics_factory) +} + pub(crate) fn get_stf_executor_from_solo_or_parachain() -> Result> { let stf_executor = if let Ok(solochain_handler) = GLOBAL_INTEGRITEE_SOLOCHAIN_HANDLER_COMPONENT.get() { diff --git a/service/Cargo.toml b/service/Cargo.toml index 4ef6361bd0..ad84e66547 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -19,6 +19,7 @@ log = "0.4" parking_lot = "0.12.1" parse_duration = "2.1.1" prometheus = { version = "0.13.0", features = ["process"] } +regex = "1.9.5" scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } serde = "1.0" serde_derive = "1.0" @@ -59,6 +60,7 @@ its-storage = { path = "../sidechain/storage" } # scs / integritee my-node-runtime = { package = "integritee-node-runtime", git = "https://github.com/integritee-network/integritee-node.git", branch = "sdk-v0.12.0-polkadot-v0.9.42" } +#my-node-runtime = { package = "integritee-runtime", git = "https://github.com/integritee-network/parachain.git", tag = "1.6.2" } sgx-verify = { git = "https://github.com/integritee-network/pallets.git", branch = "sdk-v0.12.0-polkadot-v0.9.42" } # `default-features = false` to remove the jsonrpsee dependency. enclave-bridge-primitives = { git = "https://github.com/integritee-network/pallets.git", branch = "sdk-v0.12.0-polkadot-v0.9.42" } diff --git a/service/src/main_impl.rs b/service/src/main_impl.rs index 5c1c0beb2c..e4a61713f5 100644 --- a/service/src/main_impl.rs +++ b/service/src/main_impl.rs @@ -3,7 +3,6 @@ use crate::teeracle::{schedule_periodic_reregistration_thread, start_periodic_ma #[cfg(not(feature = "dcap"))] use crate::utils::check_files; - use crate::{ account_funding::{setup_account_funding, EnclaveAccountInfoProvider}, config::Config, @@ -52,6 +51,7 @@ use its_primitives::types::block::SignedBlock as SignedSidechainBlock; use its_storage::{interface::FetchBlocks, BlockPruner, SidechainStorageLock}; use log::*; use my_node_runtime::{Hash, Header, RuntimeEvent}; +use regex::Regex; use sgx_types::*; use sp_runtime::traits::Header as HeaderT; use substrate_api_client::{ @@ -71,7 +71,8 @@ use itc_parentchain::primitives::ParentchainId; use sp_core::crypto::{AccountId32, Ss58Codec}; use sp_keyring::AccountKeyring; use sp_runtime::MultiSigner; -use std::{str, sync::Arc, thread, time::Duration}; +use std::{fmt::Debug, str, sync::Arc, thread, time::Duration}; +use substrate_api_client::ac_node_api::{EventRecord, Phase::ApplyExtrinsic}; const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -564,18 +565,18 @@ fn start_worker( 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: {}", + "[Integritee] 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!("[Integritee] initializing proxied shard vault account now"); + enclave.init_proxied_shard_vault(shard, &ParentchainId::Integritee).unwrap(); println!( - "initialized shard vault account: : {}", + "[Integritee] 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"); + panic!("[Integritee] no vault account has been initialized and we are not the primary worker"); } } @@ -589,6 +590,7 @@ fn start_worker( &enclave, &tee_accountid, url, + shard, ParentchainId::TargetA, is_development_mode, ) @@ -599,6 +601,7 @@ fn start_worker( &enclave, &tee_accountid, url, + shard, ParentchainId::TargetB, is_development_mode, ) @@ -611,7 +614,7 @@ fn start_worker( println!("[+] [{:?}] Subscribed to events. waiting...", ParentchainId::Integritee); loop { if let Some(Ok(events)) = subscription.next_events::() { - print_events(events) + print_events(events, ParentchainId::Integritee) } } } @@ -620,6 +623,7 @@ fn init_target_parentchain( enclave: &Arc, tee_account_id: &AccountId32, url: String, + shard: &ShardIdentifier, parentchain_id: ParentchainId, is_development_mode: bool, ) where @@ -665,6 +669,8 @@ fn init_target_parentchain( }) .unwrap(); } + println!("[{:?}] initializing proxied shard vault account now", parentchain_id); + enclave.init_proxied_shard_vault(shard, &parentchain_id).unwrap(); // Subscribe to events and print them. println!("*** [{:?}] Subscribing to events...", parentchain_id); @@ -675,7 +681,7 @@ fn init_target_parentchain( .name(format!("{:?}_parentchain_event_subscription", parentchain_id)) .spawn(move || loop { if let Some(Ok(events)) = subscription.next_events::() { - print_events(events) + print_events(events, parentchain_id) } }) .unwrap(); @@ -755,159 +761,21 @@ fn spawn_worker_for_shard_polling( }); } -fn print_events(events: Vec) { +fn print_events(events: Vec>, parentchain_id: ParentchainId) +where + R: Debug, +{ for evr in &events { - debug!("Decoded: phase = {:?}, event = {:?}", evr.phase, evr.event); - match &evr.event { - RuntimeEvent::Balances(be) => { - info!("[+] Received balances event"); - debug!("{:?}", be); - match &be { - pallet_balances::Event::Transfer { - from: transactor, - to: dest, - amount: value, - } => { - debug!(" Transactor: {:?}", transactor.to_ss58check()); - debug!(" Destination: {:?}", dest.to_ss58check()); - debug!(" Value: {:?}", value); - }, - _ => { - trace!("Ignoring unsupported balances event"); - }, - } - }, - RuntimeEvent::Teerex(re) => { - debug!("{:?}", re); - match &re { - my_node_runtime::pallet_teerex::Event::AddedSgxEnclave { - registered_by, - worker_url, - .. - } => { - println!("[+] Received AddedEnclave event"); - println!(" Sender (Worker): {:?}", registered_by); - println!( - " Registered URL: {:?}", - str::from_utf8(&worker_url.clone().unwrap_or("none".into())).unwrap() - ); - }, - _ => { - trace!("Ignoring unsupported pallet_teerex event"); - }, - } - }, - RuntimeEvent::EnclaveBridge(re) => { - debug!("{:?}", re); - match &re { - my_node_runtime::pallet_enclave_bridge::Event::IndirectInvocationRegistered( - shard, - ) => { - println!( - "[+] Received trusted call for shard {}", - shard.encode().to_base58() - ); - }, - my_node_runtime::pallet_enclave_bridge::Event::ProcessedParentchainBlock { - shard, - block_hash, - trusted_calls_merkle_root, - block_number, - } => { - info!("[+] Received ProcessedParentchainBlock event"); - debug!(" for shard: {:?}", shard); - debug!(" Block Hash: {:?}", hex::encode(block_hash)); - debug!(" Merkle Root: {:?}", hex::encode(trusted_calls_merkle_root)); - debug!(" Block Number: {:?}", block_number); - }, - my_node_runtime::pallet_enclave_bridge::Event::ShieldFunds { - shard, - encrypted_beneficiary, - amount, - } => { - info!("[+] Received ShieldFunds event"); - debug!(" for shard: {:?}", shard); - debug!(" for enc. beneficiary: {:?}", encrypted_beneficiary); - debug!(" Amount: {:?}", amount); - }, - my_node_runtime::pallet_enclave_bridge::Event::UnshieldedFunds { - shard, - beneficiary, - amount, - } => { - info!("[+] Received UnshieldedFunds event"); - debug!(" for shard: {:?}", shard); - debug!(" beneficiary: {:?}", beneficiary); - debug!(" Amount: {:?}", amount); - }, - _ => { - trace!("Ignoring unsupported pallet_enclave_bridge event"); - }, - } - }, - #[cfg(feature = "teeracle")] - RuntimeEvent::Teeracle(re) => { - debug!("{:?}", re); - match &re { - my_node_runtime::pallet_teeracle::Event::ExchangeRateUpdated { - data_source, - trading_pair, - exchange_rate, - } => { - println!("[+] Received ExchangeRateUpdated event"); - println!(" Data source: {}", data_source); - println!(" trading pair: {}", trading_pair); - println!(" Exchange rate: {:?}", exchange_rate); - }, - my_node_runtime::pallet_teeracle::Event::ExchangeRateDeleted { - data_source, - trading_pair, - } => { - println!("[+] Received ExchangeRateDeleted event"); - println!(" Data source: {}", data_source); - println!(" trading pair: {}", trading_pair); - }, - my_node_runtime::pallet_teeracle::Event::AddedToWhitelist { - data_source, - enclave_fingerprint, - } => { - println!("[+] Received AddedToWhitelist event"); - println!(" Data source: {}", data_source); - println!(" fingerprint: {:?}", enclave_fingerprint); - }, - my_node_runtime::pallet_teeracle::Event::RemovedFromWhitelist { - data_source, - enclave_fingerprint, - } => { - println!("[+] Received RemovedFromWhitelist event"); - println!(" Data source: {}", data_source); - println!(" fingerprint: {:?}", enclave_fingerprint); - }, - _ => { - trace!("Ignoring unsupported pallet_teeracle event"); - }, - } - }, - #[cfg(feature = "sidechain")] - RuntimeEvent::Sidechain(re) => match &re { - my_node_runtime::pallet_sidechain::Event::FinalizedSidechainBlock { - shard, - block_header_hash, - validateer, - } => { - info!("[+] Received FinalizedSidechainBlock event"); - debug!(" for shard: {:?}", shard); - debug!(" From: {:?}", hex::encode(block_header_hash)); - debug!(" validateer: {:?}", validateer); - }, - _ => { - trace!("Ignoring unsupported pallet_sidechain event"); - }, - }, - _ => { - trace!("Ignoring event {:?}", evr); - }, + if evr.phase == ApplyExtrinsic(0) { + // not interested in intrinsics + continue } + let re = Regex::new(r"\s[0-9a-f]*\s\(").unwrap(); + let event_str = re + .replace_all(format!("{:?}", evr.event).as_str(), "(") + .replace("RuntimeEvent::", "") + .replace("Event::", ""); + println!("[{}] Event: {}", parentchain_id, event_str); } } @@ -1038,16 +906,16 @@ fn subscribe_to_parentchain_new_headers( .parentchain_api() .subscribe_finalized_heads() .map_err(Error::ApiClient)?; - + let parentchain_id = parentchain_handler.parentchain_id(); loop { let new_header = subscription .next() .ok_or(Error::ApiSubscriptionDisconnected)? .map_err(|e| Error::ApiClient(e.into()))?; - println!( - "[+] Received finalized header update ({}), syncing parent chain...", - new_header.number + info!( + "[{:?}] Received finalized header update ({}), syncing parent chain...", + parentchain_id, new_header.number ); last_synced_header = parentchain_handler.sync_parentchain(last_synced_header)?; diff --git a/service/src/parentchain_handler.rs b/service/src/parentchain_handler.rs index f27b603337..58820d4bf0 100644 --- a/service/src/parentchain_handler.rs +++ b/service/src/parentchain_handler.rs @@ -149,7 +149,7 @@ where .ok_or(Error::MissingLastFinalizedBlock)?; let curr_block_number = curr_block.block.header().number(); - println!( + info!( "[{:?}] Syncing blocks from {} to {}", id, last_synced_header.number, curr_block_number ); @@ -160,7 +160,7 @@ where until_synced_header.number + 1, min(until_synced_header.number + BLOCK_SYNC_BATCH_SIZE, curr_block_number), )?; - println!("[+] [{:?}] Found {} block(s) to sync", id, block_chunk_to_sync.len()); + info!("[{:?}] Found {} block(s) to sync", id, block_chunk_to_sync.len()); if block_chunk_to_sync.is_empty() { return Ok(until_synced_header) } @@ -172,7 +172,7 @@ where }) .collect::, _>>()?; - println!("[+] [{:?}] Found {} event vector(s) to sync", id, events_chunk_to_sync.len()); + info!("[{:?}] Found {} event vector(s) to sync", id, events_chunk_to_sync.len()); let events_proofs_chunk_to_sync: Vec = block_chunk_to_sync .iter() @@ -192,7 +192,7 @@ where .last() .map(|b| b.block.header.clone()) .ok_or(Error::EmptyChunk)?; - println!( + info!( "[{:?}] Synced {} out of {} finalized parentchain blocks", id, until_synced_header.number, curr_block_number, ); diff --git a/service/src/tests/mocks/enclave_api_mock.rs b/service/src/tests/mocks/enclave_api_mock.rs index 5361e2ffa2..3c24bdc1c2 100644 --- a/service/src/tests/mocks/enclave_api_mock.rs +++ b/service/src/tests/mocks/enclave_api_mock.rs @@ -61,7 +61,11 @@ impl EnclaveBase for EnclaveMock { unimplemented!() } - fn init_proxied_shard_vault(&self, _shard: &ShardIdentifier) -> EnclaveResult<()> { + fn init_proxied_shard_vault( + &self, + _shard: &ShardIdentifier, + _parentchain_id: &ParentchainId, + ) -> EnclaveResult<()> { unimplemented!() } diff --git a/sidechain/consensus/aura/Cargo.toml b/sidechain/consensus/aura/Cargo.toml index 16d29dd847..3e1501bb87 100644 --- a/sidechain/consensus/aura/Cargo.toml +++ b/sidechain/consensus/aura/Cargo.toml @@ -30,6 +30,7 @@ itp-stf-state-handler = { path = "../../../core-primitives/stf-state-handler", d itp-time-utils = { path = "../../../core-primitives/time-utils", default-features = false } itp-top-pool-author = { path = "../../../core-primitives/top-pool-author", default-features = false } itp-types = { path = "../../../core-primitives/types", default-features = false } +itp-utils = { path = "../../../core-primitives/utils", default-features = false } its-block-composer = { path = "../../block-composer", default-features = false } its-block-verification = { path = "../../block-verification", optional = true, default-features = false } its-consensus-common = { path = "../common", default-features = false } @@ -70,6 +71,7 @@ std = [ "itp-stf-state-handler/std", "itp-time-utils/std", "itp-types/std", + "itp-utils/std", "its-block-composer/std", "its-block-verification/std", "its-consensus-common/std", diff --git a/sidechain/consensus/aura/src/lib.rs b/sidechain/consensus/aura/src/lib.rs index 0c52803086..ad6690c1c9 100644 --- a/sidechain/consensus/aura/src/lib.rs +++ b/sidechain/consensus/aura/src/lib.rs @@ -29,10 +29,13 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam #[macro_use] extern crate sgx_tstd as std; +use codec::Encode; use core::marker::PhantomData; use itc_parentchain_block_import_dispatcher::triggered_dispatcher::TriggerParentchainBlockImport; use itp_ocall_api::EnclaveOnChainOCallApi; use itp_time_utils::duration_now; + +use itp_utils::hex::hex_encode; use its_block_verification::slot::slot_author; use its_consensus_common::{Environment, Error as ConsensusError, Proposer}; use its_consensus_slots::{SimpleSlotWorker, Slot, SlotInfo}; @@ -66,29 +69,55 @@ pub struct Aura< SidechainBlock, Environment, OcallApi, - ImportTrigger, + IntegriteeImportTrigger, + TargetAImportTrigger, + TargetBImportTrigger, > { authority_pair: AuthorityPair, ocall_api: OcallApi, - parentchain_import_trigger: Arc, + parentchain_integritee_import_trigger: Arc, + maybe_parentchain_target_a_import_trigger: Option>, + maybe_parentchain_target_b_import_trigger: Option>, environment: Environment, claim_strategy: SlotClaimStrategy, _phantom: PhantomData<(AuthorityPair, ParentchainBlock, SidechainBlock)>, } -impl - Aura +impl< + AuthorityPair, + ParentchainBlock, + SidechainBlock, + Environment, + OcallApi, + IntegriteeImportTrigger, + TargetAImportTrigger, + TargetBImportTrigger, + > + Aura< + AuthorityPair, + ParentchainBlock, + SidechainBlock, + Environment, + OcallApi, + IntegriteeImportTrigger, + TargetAImportTrigger, + TargetBImportTrigger, + > { pub fn new( authority_pair: AuthorityPair, ocall_api: OcallApi, - parentchain_import_trigger: Arc, + parentchain_integritee_import_trigger: Arc, + maybe_parentchain_target_a_import_trigger: Option>, + maybe_parentchain_target_b_import_trigger: Option>, environment: Environment, ) -> Self { Self { authority_pair, ocall_api, - parentchain_import_trigger, + parentchain_integritee_import_trigger, + maybe_parentchain_target_a_import_trigger, + maybe_parentchain_target_b_import_trigger, environment, claim_strategy: SlotClaimStrategy::RoundRobin, _phantom: Default::default(), @@ -119,10 +148,26 @@ type AuthorityId

=

::Public; type ShardIdentifierFor = <<::Block as SidechainBlockTrait>::HeaderType as HeaderTrait>::ShardIdentifier; -impl - SimpleSlotWorker - for Aura -where +impl< + AuthorityPair, + ParentchainBlock, + SignedSidechainBlock, + E, + OcallApi, + IntegriteeImportTrigger, + TargetAImportTrigger, + TargetBImportTrigger, + > SimpleSlotWorker + for Aura< + AuthorityPair, + ParentchainBlock, + SignedSidechainBlock, + E, + OcallApi, + IntegriteeImportTrigger, + TargetAImportTrigger, + TargetBImportTrigger, + > where AuthorityPair: Pair, AuthorityPair::Public: UncheckedFrom<[u8; 32]>, // todo: Relax hash trait bound, but this needs a change to some other parts in the code. @@ -131,7 +176,11 @@ where E::Proposer: Proposer, SignedSidechainBlock: SignedBlock + Send + 'static, OcallApi: ValidateerFetch + EnclaveOnChainOCallApi + Send + 'static, - ImportTrigger: + IntegriteeImportTrigger: + TriggerParentchainBlockImport>, + TargetAImportTrigger: + TriggerParentchainBlockImport>, + TargetBImportTrigger: TriggerParentchainBlockImport>, { type Proposer = E::Proposer; @@ -197,12 +246,51 @@ where proposing_remaining_duration(slot_info, duration_now()) } - fn import_parentchain_blocks_until( + // Design remark: the following may seem too explicit and it certainly could be abstracted. + // however, as pretty soon we may not want to assume same Block types for all parentchains, + // it may make sense to abstract once we do that. + + fn import_integritee_parentchain_blocks_until( + &self, + parentchain_header_hash: &::Hash, + ) -> Result, ConsensusError> { + log::trace!(target: self.logging_target(), "import Integritee blocks until {}", hex_encode(parentchain_header_hash.encode().as_ref())); + let maybe_parentchain_block = self + .parentchain_integritee_import_trigger + .import_until(|parentchain_block| { + parentchain_block.block.hash() == *parentchain_header_hash + }) + .map_err(|e| ConsensusError::Other(e.into()))?; + + Ok(maybe_parentchain_block.map(|b| b.block.header().clone())) + } + + fn import_target_a_parentchain_blocks_until( + &self, + parentchain_header_hash: &::Hash, + ) -> Result, ConsensusError> { + log::trace!(target: self.logging_target(), "import TargetA blocks until {}", hex_encode(parentchain_header_hash.encode().as_ref())); + let maybe_parentchain_block = self + .maybe_parentchain_target_a_import_trigger + .clone() + .ok_or_else(|| ConsensusError::Other("no target_a assigned".into()))? + .import_until(|parentchain_block| { + parentchain_block.block.hash() == *parentchain_header_hash + }) + .map_err(|e| ConsensusError::Other(e.into()))?; + + Ok(maybe_parentchain_block.map(|b| b.block.header().clone())) + } + + fn import_target_b_parentchain_blocks_until( &self, parentchain_header_hash: &::Hash, ) -> Result, ConsensusError> { + log::trace!(target: self.logging_target(), "import TargetB blocks until {}", hex_encode(parentchain_header_hash.encode().as_ref())); let maybe_parentchain_block = self - .parentchain_import_trigger + .maybe_parentchain_target_b_import_trigger + .clone() + .ok_or_else(|| ConsensusError::Other("no target_b assigned".into()))? .import_until(|parentchain_block| { parentchain_block.block.hash() == *parentchain_header_hash }) @@ -211,11 +299,37 @@ where Ok(maybe_parentchain_block.map(|b| b.block.header().clone())) } - fn peek_latest_parentchain_header( + fn peek_latest_integritee_parentchain_header( + &self, + ) -> Result, ConsensusError> { + let maybe_parentchain_block = self + .parentchain_integritee_import_trigger + .peek_latest() + .map_err(|e| ConsensusError::Other(format!("{:?}", e).into()))?; + + Ok(maybe_parentchain_block.map(|b| b.block.header().clone())) + } + + fn peek_latest_target_a_parentchain_header( &self, ) -> Result, ConsensusError> { let maybe_parentchain_block = self - .parentchain_import_trigger + .maybe_parentchain_target_a_import_trigger + .clone() + .ok_or_else(|| ConsensusError::Other("no target_a assigned".into()))? + .peek_latest() + .map_err(|e| ConsensusError::Other(format!("{:?}", e).into()))?; + + Ok(maybe_parentchain_block.map(|b| b.block.header().clone())) + } + + fn peek_latest_target_b_parentchain_header( + &self, + ) -> Result, ConsensusError> { + let maybe_parentchain_block = self + .maybe_parentchain_target_b_import_trigger + .clone() + .ok_or_else(|| ConsensusError::Other("no target_b assigned".into()))? .peek_latest() .map_err(|e| ConsensusError::Other(format!("{:?}", e).into()))?; @@ -261,6 +375,12 @@ where .collect()) } +pub enum AnyImportTrigger { + Integritee(Integritee), + TargetA(TargetA), + TargetB(TargetB), +} + #[cfg(test)] mod tests { use super::*; @@ -283,7 +403,14 @@ mod tests { onchain_mock: OnchainMock, trigger_parentchain_import: Arc>, ) -> TestAura { - Aura::new(Keyring::Alice.pair(), onchain_mock, trigger_parentchain_import, EnvironmentMock) + Aura::new( + Keyring::Alice.pair(), + onchain_mock, + trigger_parentchain_import, + None, + None, + EnvironmentMock, + ) } fn get_default_aura() -> TestAura { @@ -297,7 +424,9 @@ mod tests { timestamp: now, duration: SLOT_DURATION, ends_at: now + SLOT_DURATION, - last_imported_parentchain_head: header.clone(), + last_imported_integritee_parentchain_head: header.clone(), + maybe_last_imported_target_a_parentchain_head: None, + maybe_last_imported_target_b_parentchain_head: None, } } @@ -413,7 +542,9 @@ mod tests { timestamp: now, duration: nano_dur, ends_at: now + nano_dur, - last_imported_parentchain_head: ParentchainHeaderBuilder::default().build(), + last_imported_integritee_parentchain_head: ParentchainHeaderBuilder::default().build(), + maybe_last_imported_target_a_parentchain_head: None, + maybe_last_imported_target_b_parentchain_head: None, }; let result = PerShardSlotWorkerScheduler::on_slot( diff --git a/sidechain/consensus/aura/src/slot_proposer.rs b/sidechain/consensus/aura/src/slot_proposer.rs index 7fd7e64836..bc8f8b4f22 100644 --- a/sidechain/consensus/aura/src/slot_proposer.rs +++ b/sidechain/consensus/aura/src/slot_proposer.rs @@ -148,7 +148,7 @@ where .map_err(|e| ConsensusError::Other(e.to_string().into()))?; info!( - "Queue/Timeslot/Transactions: {:?};{};{}", + "Queue/Timeslot/Transactions: {:?};{}ms;{}", trusted_calls.len(), max_duration.as_millis(), number_executed_transactions diff --git a/sidechain/consensus/aura/src/test/fixtures/types.rs b/sidechain/consensus/aura/src/test/fixtures/types.rs index 39aa4ef3f4..98cec742ba 100644 --- a/sidechain/consensus/aura/src/test/fixtures/types.rs +++ b/sidechain/consensus/aura/src/test/fixtures/types.rs @@ -40,4 +40,6 @@ pub type TestAura = Aura< EnvironmentMock, OnchainMock, TriggerParentchainBlockImportMock>, + TriggerParentchainBlockImportMock>, + TriggerParentchainBlockImportMock>, >; diff --git a/sidechain/consensus/common/src/lib.rs b/sidechain/consensus/common/src/lib.rs index fa2104186f..adb91d9ec8 100644 --- a/sidechain/consensus/common/src/lib.rs +++ b/sidechain/consensus/common/src/lib.rs @@ -27,7 +27,6 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam #[macro_use] extern crate sgx_tstd as std; -use itp_types::OpaqueCall; use its_primitives::traits::{ShardIdentifierFor, SignedBlock as SignedSidechainBlockTrait}; use sp_runtime::traits::Block as ParentchainBlockTrait; use std::{time::Duration, vec::Vec}; @@ -50,6 +49,7 @@ pub use block_import::*; pub use block_import_confirmation_handler::*; pub use block_import_queue_worker::*; pub use error::*; +use itp_types::parentchain::ParentchainCall; pub use peer_block_sync::*; pub trait Verifier: Send + Sync @@ -110,5 +110,5 @@ pub struct Proposal { /// /// Any sidechain stf that invokes a parentchain stf must not commit its state change /// before the parentchain effect has been finalized. - pub parentchain_effects: Vec, + pub parentchain_effects: Vec, } diff --git a/sidechain/consensus/slots/src/lib.rs b/sidechain/consensus/slots/src/lib.rs index cff263fa60..79a20386d2 100644 --- a/sidechain/consensus/slots/src/lib.rs +++ b/sidechain/consensus/slots/src/lib.rs @@ -34,7 +34,7 @@ extern crate sgx_tstd as std; use codec::Encode; use derive_more::From; use itp_time_utils::{duration_difference, duration_now}; -use itp_types::OpaqueCall; + use its_consensus_common::{Error as ConsensusError, Proposer}; use its_primitives::traits::{ Block as SidechainBlockTrait, Header as HeaderTrait, ShardIdentifierFor, @@ -55,6 +55,7 @@ mod mocks; #[cfg(test)] mod per_shard_slot_worker_tests; +use itp_types::parentchain::ParentchainCall; #[cfg(feature = "std")] pub use slot_stream::*; pub use slots::*; @@ -68,7 +69,7 @@ pub struct SlotResult { /// /// Any sidechain stf that invokes a parentchain stf must not commit its state change /// before the parentchain effect has been finalized. - pub parentchain_effects: Vec, + pub parentchain_effects: Vec, } /// A worker that should be invoked at every new slot for a specific shard. @@ -167,14 +168,32 @@ pub trait SimpleSlotWorker { /// /// Returns the header of the latest imported block. In case no block was imported with this trigger, /// None is returned. - fn import_parentchain_blocks_until( + fn import_integritee_parentchain_blocks_until( + &self, + last_imported_parentchain_header: &::Hash, + ) -> Result, ConsensusError>; + + fn import_target_a_parentchain_blocks_until( + &self, + last_imported_parentchain_header: &::Hash, + ) -> Result, ConsensusError>; + + fn import_target_b_parentchain_blocks_until( &self, last_imported_parentchain_header: &::Hash, ) -> Result, ConsensusError>; /// Peek the parentchain import queue for the latest block in queue. /// Does not perform the import or mutate the queue. - fn peek_latest_parentchain_header( + fn peek_latest_integritee_parentchain_header( + &self, + ) -> Result, ConsensusError>; + + fn peek_latest_target_a_parentchain_header( + &self, + ) -> Result, ConsensusError>; + + fn peek_latest_target_b_parentchain_header( &self, ) -> Result, ConsensusError>; @@ -203,25 +222,67 @@ pub trait SimpleSlotWorker { return None } - let latest_parentchain_header = match self.peek_latest_parentchain_header() { - Ok(Some(peeked_header)) => peeked_header, - Ok(None) => slot_info.last_imported_parentchain_head.clone(), - Err(e) => { - warn!( - target: logging_target, - "Failed to peek latest parentchain block header: {:?}", e - ); - return None - }, - }; + let latest_integritee_parentchain_header = + match self.peek_latest_integritee_parentchain_header() { + Ok(Some(peeked_header)) => peeked_header, + Ok(None) => slot_info.last_imported_integritee_parentchain_head.clone(), + Err(e) => { + warn!( + target: logging_target, + "Failed to peek latest Integritee parentchain block header: {:?}", e + ); + return None + }, + }; + trace!( + target: logging_target, + "on_slot: a priori latest Integritee block number: {:?}", + latest_integritee_parentchain_header.number() + ); + // fixme: we need proper error handling here. we just assume there is no target_a if there is an error here, which is very brittle + let maybe_latest_target_a_parentchain_header = + match self.peek_latest_target_a_parentchain_header() { + Ok(Some(peeked_header)) => Some(peeked_header), + Ok(None) => slot_info.maybe_last_imported_target_a_parentchain_head.clone(), + Err(e) => { + debug!( + target: logging_target, + "Failed to peek latest target_a_parentchain block header: {:?}", e + ); + None + }, + }; + trace!( + target: logging_target, + "on_slot: a priori latest TargetA block number: {:?}", + maybe_latest_target_a_parentchain_header.clone().map(|h| *h.number()) + ); + + let maybe_latest_target_b_parentchain_header = + match self.peek_latest_target_b_parentchain_header() { + Ok(Some(peeked_header)) => Some(peeked_header), + Ok(None) => slot_info.maybe_last_imported_target_b_parentchain_head.clone(), + Err(e) => { + debug!( + target: logging_target, + "Failed to peek latest target_a_parentchain block header: {:?}", e + ); + None + }, + }; + trace!( + target: logging_target, + "on_slot: a priori latest TargetB block number: {:?}", + maybe_latest_target_b_parentchain_header.clone().map(|h| *h.number()) + ); - let epoch_data = match self.epoch_data(&latest_parentchain_header, shard, slot) { + let epoch_data = match self.epoch_data(&latest_integritee_parentchain_header, shard, slot) { Ok(epoch_data) => epoch_data, Err(e) => { warn!( target: logging_target, "Unable to fetch epoch data at block {:?}: {:?}", - latest_parentchain_header.hash(), + latest_integritee_parentchain_header.hash(), e, ); @@ -238,22 +299,79 @@ pub trait SimpleSlotWorker { ); } - let _claim = self.claim_slot(&latest_parentchain_header, slot, &epoch_data)?; + let _claim = self.claim_slot(&latest_integritee_parentchain_header, slot, &epoch_data)?; // Import the peeked parentchain header(s). - let last_imported_header = - match self.import_parentchain_blocks_until(&latest_parentchain_header.hash()) { - Ok(h) => h, - Err(e) => { - warn!( - target: logging_target, - "Failed to import and retrieve parentchain block header: {:?}", e - ); - return None - }, + let last_imported_integritee_header = match self.import_integritee_parentchain_blocks_until( + &latest_integritee_parentchain_header.hash(), + ) { + Ok(h) => h, + Err(e) => { + debug!( + target: logging_target, + "Failed to import Integritee blocks until nr{:?}: {:?}", + latest_integritee_parentchain_header.number(), + e + ); + None + }, + }; + trace!( + target: logging_target, + "on_slot: a posteriori latest Integritee block number: {:?}", + last_imported_integritee_header.clone().map(|h| *h.number()) + ); + + let maybe_last_imported_target_a_header = + if let Some(ref header) = maybe_latest_target_a_parentchain_header { + match self.import_target_a_parentchain_blocks_until(&header.hash()) { + Ok(Some(h)) => Some(h), + Ok(None) => None, + Err(e) => { + debug!( + target: logging_target, + "Failed to import TargetA blocks until nr{:?}: {:?}", + header.number(), + e + ); + None + }, + } + } else { + None + }; + trace!( + target: logging_target, + "on_slot: a posteriori latest TargetA block number: {:?}", + maybe_last_imported_target_a_header.map(|h| *h.number()) + ); + + let maybe_last_imported_target_b_header = + if let Some(ref header) = maybe_latest_target_b_parentchain_header { + match self.import_target_b_parentchain_blocks_until(&header.hash()) { + Ok(Some(h)) => Some(h), + Ok(None) => None, + Err(e) => { + debug!( + target: logging_target, + "Failed to import TargetB blocks until nr{:?}: {:?}", + header.number(), + e + ); + None + }, + } + } else { + None }; - let proposer = match self.proposer(latest_parentchain_header.clone(), shard) { + trace!( + target: logging_target, + "on_slot: a posteriori latest TargetB block number: {:?}", + maybe_last_imported_target_b_header.map(|h| *h.number()) + ); + + let proposer = match self.proposer(latest_integritee_parentchain_header.clone(), shard) { Ok(p) => p, Err(e) => { warn!(target: logging_target, "Could not create proposer: {:?}", e); @@ -279,17 +397,19 @@ pub trait SimpleSlotWorker { return None } - if last_imported_header.is_some() { + if last_imported_integritee_header.is_some() { println!( - "Syncing Parentchain block number {:?} at Sidechain block number {:?} ", - latest_parentchain_header.number(), + "Syncing Parentchain block numbers Integritee:{:?} TargetA: {:?}, TargetB: {:?} at Sidechain block number {:?} ", + latest_integritee_parentchain_header.number(), + maybe_latest_target_a_parentchain_header.map(|h| *h.number()), + maybe_latest_target_b_parentchain_header.map(|h| *h.number()), proposing.block.block().header().block_number() ); } - info!("Proposing sidechain block (number: {}, hash: {}) based on parentchain block (number: {:?}, hash: {:?})", + info!("Proposing sidechain block (number: {}, hash: {}) based on integritee parentchain block (number: {:?}, hash: {:?})", proposing.block.block().header().block_number(), proposing.block.hash(), - latest_parentchain_header.number(), latest_parentchain_header.hash() + latest_integritee_parentchain_header.number(), latest_integritee_parentchain_header.hash() ); Some(SlotResult { @@ -353,11 +473,19 @@ impl slot_results.push(res), + match SimpleSlotWorker::on_slot(self, shard_slot.clone(), shard) { + Some(res) => { + slot_results.push(res); + debug!( + target: logging_target, + "on_slot: produced block for slot: {:?} in shard {:?}", shard_slot, shard + ) + }, None => info!( target: logging_target, "Did not produce a block for slot {} in shard {:?}", *slot_info.slot, shard diff --git a/sidechain/consensus/slots/src/mocks.rs b/sidechain/consensus/slots/src/mocks.rs index 6664351160..8f4be9ea4f 100644 --- a/sidechain/consensus/slots/src/mocks.rs +++ b/sidechain/consensus/slots/src/mocks.rs @@ -94,14 +94,36 @@ where todo!() } - fn import_parentchain_blocks_until( + fn import_integritee_parentchain_blocks_until( &self, _last_imported_parentchain_header: &::Hash, ) -> Result> { todo!() } - fn peek_latest_parentchain_header(&self) -> Result> { + fn peek_latest_integritee_parentchain_header(&self) -> Result> { + todo!() + } + + fn import_target_a_parentchain_blocks_until( + &self, + _last_imported_parentchain_header: &::Hash, + ) -> Result> { + todo!() + } + + fn peek_latest_target_a_parentchain_header(&self) -> Result> { + todo!() + } + + fn import_target_b_parentchain_blocks_until( + &self, + _last_imported_parentchain_header: &::Hash, + ) -> Result> { + todo!() + } + + fn peek_latest_target_b_parentchain_header(&self) -> Result> { todo!() } diff --git a/sidechain/consensus/slots/src/per_shard_slot_worker_tests.rs b/sidechain/consensus/slots/src/per_shard_slot_worker_tests.rs index 3f6d212b5f..b4856d767c 100644 --- a/sidechain/consensus/slots/src/per_shard_slot_worker_tests.rs +++ b/sidechain/consensus/slots/src/per_shard_slot_worker_tests.rs @@ -86,5 +86,7 @@ fn slot_info_from_now() -> SlotInfo { SLOT_DURATION, slot_ends_at, ParentchainHeaderBuilder::default().build(), + None, + None, ) } diff --git a/sidechain/consensus/slots/src/slots.rs b/sidechain/consensus/slots/src/slots.rs index fa6564bac2..54dcc23349 100644 --- a/sidechain/consensus/slots/src/slots.rs +++ b/sidechain/consensus/slots/src/slots.rs @@ -64,7 +64,11 @@ pub struct SlotInfo { /// The time at which the slot ends. pub ends_at: Duration, /// Last imported parentchain header, potentially outdated. - pub last_imported_parentchain_head: ParentchainBlock::Header, + pub last_imported_integritee_parentchain_head: ParentchainBlock::Header, + /// Last imported parentchain header, potentially outdated. + pub maybe_last_imported_target_a_parentchain_head: Option, + /// Last imported parentchain header, potentially outdated. + pub maybe_last_imported_target_b_parentchain_head: Option, } impl SlotInfo { @@ -76,14 +80,18 @@ impl SlotInfo { timestamp: Duration, duration: Duration, ends_at: Duration, - parentchain_head: ParentchainBlock::Header, + last_imported_integritee_parentchain_head: ParentchainBlock::Header, + maybe_last_imported_target_a_parentchain_head: Option, + maybe_last_imported_target_b_parentchain_head: Option, ) -> Self { Self { slot, timestamp, duration, ends_at, - last_imported_parentchain_head: parentchain_head, + last_imported_integritee_parentchain_head, + maybe_last_imported_target_a_parentchain_head, + maybe_last_imported_target_b_parentchain_head, } } @@ -99,7 +107,7 @@ impl SlotInfo { /// The time at which the slot ends. /// /// !! Slot duration needs to be the 'global' slot duration that is used for the sidechain. -/// Do not use this with 'custom' slot durations, as used e.g. for the shard slots. +/// Do not use this with 'custom' slot durations, as used e.g. for the shard slots. pub fn slot_ends_at(slot: Slot, slot_duration: Duration) -> Duration { Duration::from_millis(*slot.saturating_add(1u64) * (slot_duration.as_millis() as u64)) } @@ -131,7 +139,9 @@ pub(crate) fn timestamp_within_slot< pub fn yield_next_slot( timestamp: Duration, duration: Duration, - header: ParentchainBlock::Header, + integritee_header: ParentchainBlock::Header, + maybe_target_a_header: Option, + maybe_target_b_header: Option, last_slot_getter: &mut SlotGetter, ) -> Result>, ConsensusError> where @@ -152,7 +162,15 @@ where last_slot_getter.set_last_slot(slot)?; let slot_ends_time = slot_ends_at(slot, duration); - Ok(Some(SlotInfo::new(slot, timestamp, duration, slot_ends_time, header))) + Ok(Some(SlotInfo::new( + slot, + timestamp, + duration, + slot_ends_time, + integritee_header, + maybe_target_a_header, + maybe_target_b_header, + ))) } pub trait LastSlotTrait { @@ -213,7 +231,9 @@ mod tests { timestamp: duration_now(), duration: SLOT_DURATION, ends_at: duration_now() + SLOT_DURATION, - last_imported_parentchain_head: ParentchainHeaderBuilder::default().build(), + last_imported_integritee_parentchain_head: ParentchainHeaderBuilder::default().build(), + maybe_last_imported_target_a_parentchain_head: None, + maybe_last_imported_target_b_parentchain_head: None, } } @@ -252,11 +272,18 @@ mod tests { let slot: Slot = 1000.into(); let slot_end_time = slot_ends_at(slot, SLOT_DURATION); - let slot_one: SlotInfo = - SlotInfo::new(slot, timestamp, SLOT_DURATION, slot_end_time, pc_header.clone()); + let slot_one: SlotInfo = SlotInfo::new( + slot, + timestamp, + SLOT_DURATION, + slot_end_time, + pc_header.clone(), + None, + None, + ); thread::sleep(Duration::from_millis(200)); let slot_two: SlotInfo = - SlotInfo::new(slot, timestamp, SLOT_DURATION, slot_end_time, pc_header); + SlotInfo::new(slot, timestamp, SLOT_DURATION, slot_end_time, pc_header, None, None); let difference_of_ends_at = (slot_one.ends_at.as_millis()).abs_diff(slot_two.ends_at.as_millis()); @@ -276,7 +303,9 @@ mod tests { timestamp: duration_now() - Duration::from_secs(5), duration: SLOT_DURATION, ends_at: duration_now() + SLOT_DURATION - Duration::from_secs(5), - last_imported_parentchain_head: ParentchainHeaderBuilder::default().build(), + last_imported_integritee_parentchain_head: ParentchainHeaderBuilder::default().build(), + maybe_last_imported_target_a_parentchain_head: None, + maybe_last_imported_target_b_parentchain_head: None, }; assert!(slot.duration_remaining().is_none()); } @@ -288,7 +317,9 @@ mod tests { timestamp: duration_now() - Duration::from_secs(5), duration: SLOT_DURATION, ends_at: duration_now() + Duration::from_secs(60), - last_imported_parentchain_head: ParentchainHeaderBuilder::default().build(), + last_imported_integritee_parentchain_head: ParentchainHeaderBuilder::default().build(), + maybe_last_imported_target_a_parentchain_head: None, + maybe_last_imported_target_b_parentchain_head: None, }; let maybe_duration_remaining = slot.duration_remaining(); assert!(maybe_duration_remaining.is_some()); @@ -304,7 +335,7 @@ mod tests { thread::sleep(SLOT_DURATION * 2); let slot: SlotInfo = - SlotInfo::new(slot, timestamp, SLOT_DURATION, slot_end_time, pc_header); + SlotInfo::new(slot, timestamp, SLOT_DURATION, slot_end_time, pc_header, None, None); assert!(slot.ends_at < duration_now()); } @@ -348,6 +379,8 @@ mod tests { duration_now(), SLOT_DURATION, ParentchainHeaderBuilder::default().build(), + None, + None, &mut LastSlot, ) .unwrap() @@ -362,6 +395,8 @@ mod tests { duration_now() + SLOT_DURATION, SLOT_DURATION, ParentchainHeaderBuilder::default().build(), + None, + None, &mut LastSlot ) .unwrap() @@ -375,6 +410,8 @@ mod tests { duration_now(), Default::default(), ParentchainHeaderBuilder::default().build(), + None, + None, &mut LastSlot, ), "Tried to yield next slot with 0 duration",