diff --git a/tee-worker/cli/src/benchmark/mod.rs b/tee-worker/cli/src/benchmark/mod.rs index 3c46a8d1ab..748cbbbd18 100644 --- a/tee-worker/cli/src/benchmark/mod.rs +++ b/tee-worker/cli/src/benchmark/mod.rs @@ -1,378 +1,2 @@ -/* - Copyright 2021 Integritee AG and Supercomputing Systems AG - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -use crate::{ - command_utils::get_worker_api_direct, - get_layer_two_nonce, - trusted_cli::TrustedCli, - trusted_command_utils::{get_identifiers, get_keystore_path, get_pair_from_str}, - trusted_operation::{get_json_request, get_state, wait_until}, - Cli, CliResult, CliResultOk, SR25519_KEY_TYPE, -}; -use codec::Decode; -use hdrhistogram::Histogram; -use ita_stf::{ - Getter, Index, PublicGetter, TrustedCall, TrustedCallSigned, TrustedGetter, STF_TX_FEE, -}; -use itc_rpc_client::direct_client::{DirectApi, DirectClient}; -use itp_stf_primitives::{ - traits::TrustedCallSigning, - types::{KeyPair, TrustedOperation}, -}; -use itp_types::{ - Balance, ShardIdentifier, TrustedOperationStatus, - TrustedOperationStatus::{InSidechainBlock, Submitted}, -}; -use log::*; -use rand::Rng; -use rayon::prelude::*; -use sgx_crypto_helper::rsa3072::Rsa3072PubKey; -use sp_application_crypto::sr25519; -use sp_core::{sr25519 as sr25519_core, Pair}; -use sp_keystore::Keystore; -use std::{ - boxed::Box, - string::ToString, - sync::mpsc::{channel, Receiver}, - thread, time, - time::Instant, - vec::Vec, -}; -use substrate_client_keystore::LocalKeystore; - -// Needs to be above the existential deposit minimum, otherwise an account will not -// be created and the state is not increased. -const EXISTENTIAL_DEPOSIT: Balance = 1000; - -#[derive(Parser)] -pub struct BenchmarkCommand { - /// The number of clients (=threads) to be used in the benchmark - #[clap(default_value_t = 10)] - number_clients: u32, - - /// The number of iterations to execute for each client - #[clap(default_value_t = 30)] - 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)] - random_wait_before_transaction_min_ms: u32, - - /// Adds a random wait before each transaction. This is the upper bound for the interval in ms. - #[clap(default_value_t = 0)] - random_wait_before_transaction_max_ms: u32, - - /// Whether to wait for "InSidechainBlock" confirmation for each transaction - #[clap(short, long)] - wait_for_confirmation: bool, - - /// Account to be used for initial funding of generated accounts used in benchmark - #[clap(default_value_t = String::from("//Alice"))] - funding_account: String, -} - -struct BenchmarkClient { - account: sr25519_core::Pair, - current_balance: u128, - client_api: DirectClient, - receiver: Receiver, -} - -impl BenchmarkClient { - fn new( - account: sr25519_core::Pair, - initial_balance: u128, - initial_request: String, - cli: &Cli, - ) -> Self { - debug!("get direct api"); - let client_api = get_worker_api_direct(cli); - - debug!("setup sender and receiver"); - let (sender, receiver) = channel(); - client_api.watch(initial_request, sender); - BenchmarkClient { account, current_balance: initial_balance, client_api, receiver } - } -} - -/// Stores timing information about a specific transaction -struct BenchmarkTransaction { - started: Instant, - submitted: Instant, - confirmed: Option, -} - -impl BenchmarkCommand { - pub(crate) fn run(&self, cli: &Cli, trusted_args: &TrustedCli) -> CliResult { - let random_wait_before_transaction_ms: (u32, u32) = ( - self.random_wait_before_transaction_min_ms, - self.random_wait_before_transaction_max_ms, - ); - let store = LocalKeystore::open(get_keystore_path(trusted_args, cli), None).unwrap(); - let funding_account_keys = get_pair_from_str(trusted_args, &self.funding_account, cli); - - let (mrenclave, shard) = get_identifiers(trusted_args, cli); - - // Get shielding pubkey. - let worker_api_direct = get_worker_api_direct(cli); - let shielding_pubkey: Rsa3072PubKey = match worker_api_direct.get_rsa_pubkey() { - Ok(key) => key, - Err(err_msg) => panic!("{}", err_msg.to_string()), - }; - - let nonce_start = get_layer_two_nonce!(funding_account_keys, cli, trusted_args); - 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 {} 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(), cli); - - // Transfer amount from Alice to new account. - let top: TrustedOperation = TrustedCall::balance_transfer( - funding_account_keys.public().into(), - account.public().into(), - initial_balance, - ) - .sign( - &KeyPair::Sr25519(Box::new(funding_account_keys.clone())), - nonce, - &mrenclave, - &shard, - ) - .into_trusted_operation(trusted_args.direct); - - // For the last account we wait for confirmation in order to ensure all accounts were setup correctly - let wait_for_confirmation = i == self.number_clients - 1; - let account_funding_request = get_json_request(shard, &top, shielding_pubkey); - - let client = - BenchmarkClient::new(account, initial_balance, account_funding_request, cli); - let _result = wait_for_top_confirmation(wait_for_confirmation, &client); - accounts.push(client); - } - - rayon::ThreadPoolBuilder::new() - .num_threads(self.number_clients as usize) - .build_global() - .unwrap(); - - let overall_start = Instant::now(); - - // Run actual benchmark logic, in parallel, for each account initialized above. - let outputs: Vec> = accounts - .into_par_iter() - .map(move |mut client| { - let mut output: Vec = Vec::new(); - - for i in 0..self.number_iterations { - println!("Iteration: {}", i); - - if random_wait_before_transaction_ms.1 > 0 { - random_wait(random_wait_before_transaction_ms); - } - - // Create new account. - let account_keys = LocalKeystore::sr25519_generate_new(&store, SR25519_KEY_TYPE, None).unwrap(); - - let new_account = - get_pair_from_str(trusted_args, account_keys.to_string().as_str(), cli); - - println!(" Transfer amount: {}", EXISTENTIAL_DEPOSIT); - println!(" From: {:?}", client.account.public()); - println!(" To: {:?}", new_account.public()); - - // Get nonce of account. - let nonce = get_nonce(client.account.clone(), shard, &client.client_api); - - // Transfer money from client account to new account. - let top: TrustedOperation = TrustedCall::balance_transfer( - client.account.public().into(), - new_account.public().into(), - EXISTENTIAL_DEPOSIT, - ) - .sign(&KeyPair::Sr25519(Box::new(client.account.clone())), nonce, &mrenclave, &shard) - .into_trusted_operation(trusted_args.direct); - - let last_iteration = i == self.number_iterations - 1; - let jsonrpc_call = get_json_request(shard, &top, shielding_pubkey); - client.client_api.send(&jsonrpc_call).unwrap(); - let result = wait_for_top_confirmation( - self.wait_for_confirmation || last_iteration, - &client, - ); - - client.current_balance -= EXISTENTIAL_DEPOSIT; - - let balance = get_balance(client.account.clone(), shard, &client.client_api); - println!("Balance: {}", balance.unwrap_or_default()); - assert_eq!(client.current_balance, balance.unwrap_or_default()); - - output.push(result); - - // FIXME: We probably should re-fund the account in this case. - if client.current_balance <= EXISTENTIAL_DEPOSIT + STF_TX_FEE { - error!("Account {:?} does not have enough balance anymore. Finishing benchmark early", client.account.public()); - break; - } - } - - client.client_api.close().unwrap(); - - output - }) - .collect(); - - println!( - "Finished benchmark with {} clients and {} transactions in {} ms", - self.number_clients, - self.number_iterations, - overall_start.elapsed().as_millis() - ); - - print_benchmark_statistic(outputs, self.wait_for_confirmation); - - Ok(CliResultOk::None) - } -} - -fn get_balance( - account: sr25519::Pair, - shard: ShardIdentifier, - direct_client: &DirectClient, -) -> Option { - let getter = Getter::trusted( - TrustedGetter::free_balance(account.public().into()) - .sign(&KeyPair::Sr25519(Box::new(account.clone()))), - ); - - let getter_start_timer = Instant::now(); - let getter_result = direct_client.get_state(shard, &getter); - let getter_execution_time = getter_start_timer.elapsed().as_millis(); - - let balance = decode_balance(getter_result); - info!("Balance getter execution took {} ms", getter_execution_time,); - debug!("Retrieved {:?} Balance for {:?}", balance.unwrap_or_default(), account.public()); - balance -} - -fn get_nonce( - account: sr25519::Pair, - shard: ShardIdentifier, - direct_client: &DirectClient, -) -> Index { - let getter = Getter::public(PublicGetter::nonce(account.public().into())); - - let getter_start_timer = Instant::now(); - let nonce = get_state::(direct_client, shard, &getter).ok().unwrap_or_default(); - let getter_execution_time = getter_start_timer.elapsed().as_millis(); - info!("Nonce getter execution took {} ms", getter_execution_time,); - debug!("Retrieved {:?} nonce for {:?}", nonce, account.public()); - nonce -} - -fn print_benchmark_statistic(outputs: Vec>, wait_for_confirmation: bool) { - let mut hist = Histogram::::new(1).unwrap(); - for output in outputs { - for t in output { - let benchmarked_timestamp = - if wait_for_confirmation { t.confirmed } else { Some(t.submitted) }; - if let Some(confirmed) = benchmarked_timestamp { - hist += confirmed.duration_since(t.started).as_millis() as u64; - } else { - println!("Missing measurement data"); - } - } - } - - for i in (5..=100).step_by(5) { - let text = format!( - "{} percent are done within {} ms", - i, - hist.value_at_quantile(i as f64 / 100.0) - ); - println!("{}", text); - } -} - -fn random_wait(random_wait_before_transaction_ms: (u32, u32)) { - let mut rng = rand::thread_rng(); - let sleep_time = time::Duration::from_millis( - rng.gen_range(random_wait_before_transaction_ms.0..=random_wait_before_transaction_ms.1) - .into(), - ); - println!("Sleep for: {}ms", sleep_time.as_millis()); - thread::sleep(sleep_time); -} - -fn wait_for_top_confirmation( - wait_for_sidechain_block: bool, - client: &BenchmarkClient, -) -> BenchmarkTransaction { - let started = Instant::now(); - - let submitted = wait_until(&client.receiver, is_submitted); - - let confirmed = if wait_for_sidechain_block { - // We wait for the transaction hash that actually matches the submitted hash - loop { - let transaction_information = wait_until(&client.receiver, is_sidechain_block); - if let Some((hash, _)) = transaction_information { - if hash == submitted.unwrap().0 { - break transaction_information - } - } - } - } else { - None - }; - if let (Some(s), Some(c)) = (submitted, confirmed) { - // Assert the two hashes are identical - assert_eq!(s.0, c.0); - } - - BenchmarkTransaction { - started, - submitted: submitted.unwrap().1, - confirmed: confirmed.map(|v| v.1), - } -} - -fn is_submitted(s: TrustedOperationStatus) -> bool { - matches!(s, Submitted) -} - -fn is_sidechain_block(s: TrustedOperationStatus) -> bool { - matches!(s, InSidechainBlock(_)) -} - -fn decode_balance(maybe_encoded_balance: Option>) -> Option { - maybe_encoded_balance.and_then(|encoded_balance| { - if let Ok(vd) = Balance::decode(&mut encoded_balance.as_slice()) { - Some(vd) - } else { - warn!("Could not decode balance. maybe hasn't been set? {:x?}", encoded_balance); - None - } - }) -} +pub mod request_vc; +pub mod stf; diff --git a/tee-worker/cli/src/benchmark/request_vc.rs b/tee-worker/cli/src/benchmark/request_vc.rs new file mode 100644 index 0000000000..4730f29c95 --- /dev/null +++ b/tee-worker/cli/src/benchmark/request_vc.rs @@ -0,0 +1,166 @@ +use crate::{ + command_utils::{get_shielding_key, get_worker_api_direct}, + trusted_base_cli::commands::litentry::request_vc_subcommands::Command, + trusted_cli::TrustedCli, + trusted_command_utils::{get_identifiers, get_pair_from_str}, + trusted_operation::send_direct_vc_request, + Cli, CliResult, CliResultOk, +}; +use clap::Parser; +use core::time::Duration; +use ita_sgx_runtime::pallet_imt::Identity; +use ita_stf::{Getter, TrustedCall, TrustedCallSigned}; +use itc_rpc_client::direct_client::DirectClient; +use itp_stf_primitives::{ + traits::TrustedCallSigning, + types::{KeyPair, TrustedOperation}, +}; +use litentry_primitives::{RequestAesKey, ShardIdentifier, REQUEST_AES_KEY_LEN}; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use sgx_crypto_helper::rsa3072::Rsa3072PubKey; +use sp_core::Pair; +use std::time::Instant; + +// Command to perform request_vc benchmarking. It creates a given number of threads and sends +// `requests_per_thread` requests one by one recording time to get response. It uses Alice as +// an IdGraph root. If bench case requires any identities to be linked, the preparation should be done +// using other CLI commands. +// Example usage: +// ./litentry-cli trusted benchmark-request-vc 8 400 \ +// did:litentry:substrate:0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48 \ +// a1 +#[derive(Parser)] +pub struct BenchmarkRequestVcCommand { + threads: u32, + requests_per_thread: u32, + // did account to whom the vc will be issued + did: String, + #[clap(subcommand)] + assertion: Command, +} + +struct ActionData<'a> { + client: &'a DirectClient, + request_aes_key: &'a RequestAesKey, + shard_identifier: &'a ShardIdentifier, + shielding_key: &'a Rsa3072PubKey, + top: &'a TrustedOperation, +} + +struct Client<'a> { + client_api: DirectClient, + action: fn(&ActionData) -> Result, + triggers: u32, + aes_key: &'a RequestAesKey, + shard: &'a ShardIdentifier, + shielding_key: &'a Rsa3072PubKey, + top: &'a TrustedOperation, +} + +impl BenchmarkRequestVcCommand { + pub(crate) fn run(&self, cli: &Cli, trusted_cli: &TrustedCli) -> CliResult { + println!("Running request_vc benchmarking"); + let identity = Identity::from_did(self.did.as_str()).unwrap(); + let alice = get_pair_from_str(trusted_cli, "//Alice", cli); + let (mrenclave, shard) = get_identifiers(trusted_cli, cli); + let encryption_key = get_shielding_key(cli).unwrap(); + + let threads = self.threads; + + let mut clients = Vec::with_capacity(threads as usize); + + let assertion = self.assertion.to_assertion().unwrap(); + let aes_key = random_aes_key(); + + let top = TrustedCall::request_vc( + alice.public().into(), + identity, + assertion, + Some(aes_key), + Default::default(), + ) + .sign(&KeyPair::Sr25519(Box::new(alice)), 1, &mrenclave, &shard) + .into_trusted_operation(true); + + for _ in 0..threads { + let worker_api_direct = get_worker_api_direct(cli); + clients.push(Client { + client_api: worker_api_direct, + action: |action_data| { + let action_start: Instant = Instant::now(); + match send_direct_vc_request( + action_data.client, + *action_data.shard_identifier, + action_data.shielding_key, + *action_data.request_aes_key, + action_data.top, + ) { + Ok(mut result) => { + let result = result.remove(0); + match result.result { + Err(_) => Err(()), + Ok(_) => Ok(action_start.elapsed()), + } + }, + Err(_) => Err(()), + } + }, + triggers: self.requests_per_thread, + aes_key: &aes_key, + shard: &shard, + shielding_key: &encryption_key, + top: &top, + }); + } + + rayon::ThreadPoolBuilder::new() + .num_threads(threads as usize) + .build_global() + .unwrap(); + + let overall_start: Instant = Instant::now(); + + let results: Vec>> = clients + .into_par_iter() + .map(move |client| { + let mut results = Vec::with_capacity(client.triggers as usize); + for _ in 0..client.triggers { + let action_data = ActionData { + client: &client.client_api, + request_aes_key: client.aes_key, + shard_identifier: client.shard, + shielding_key: client.shielding_key, + top: client.top, + }; + results.push((client.action)(&action_data)); + } + results + }) + .collect(); + + let mut time_sum = 0_f64; + let mut time_count = 0; + let mut errors_count = 0; + + for result in results { + for result in result { + match result { + Ok(time) => { + time_sum += time.as_secs_f64(); + time_count += 1; + }, + Err(_) => errors_count += 1, + } + } + } + println!("Total time: {:.4}s", overall_start.elapsed().as_secs_f64()); + println!("Average request vc time is: {:.4}s", time_sum / (time_count as f64)); + println!("Errors count: {}", errors_count); + Ok(CliResultOk::None) + } +} + +fn random_aes_key() -> RequestAesKey { + let random: Vec = (0..REQUEST_AES_KEY_LEN).map(|_| rand::random::()).collect(); + random[0..REQUEST_AES_KEY_LEN].try_into().unwrap() +} diff --git a/tee-worker/cli/src/benchmark/stf.rs b/tee-worker/cli/src/benchmark/stf.rs new file mode 100644 index 0000000000..c7abc8bd2f --- /dev/null +++ b/tee-worker/cli/src/benchmark/stf.rs @@ -0,0 +1,378 @@ +/* + Copyright 2021 Integritee AG and Supercomputing Systems AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +use crate::{ + command_utils::get_worker_api_direct, + get_layer_two_nonce, + trusted_cli::TrustedCli, + trusted_command_utils::{get_identifiers, get_keystore_path, get_pair_from_str}, + trusted_operation::{get_json_request, get_state, wait_until}, + Cli, CliResult, CliResultOk, SR25519_KEY_TYPE, +}; +use codec::Decode; +use hdrhistogram::Histogram; +use ita_stf::{ + Getter, Index, PublicGetter, TrustedCall, TrustedCallSigned, TrustedGetter, STF_TX_FEE, +}; +use itc_rpc_client::direct_client::{DirectApi, DirectClient}; +use itp_stf_primitives::{ + traits::TrustedCallSigning, + types::{KeyPair, TrustedOperation}, +}; +use itp_types::{ + Balance, ShardIdentifier, TrustedOperationStatus, + TrustedOperationStatus::{InSidechainBlock, Submitted}, +}; +use log::*; +use rand::Rng; +use rayon::prelude::*; +use sgx_crypto_helper::rsa3072::Rsa3072PubKey; +use sp_application_crypto::sr25519; +use sp_core::{sr25519 as sr25519_core, Pair}; +use sp_keystore::Keystore; +use std::{ + boxed::Box, + string::ToString, + sync::mpsc::{channel, Receiver}, + thread, time, + time::Instant, + vec::Vec, +}; +use substrate_client_keystore::LocalKeystore; + +// Needs to be above the existential deposit minimum, otherwise an account will not +// be created and the state is not increased. +const EXISTENTIAL_DEPOSIT: Balance = 1000; + +#[derive(Parser)] +pub struct BenchmarkStfCommand { + /// The number of clients (=threads) to be used in the benchmark + #[clap(default_value_t = 10)] + number_clients: u32, + + /// The number of iterations to execute for each client + #[clap(default_value_t = 30)] + 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)] + random_wait_before_transaction_min_ms: u32, + + /// Adds a random wait before each transaction. This is the upper bound for the interval in ms. + #[clap(default_value_t = 0)] + random_wait_before_transaction_max_ms: u32, + + /// Whether to wait for "InSidechainBlock" confirmation for each transaction + #[clap(short, long)] + wait_for_confirmation: bool, + + /// Account to be used for initial funding of generated accounts used in benchmark + #[clap(default_value_t = String::from("//Alice"))] + funding_account: String, +} + +struct BenchmarkClient { + account: sr25519_core::Pair, + current_balance: u128, + client_api: DirectClient, + receiver: Receiver, +} + +impl BenchmarkClient { + fn new( + account: sr25519_core::Pair, + initial_balance: u128, + initial_request: String, + cli: &Cli, + ) -> Self { + debug!("get direct api"); + let client_api = get_worker_api_direct(cli); + + debug!("setup sender and receiver"); + let (sender, receiver) = channel(); + client_api.watch(initial_request, sender); + BenchmarkClient { account, current_balance: initial_balance, client_api, receiver } + } +} + +/// Stores timing information about a specific transaction +struct BenchmarkTransaction { + started: Instant, + submitted: Instant, + confirmed: Option, +} + +impl BenchmarkStfCommand { + pub(crate) fn run(&self, cli: &Cli, trusted_args: &TrustedCli) -> CliResult { + let random_wait_before_transaction_ms: (u32, u32) = ( + self.random_wait_before_transaction_min_ms, + self.random_wait_before_transaction_max_ms, + ); + let store = LocalKeystore::open(get_keystore_path(trusted_args, cli), None).unwrap(); + let funding_account_keys = get_pair_from_str(trusted_args, &self.funding_account, cli); + + let (mrenclave, shard) = get_identifiers(trusted_args, cli); + + // Get shielding pubkey. + let worker_api_direct = get_worker_api_direct(cli); + let shielding_pubkey: Rsa3072PubKey = match worker_api_direct.get_rsa_pubkey() { + Ok(key) => key, + Err(err_msg) => panic!("{}", err_msg.to_string()), + }; + + let nonce_start = get_layer_two_nonce!(funding_account_keys, cli, trusted_args); + 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 {} 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(), cli); + + // Transfer amount from Alice to new account. + let top: TrustedOperation = TrustedCall::balance_transfer( + funding_account_keys.public().into(), + account.public().into(), + initial_balance, + ) + .sign( + &KeyPair::Sr25519(Box::new(funding_account_keys.clone())), + nonce, + &mrenclave, + &shard, + ) + .into_trusted_operation(trusted_args.direct); + + // For the last account we wait for confirmation in order to ensure all accounts were setup correctly + let wait_for_confirmation = i == self.number_clients - 1; + let account_funding_request = get_json_request(shard, &top, shielding_pubkey); + + let client = + BenchmarkClient::new(account, initial_balance, account_funding_request, cli); + let _result = wait_for_top_confirmation(wait_for_confirmation, &client); + accounts.push(client); + } + + rayon::ThreadPoolBuilder::new() + .num_threads(self.number_clients as usize) + .build_global() + .unwrap(); + + let overall_start = Instant::now(); + + // Run actual benchmark logic, in parallel, for each account initialized above. + let outputs: Vec> = accounts + .into_par_iter() + .map(move |mut client| { + let mut output: Vec = Vec::new(); + + for i in 0..self.number_iterations { + println!("Iteration: {}", i); + + if random_wait_before_transaction_ms.1 > 0 { + random_wait(random_wait_before_transaction_ms); + } + + // Create new account. + let account_keys = LocalKeystore::sr25519_generate_new(&store, SR25519_KEY_TYPE, None).unwrap(); + + let new_account = + get_pair_from_str(trusted_args, account_keys.to_string().as_str(), cli); + + println!(" Transfer amount: {}", EXISTENTIAL_DEPOSIT); + println!(" From: {:?}", client.account.public()); + println!(" To: {:?}", new_account.public()); + + // Get nonce of account. + let nonce = get_nonce(client.account.clone(), shard, &client.client_api); + + // Transfer money from client account to new account. + let top: TrustedOperation = TrustedCall::balance_transfer( + client.account.public().into(), + new_account.public().into(), + EXISTENTIAL_DEPOSIT, + ) + .sign(&KeyPair::Sr25519(Box::new(client.account.clone())), nonce, &mrenclave, &shard) + .into_trusted_operation(trusted_args.direct); + + let last_iteration = i == self.number_iterations - 1; + let jsonrpc_call = get_json_request(shard, &top, shielding_pubkey); + client.client_api.send(&jsonrpc_call).unwrap(); + let result = wait_for_top_confirmation( + self.wait_for_confirmation || last_iteration, + &client, + ); + + client.current_balance -= EXISTENTIAL_DEPOSIT; + + let balance = get_balance(client.account.clone(), shard, &client.client_api); + println!("Balance: {}", balance.unwrap_or_default()); + assert_eq!(client.current_balance, balance.unwrap_or_default()); + + output.push(result); + + // FIXME: We probably should re-fund the account in this case. + if client.current_balance <= EXISTENTIAL_DEPOSIT + STF_TX_FEE { + error!("Account {:?} does not have enough balance anymore. Finishing benchmark early", client.account.public()); + break; + } + } + + client.client_api.close().unwrap(); + + output + }) + .collect(); + + println!( + "Finished benchmark with {} clients and {} transactions in {} ms", + self.number_clients, + self.number_iterations, + overall_start.elapsed().as_millis() + ); + + print_benchmark_statistic(outputs, self.wait_for_confirmation); + + Ok(CliResultOk::None) + } +} + +fn get_balance( + account: sr25519::Pair, + shard: ShardIdentifier, + direct_client: &DirectClient, +) -> Option { + let getter = Getter::trusted( + TrustedGetter::free_balance(account.public().into()) + .sign(&KeyPair::Sr25519(Box::new(account.clone()))), + ); + + let getter_start_timer = Instant::now(); + let getter_result = direct_client.get_state(shard, &getter); + let getter_execution_time = getter_start_timer.elapsed().as_millis(); + + let balance = decode_balance(getter_result); + info!("Balance getter execution took {} ms", getter_execution_time,); + debug!("Retrieved {:?} Balance for {:?}", balance.unwrap_or_default(), account.public()); + balance +} + +fn get_nonce( + account: sr25519::Pair, + shard: ShardIdentifier, + direct_client: &DirectClient, +) -> Index { + let getter = Getter::public(PublicGetter::nonce(account.public().into())); + + let getter_start_timer = Instant::now(); + let nonce = get_state::(direct_client, shard, &getter).ok().unwrap_or_default(); + let getter_execution_time = getter_start_timer.elapsed().as_millis(); + info!("Nonce getter execution took {} ms", getter_execution_time,); + debug!("Retrieved {:?} nonce for {:?}", nonce, account.public()); + nonce +} + +fn print_benchmark_statistic(outputs: Vec>, wait_for_confirmation: bool) { + let mut hist = Histogram::::new(1).unwrap(); + for output in outputs { + for t in output { + let benchmarked_timestamp = + if wait_for_confirmation { t.confirmed } else { Some(t.submitted) }; + if let Some(confirmed) = benchmarked_timestamp { + hist += confirmed.duration_since(t.started).as_millis() as u64; + } else { + println!("Missing measurement data"); + } + } + } + + for i in (5..=100).step_by(5) { + let text = format!( + "{} percent are done within {} ms", + i, + hist.value_at_quantile(i as f64 / 100.0) + ); + println!("{}", text); + } +} + +fn random_wait(random_wait_before_transaction_ms: (u32, u32)) { + let mut rng = rand::thread_rng(); + let sleep_time = time::Duration::from_millis( + rng.gen_range(random_wait_before_transaction_ms.0..=random_wait_before_transaction_ms.1) + .into(), + ); + println!("Sleep for: {}ms", sleep_time.as_millis()); + thread::sleep(sleep_time); +} + +fn wait_for_top_confirmation( + wait_for_sidechain_block: bool, + client: &BenchmarkClient, +) -> BenchmarkTransaction { + let started = Instant::now(); + + let submitted = wait_until(&client.receiver, is_submitted); + + let confirmed = if wait_for_sidechain_block { + // We wait for the transaction hash that actually matches the submitted hash + loop { + let transaction_information = wait_until(&client.receiver, is_sidechain_block); + if let Some((hash, _)) = transaction_information { + if hash == submitted.unwrap().0 { + break transaction_information + } + } + } + } else { + None + }; + if let (Some(s), Some(c)) = (submitted, confirmed) { + // Assert the two hashes are identical + assert_eq!(s.0, c.0); + } + + BenchmarkTransaction { + started, + submitted: submitted.unwrap().1, + confirmed: confirmed.map(|v| v.1), + } +} + +fn is_submitted(s: TrustedOperationStatus) -> bool { + matches!(s, Submitted) +} + +fn is_sidechain_block(s: TrustedOperationStatus) -> bool { + matches!(s, InSidechainBlock(_)) +} + +fn decode_balance(maybe_encoded_balance: Option>) -> Option { + maybe_encoded_balance.and_then(|encoded_balance| { + if let Ok(vd) = Balance::decode(&mut encoded_balance.as_slice()) { + Some(vd) + } else { + warn!("Could not decode balance. maybe hasn't been set? {:x?}", encoded_balance); + None + } + }) +} diff --git a/tee-worker/cli/src/trusted_base_cli/commands/litentry/mod.rs b/tee-worker/cli/src/trusted_base_cli/commands/litentry/mod.rs index 426274184f..c43a30c81f 100644 --- a/tee-worker/cli/src/trusted_base_cli/commands/litentry/mod.rs +++ b/tee-worker/cli/src/trusted_base_cli/commands/litentry/mod.rs @@ -20,4 +20,5 @@ pub mod link_identity; #[cfg(feature = "development")] pub mod remove_identity; pub mod request_vc; +pub mod request_vc_subcommands; pub mod send_erroneous_parentchain_call; diff --git a/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs b/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs index 3c1fa77572..4aa9998eb5 100644 --- a/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs +++ b/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs @@ -16,26 +16,23 @@ use crate::{ get_layer_two_nonce, + trusted_base_cli::commands::litentry::request_vc_subcommands::Command, trusted_cli::TrustedCli, trusted_command_utils::{get_identifiers, get_pair_from_str}, - trusted_operation::{perform_trusted_operation, send_direct_vc_request}, - Cli, CliError, CliResult, CliResultOk, + trusted_operation::{ + perform_trusted_operation, prepare_request_data_and_send_direct_vc_request, + }, + Cli, CliResult, CliResultOk, }; use clap::Parser; use codec::Decode; use ita_stf::{trusted_call_result::RequestVCResult, Index, TrustedCall}; use itp_stf_primitives::{traits::TrustedCallSigning, types::KeyPair}; -use litentry_hex_utils::decode_hex; use litentry_primitives::{ - aes_decrypt, AchainableAmount, AchainableAmountHolding, AchainableAmountToken, - AchainableAmounts, AchainableBasic, AchainableBetweenPercents, AchainableClassOfYear, - AchainableDate, AchainableDateInterval, AchainableDatePercent, AchainableParams, - AchainableToken, Assertion, BnbDigitDomainType, BoundedWeb3Network, ContestType, - DynamicContractParams, DynamicParams, EVMTokenType, GenericDiscordRoleType, Identity, - OneBlockCourseType, ParameterString, PlatformUserType, RequestAesKey, SoraQuizType, - VIP3MembershipCardLevel, Web3Network, Web3NftType, Web3TokenType, REQUEST_AES_KEY_LEN, + aes_decrypt, Assertion, BoundedWeb3Network, Identity, ParameterString, RequestAesKey, + Web3Network, REQUEST_AES_KEY_LEN, }; -use sp_core::{Pair, H160, H256}; +use sp_core::{Pair, H256}; // usage example below // @@ -100,274 +97,6 @@ pub struct RequestVcCommand { assertion: Vec, } -#[derive(Debug, Parser)] -// the wrapper to the underlying `subcommand` type -pub struct AssertionCommand { - /// subcommand to define the vc type requested - #[clap(subcommand)] - command: Command, -} - -// see `assertion.rs` -#[derive(Subcommand, Debug)] -pub enum Command { - A1, - A2(A2Arg), - A3(A3Arg), - A4(HolderArg), - A6, - A7(HolderArg), - A8(A8Arg), - A10(HolderArg), - A11(HolderArg), - A13(A13Arg), - A14, - #[clap(subcommand)] - Achainable(AchainableCommand), - A20, - #[clap(subcommand)] - OneBlock(OneblockCommand), - #[clap(subcommand)] - GenericDiscordRole(GenericDiscordRoleCommand), - BnbDomainHolding, - #[clap(subcommand)] - BnbDigitalDomainClub(BnbDigitalDomainClubCommand), - #[clap(subcommand)] - VIP3MembershipCard(VIP3MembershipCardLevelCommand), - WeirdoGhostGangHolder, - LITStaking, - #[clap(subcommand)] - EVMAmountHolding(EVMAmountHoldingCommand), - BRC20AmountHolder, - CryptoSummary, - #[clap(subcommand)] - TokenHoldingAmount(TokenHoldingAmountCommand), - #[clap(subcommand)] - PlatformUser(PlatformUserCommand), - #[clap(subcommand)] - NftHolder(NftHolderCommand), - Dynamic(DynamicArg), -} - -#[derive(Args, Debug)] -pub struct A2Arg { - pub guild_id: String, -} - -#[derive(Args, Debug)] -pub struct DynamicArg { - // hex encoded smart contract id - pub smart_contract_id: String, - // hex encoded smart contract params - // can use this online tool to encode params: https://abi.hashex.org/ - pub smart_contract_param: Option, - pub return_log: Option, -} - -#[derive(Args, Debug)] -pub struct A3Arg { - pub guild_id: String, - pub channel_id: String, - pub role_id: String, -} - -// used in A4/A7/A10/A11 -#[derive(Args, Debug)] -pub struct HolderArg { - pub minimum_amount: String, -} - -#[derive(Args, Debug)] -pub struct A8Arg { - #[clap(num_args = 0.., value_delimiter = ',')] - pub networks: Vec, -} - -#[derive(Args, Debug)] -pub struct A13Arg { - pub account: String, -} - -#[derive(Subcommand, Debug)] -pub enum AchainableCommand { - AmountHolding(AmountHoldingArg), - AmountToken(AmountTokenArg), - Amount(AmountArg), - Amounts(AmountsArg), - Basic(BasicArg), - BetweenPercents(BetweenPercentsArg), - ClassOfYear(ClassOfYearArg), - DateInterval(DateIntervalArg), - DatePercent(DatePercentArg), - Date(DateArg), - Token(TokenArg), -} - -#[derive(Subcommand, Debug)] -pub enum OneblockCommand { - Completion, - Outstanding, - Participation, -} - -#[derive(Subcommand, Debug)] -pub enum GenericDiscordRoleCommand { - #[clap(subcommand)] - Contest(ContestCommand), - #[clap(subcommand)] - SoraQuiz(SoraQuizCommand), -} - -#[derive(Subcommand, Debug)] -pub enum ContestCommand { - Legend, - Popularity, - Participant, -} - -#[derive(Subcommand, Debug)] -pub enum SoraQuizCommand { - Attendee, - Master, -} - -#[derive(Subcommand, Debug)] -pub enum BnbDigitalDomainClubCommand { - Bnb999ClubMember, - Bnb10kClubMember, -} - -#[derive(Subcommand, Debug)] -pub enum VIP3MembershipCardLevelCommand { - Gold, - Silver, -} - -#[derive(Subcommand, Debug)] -pub enum EVMAmountHoldingCommand { - Ton, - Trx, -} - -#[derive(Subcommand, Debug)] -pub enum TokenHoldingAmountCommand { - Bnb, - Eth, - SpaceId, - Lit, - Wbtc, - Usdc, - Usdt, - Crv, - Matic, - Dydx, - Amp, - Cvx, - Tusd, - Usdd, - Gusd, - Link, - Grt, - Comp, - People, - Gtc, - Ton, - Trx, - Nfp, - Sol, - Mcrt, - Btc, - Bean, - An, - Tuna, -} - -#[derive(Subcommand, Debug)] -pub enum PlatformUserCommand { - KaratDao, - MagicCraftStaking, - DarenMarket, -} - -#[derive(Subcommand, Debug)] -pub enum NftHolderCommand { - WeirdoGhostGang, - Club3Sbt, - MFan, - Mvp, -} - -// positional args (to vec) + required arg + optional arg is a nightmare combination for clap parser, -// additionally, only the last positional argument, or second to last positional argument may be set to `.num_args()` -// -// the best bet is to use a flag explicitly, be sure to use equal form for `chain`, e.g.: -// -- name -c=bsc,ethereum 10 -// -- name -c=bsc,ethereum 10 token -macro_rules! AchainableCommandArgs { - ($type_name:ident, {$( $field_name:ident : $field_type:ty , )* }) => { - #[derive(Args, Debug)] - pub struct $type_name { - pub name: String, - #[clap( - short, long, - num_args = 1.., - required = true, - value_delimiter = ',', - )] - pub chain: Vec, - $( pub $field_name: $field_type ),* - } - }; -} - -AchainableCommandArgs!(AmountHoldingArg, { - amount: String, - date: String, - token: Option, -}); - -AchainableCommandArgs!(AmountTokenArg, { - amount: String, - token: Option, -}); - -AchainableCommandArgs!(AmountArg, { - amount: String, -}); - -AchainableCommandArgs!(AmountsArg, { - amount1: String, - amount2: String, -}); - -AchainableCommandArgs!(BasicArg, {}); - -AchainableCommandArgs!(BetweenPercentsArg, { - greater_than_or_equal_to: String, - less_than_or_equal_to: String, -}); - -AchainableCommandArgs!(ClassOfYearArg, {}); - -AchainableCommandArgs!(DateIntervalArg, { - start_date: String, - end_date: String, -}); - -AchainableCommandArgs!(DatePercentArg, { - token: String, - date: String, - percent: String, -}); - -AchainableCommandArgs!(DateArg, { - date: String, -}); - -AchainableCommandArgs!(TokenArg, { - token: String, -}); - fn print_vc(key: &RequestAesKey, mut vc: RequestVCResult) { let decrypted = aes_decrypt(key, &mut vc.vc_payload).unwrap(); let credential_str = String::from_utf8(decrypted).expect("Found invalid UTF-8"); @@ -449,10 +178,10 @@ impl RequestVcCommand { Some(key), Default::default(), ) - .sign(&KeyPair::Sr25519(Box::new(alice)), nonce, &mrenclave, &shard) + .sign(&KeyPair::Sr25519(Box::new(alice)), 0, &mrenclave, &shard) .into_trusted_operation(trusted_cli.direct); - match send_direct_vc_request(cli, trusted_cli, &top, key) { + match prepare_request_data_and_send_direct_vc_request(cli, trusted_cli, &top, key) { Ok(result) => for res in result { match res.result { @@ -480,224 +209,10 @@ impl RequestVcCommand { } } -impl Command { - // helper fn to convert a `Command` to `Assertion` - pub fn to_assertion(&self) -> Result { - use Assertion::*; - match self { - Command::A1 => Ok(A1), - Command::A2(arg) => Ok(A2(to_para_str(&arg.guild_id))), - Command::A3(arg) => Ok(A3( - to_para_str(&arg.guild_id), - to_para_str(&arg.channel_id), - to_para_str(&arg.role_id), - )), - Command::A4(arg) => Ok(A4(to_para_str(&arg.minimum_amount))), - Command::A6 => Ok(A6), - Command::A7(arg) => Ok(A7(to_para_str(&arg.minimum_amount))), - Command::A8(arg) => Ok(A8(to_chains(&arg.networks))), - Command::A10(arg) => Ok(A10(to_para_str(&arg.minimum_amount))), - Command::A11(arg) => Ok(A11(to_para_str(&arg.minimum_amount))), - Command::A13(arg) => { - let raw: [u8; 32] = decode_hex(&arg.account).unwrap().try_into().unwrap(); - Ok(A13(raw.into())) - }, - Command::A14 => Ok(A14), - Command::Achainable(c) => Ok(match c { - AchainableCommand::AmountHolding(arg) => - Achainable(AchainableParams::AmountHolding(AchainableAmountHolding { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - amount: to_para_str(&arg.amount), - date: to_para_str(&arg.date), - token: arg.token.as_ref().map(to_para_str), - })), - AchainableCommand::AmountToken(arg) => - Achainable(AchainableParams::AmountToken(AchainableAmountToken { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - amount: to_para_str(&arg.amount), - token: arg.token.as_ref().map(to_para_str), - })), - AchainableCommand::Amount(arg) => - Achainable(AchainableParams::Amount(AchainableAmount { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - amount: to_para_str(&arg.amount), - })), - AchainableCommand::Amounts(arg) => - Achainable(AchainableParams::Amounts(AchainableAmounts { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - amount1: to_para_str(&arg.amount1), - amount2: to_para_str(&arg.amount2), - })), - AchainableCommand::Basic(arg) => - Achainable(AchainableParams::Basic(AchainableBasic { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - })), - AchainableCommand::BetweenPercents(arg) => - Achainable(AchainableParams::BetweenPercents(AchainableBetweenPercents { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - greater_than_or_equal_to: to_para_str(&arg.greater_than_or_equal_to), - less_than_or_equal_to: to_para_str(&arg.less_than_or_equal_to), - })), - AchainableCommand::ClassOfYear(arg) => - Achainable(AchainableParams::ClassOfYear(AchainableClassOfYear { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - })), - AchainableCommand::DateInterval(arg) => - Achainable(AchainableParams::DateInterval(AchainableDateInterval { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - start_date: to_para_str(&arg.start_date), - end_date: to_para_str(&arg.end_date), - })), - AchainableCommand::DatePercent(arg) => - Achainable(AchainableParams::DatePercent(AchainableDatePercent { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - date: to_para_str(&arg.date), - percent: to_para_str(&arg.percent), - token: to_para_str(&arg.token), - })), - AchainableCommand::Date(arg) => - Achainable(AchainableParams::Date(AchainableDate { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - date: to_para_str(&arg.date), - })), - AchainableCommand::Token(arg) => - Achainable(AchainableParams::Token(AchainableToken { - name: to_para_str(&arg.name), - chain: to_chains(&arg.chain), - token: to_para_str(&arg.token), - })), - }), - Command::A20 => Ok(A20), - Command::OneBlock(c) => Ok(match c { - OneblockCommand::Completion => OneBlock(OneBlockCourseType::CourseCompletion), - OneblockCommand::Outstanding => OneBlock(OneBlockCourseType::CourseOutstanding), - OneblockCommand::Participation => OneBlock(OneBlockCourseType::CourseParticipation), - }), - Command::GenericDiscordRole(c) => Ok(match c { - GenericDiscordRoleCommand::Contest(s) => match s { - ContestCommand::Legend => - GenericDiscordRole(GenericDiscordRoleType::Contest(ContestType::Legend)), - ContestCommand::Popularity => - GenericDiscordRole(GenericDiscordRoleType::Contest(ContestType::Popularity)), - ContestCommand::Participant => GenericDiscordRole( - GenericDiscordRoleType::Contest(ContestType::Participant), - ), - }, - GenericDiscordRoleCommand::SoraQuiz(s) => match s { - SoraQuizCommand::Attendee => - GenericDiscordRole(GenericDiscordRoleType::SoraQuiz(SoraQuizType::Attendee)), - SoraQuizCommand::Master => - GenericDiscordRole(GenericDiscordRoleType::SoraQuiz(SoraQuizType::Master)), - }, - }), - Command::BnbDomainHolding => Ok(BnbDomainHolding), - Command::BnbDigitalDomainClub(c) => Ok(match c { - BnbDigitalDomainClubCommand::Bnb999ClubMember => - BnbDigitDomainClub(BnbDigitDomainType::Bnb999ClubMember), - BnbDigitalDomainClubCommand::Bnb10kClubMember => - BnbDigitDomainClub(BnbDigitDomainType::Bnb10kClubMember), - }), - Command::VIP3MembershipCard(arg) => Ok(match arg { - VIP3MembershipCardLevelCommand::Gold => - VIP3MembershipCard(VIP3MembershipCardLevel::Gold), - VIP3MembershipCardLevelCommand::Silver => - VIP3MembershipCard(VIP3MembershipCardLevel::Silver), - }), - Command::WeirdoGhostGangHolder => Ok(WeirdoGhostGangHolder), - Command::EVMAmountHolding(c) => Ok(match c { - EVMAmountHoldingCommand::Ton => EVMAmountHolding(EVMTokenType::Ton), - EVMAmountHoldingCommand::Trx => EVMAmountHolding(EVMTokenType::Trx), - }), - Command::CryptoSummary => Ok(CryptoSummary), - Command::LITStaking => Ok(LITStaking), - Command::BRC20AmountHolder => Ok(BRC20AmountHolder), - Command::TokenHoldingAmount(arg) => Ok(match arg { - TokenHoldingAmountCommand::Bnb => TokenHoldingAmount(Web3TokenType::Bnb), - TokenHoldingAmountCommand::Eth => TokenHoldingAmount(Web3TokenType::Eth), - TokenHoldingAmountCommand::SpaceId => TokenHoldingAmount(Web3TokenType::SpaceId), - TokenHoldingAmountCommand::Lit => TokenHoldingAmount(Web3TokenType::Lit), - TokenHoldingAmountCommand::Wbtc => TokenHoldingAmount(Web3TokenType::Wbtc), - TokenHoldingAmountCommand::Usdc => TokenHoldingAmount(Web3TokenType::Usdc), - TokenHoldingAmountCommand::Usdt => TokenHoldingAmount(Web3TokenType::Usdt), - TokenHoldingAmountCommand::Crv => TokenHoldingAmount(Web3TokenType::Crv), - TokenHoldingAmountCommand::Matic => TokenHoldingAmount(Web3TokenType::Matic), - TokenHoldingAmountCommand::Dydx => TokenHoldingAmount(Web3TokenType::Dydx), - TokenHoldingAmountCommand::Amp => TokenHoldingAmount(Web3TokenType::Amp), - TokenHoldingAmountCommand::Cvx => TokenHoldingAmount(Web3TokenType::Cvx), - TokenHoldingAmountCommand::Tusd => TokenHoldingAmount(Web3TokenType::Tusd), - TokenHoldingAmountCommand::Usdd => TokenHoldingAmount(Web3TokenType::Usdd), - TokenHoldingAmountCommand::Gusd => TokenHoldingAmount(Web3TokenType::Gusd), - TokenHoldingAmountCommand::Link => TokenHoldingAmount(Web3TokenType::Link), - TokenHoldingAmountCommand::Grt => TokenHoldingAmount(Web3TokenType::Grt), - TokenHoldingAmountCommand::Comp => TokenHoldingAmount(Web3TokenType::Comp), - TokenHoldingAmountCommand::People => TokenHoldingAmount(Web3TokenType::People), - TokenHoldingAmountCommand::Gtc => TokenHoldingAmount(Web3TokenType::Gtc), - TokenHoldingAmountCommand::Ton => TokenHoldingAmount(Web3TokenType::Ton), - TokenHoldingAmountCommand::Trx => TokenHoldingAmount(Web3TokenType::Trx), - TokenHoldingAmountCommand::Nfp => TokenHoldingAmount(Web3TokenType::Nfp), - TokenHoldingAmountCommand::Sol => TokenHoldingAmount(Web3TokenType::Sol), - TokenHoldingAmountCommand::Mcrt => TokenHoldingAmount(Web3TokenType::Mcrt), - TokenHoldingAmountCommand::Btc => TokenHoldingAmount(Web3TokenType::Btc), - TokenHoldingAmountCommand::Bean => TokenHoldingAmount(Web3TokenType::Bean), - TokenHoldingAmountCommand::An => TokenHoldingAmount(Web3TokenType::An), - TokenHoldingAmountCommand::Tuna => TokenHoldingAmount(Web3TokenType::Tuna), - }), - Command::PlatformUser(arg) => Ok(match arg { - PlatformUserCommand::KaratDao => PlatformUser(PlatformUserType::KaratDao), - PlatformUserCommand::MagicCraftStaking => - PlatformUser(PlatformUserType::MagicCraftStaking), - PlatformUserCommand::DarenMarket => PlatformUser(PlatformUserType::DarenMarket), - }), - Command::NftHolder(arg) => Ok(match arg { - NftHolderCommand::WeirdoGhostGang => NftHolder(Web3NftType::WeirdoGhostGang), - NftHolderCommand::Club3Sbt => NftHolder(Web3NftType::Club3Sbt), - NftHolderCommand::MFan => NftHolder(Web3NftType::MFan), - NftHolderCommand::Mvp => NftHolder(Web3NftType::Mvp), - }), - Command::Dynamic(arg) => { - let decoded_id = hex::decode(&arg.smart_contract_id.clone()).unwrap(); - let id_bytes: [u8; 20] = decoded_id.try_into().unwrap(); - - let smart_contract_params = match &arg.smart_contract_param { - Some(p) => { - let params = hex::decode(p).unwrap(); - let params_len = params.len(); - let truncated_params = DynamicContractParams::truncate_from(params); - let truncated_params_len = truncated_params.len(); - if params_len > truncated_params_len { - println!( - "The dynamic params length {} is over the maximum value {}", - params_len, truncated_params_len - ); - Err(CliError::Extrinsic { - msg: format!( - "The dynamic params length {} is over the maximum value {}", - params_len, truncated_params_len - ), - }) - } else { - Ok(Some(truncated_params)) - } - }, - None => Ok(None), - }?; - - Ok(Assertion::Dynamic(DynamicParams { - smart_contract_id: H160::from(id_bytes), - smart_contract_params, - return_log: arg.return_log.unwrap_or_default(), - })) - }, - } - } +#[derive(Debug, clap::Parser)] +// the wrapper to the underlying `subcommand` type +pub struct AssertionCommand { + /// subcommand to define the vc type requested + #[clap(subcommand)] + pub command: Command, } diff --git a/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc_direct.rs b/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc_direct.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc_subcommands.rs b/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc_subcommands.rs new file mode 100644 index 0000000000..832b8636f8 --- /dev/null +++ b/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc_subcommands.rs @@ -0,0 +1,497 @@ +use crate::{ + trusted_base_cli::commands::litentry::request_vc::{to_chains, to_para_str}, + CliError, +}; +use ita_stf::Assertion; +use litentry_hex_utils::decode_hex; +use litentry_primitives::{ + AchainableAmount, AchainableAmountHolding, AchainableAmountToken, AchainableAmounts, + AchainableBasic, AchainableBetweenPercents, AchainableClassOfYear, AchainableDate, + AchainableDateInterval, AchainableDatePercent, AchainableParams, AchainableToken, + BnbDigitDomainType, ContestType, DynamicContractParams, DynamicParams, EVMTokenType, + GenericDiscordRoleType, OneBlockCourseType, PlatformUserType, SoraQuizType, + VIP3MembershipCardLevel, Web3NftType, Web3TokenType, +}; +use sp_core::H160; + +// see `assertion.rs` +#[derive(Subcommand, Debug)] +pub enum Command { + A1, + A2(A2Arg), + A3(A3Arg), + A4(HolderArg), + A6, + A7(HolderArg), + A8(A8Arg), + A10(HolderArg), + A11(HolderArg), + A13(A13Arg), + A14, + #[clap(subcommand)] + Achainable(AchainableCommand), + A20, + #[clap(subcommand)] + OneBlock(OneblockCommand), + #[clap(subcommand)] + GenericDiscordRole(GenericDiscordRoleCommand), + BnbDomainHolding, + #[clap(subcommand)] + BnbDigitalDomainClub(BnbDigitalDomainClubCommand), + #[clap(subcommand)] + VIP3MembershipCard(VIP3MembershipCardLevelCommand), + WeirdoGhostGangHolder, + LITStaking, + #[clap(subcommand)] + EVMAmountHolding(EVMAmountHoldingCommand), + BRC20AmountHolder, + CryptoSummary, + #[clap(subcommand)] + TokenHoldingAmount(TokenHoldingAmountCommand), + #[clap(subcommand)] + PlatformUser(PlatformUserCommand), + #[clap(subcommand)] + NftHolder(NftHolderCommand), + Dynamic(DynamicArg), +} + +#[derive(Args, Debug)] +pub struct A2Arg { + pub guild_id: String, +} + +#[derive(Args, Debug)] +pub struct DynamicArg { + // hex encoded smart contract id + pub smart_contract_id: String, + // hex encoded smart contract params + // can use this online tool to encode params: https://abi.hashex.org/ + pub smart_contract_param: Option, + pub return_log: Option, +} + +#[derive(Args, Debug)] +pub struct A3Arg { + pub guild_id: String, + pub channel_id: String, + pub role_id: String, +} + +// used in A4/A7/A10/A11 +#[derive(Args, Debug)] +pub struct HolderArg { + pub minimum_amount: String, +} + +#[derive(Args, Debug)] +pub struct A8Arg { + #[clap(num_args = 0.., value_delimiter = ',')] + pub networks: Vec, +} + +#[derive(Args, Debug)] +pub struct A13Arg { + pub account: String, +} + +#[derive(Subcommand, Debug)] +pub enum AchainableCommand { + AmountHolding(AmountHoldingArg), + AmountToken(AmountTokenArg), + Amount(AmountArg), + Amounts(AmountsArg), + Basic(BasicArg), + BetweenPercents(BetweenPercentsArg), + ClassOfYear(ClassOfYearArg), + DateInterval(DateIntervalArg), + DatePercent(DatePercentArg), + Date(DateArg), + Token(TokenArg), +} + +#[derive(Subcommand, Debug)] +pub enum OneblockCommand { + Completion, + Outstanding, + Participation, +} + +#[derive(Subcommand, Debug)] +pub enum GenericDiscordRoleCommand { + #[clap(subcommand)] + Contest(ContestCommand), + #[clap(subcommand)] + SoraQuiz(SoraQuizCommand), +} + +#[derive(Subcommand, Debug)] +pub enum ContestCommand { + Legend, + Popularity, + Participant, +} + +#[derive(Subcommand, Debug)] +pub enum SoraQuizCommand { + Attendee, + Master, +} + +#[derive(Subcommand, Debug)] +pub enum BnbDigitalDomainClubCommand { + Bnb999ClubMember, + Bnb10kClubMember, +} + +#[derive(Subcommand, Debug)] +pub enum VIP3MembershipCardLevelCommand { + Gold, + Silver, +} + +#[derive(Subcommand, Debug)] +pub enum EVMAmountHoldingCommand { + Ton, + Trx, +} + +#[derive(Subcommand, Debug)] +pub enum TokenHoldingAmountCommand { + Bnb, + Eth, + SpaceId, + Lit, + Wbtc, + Usdc, + Usdt, + Crv, + Matic, + Dydx, + Amp, + Cvx, + Tusd, + Usdd, + Gusd, + Link, + Grt, + Comp, + People, + Gtc, + Ton, + Trx, + Nfp, + Sol, + Mcrt, + Btc, + Bean, + An, + Tuna, +} + +#[derive(Subcommand, Debug)] +pub enum PlatformUserCommand { + KaratDao, + MagicCraftStaking, + DarenMarket, +} + +#[derive(Subcommand, Debug)] +pub enum NftHolderCommand { + WeirdoGhostGang, + Club3Sbt, + MFan, + Mvp, +} + +// positional args (to vec) + required arg + optional arg is a nightmare combination for clap parser, +// additionally, only the last positional argument, or second to last positional argument may be set to `.num_args()` +// +// the best bet is to use a flag explicitly, be sure to use equal form for `chain`, e.g.: +// -- name -c=bsc,ethereum 10 +// -- name -c=bsc,ethereum 10 token +macro_rules! AchainableCommandArgs { + ($type_name:ident, {$( $field_name:ident : $field_type:ty , )* }) => { + #[derive(Args, Debug)] + pub struct $type_name { + pub name: String, + #[clap( + short, long, + num_args = 1.., + required = true, + value_delimiter = ',', + )] + pub chain: Vec, + $( pub $field_name: $field_type ),* + } + }; +} + +AchainableCommandArgs!(AmountHoldingArg, { + amount: String, + date: String, + token: Option, +}); + +AchainableCommandArgs!(AmountTokenArg, { + amount: String, + token: Option, +}); + +AchainableCommandArgs!(AmountArg, { + amount: String, +}); + +AchainableCommandArgs!(AmountsArg, { + amount1: String, + amount2: String, +}); + +AchainableCommandArgs!(BasicArg, {}); + +AchainableCommandArgs!(BetweenPercentsArg, { + greater_than_or_equal_to: String, + less_than_or_equal_to: String, +}); + +AchainableCommandArgs!(ClassOfYearArg, {}); + +AchainableCommandArgs!(DateIntervalArg, { + start_date: String, + end_date: String, +}); + +AchainableCommandArgs!(DatePercentArg, { + token: String, + date: String, + percent: String, +}); + +AchainableCommandArgs!(DateArg, { + date: String, +}); + +AchainableCommandArgs!(TokenArg, { + token: String, +}); + +impl Command { + // helper fn to convert a `Command` to `Assertion` + pub fn to_assertion(&self) -> Result { + use Assertion::*; + match self { + Command::A1 => Ok(A1), + Command::A2(arg) => Ok(A2(to_para_str(&arg.guild_id))), + Command::A3(arg) => Ok(A3( + to_para_str(&arg.guild_id), + to_para_str(&arg.channel_id), + to_para_str(&arg.role_id), + )), + Command::A4(arg) => Ok(A4(to_para_str(&arg.minimum_amount))), + Command::A6 => Ok(A6), + Command::A7(arg) => Ok(A7(to_para_str(&arg.minimum_amount))), + Command::A8(arg) => Ok(A8(to_chains(&arg.networks))), + Command::A10(arg) => Ok(A10(to_para_str(&arg.minimum_amount))), + Command::A11(arg) => Ok(A11(to_para_str(&arg.minimum_amount))), + Command::A13(arg) => { + let raw: [u8; 32] = decode_hex(&arg.account).unwrap().try_into().unwrap(); + Ok(A13(raw.into())) + }, + Command::A14 => Ok(A14), + Command::Achainable(c) => Ok(match c { + AchainableCommand::AmountHolding(arg) => + Achainable(AchainableParams::AmountHolding(AchainableAmountHolding { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + amount: to_para_str(&arg.amount), + date: to_para_str(&arg.date), + token: arg.token.as_ref().map(to_para_str), + })), + AchainableCommand::AmountToken(arg) => + Achainable(AchainableParams::AmountToken(AchainableAmountToken { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + amount: to_para_str(&arg.amount), + token: arg.token.as_ref().map(to_para_str), + })), + AchainableCommand::Amount(arg) => + Achainable(AchainableParams::Amount(AchainableAmount { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + amount: to_para_str(&arg.amount), + })), + AchainableCommand::Amounts(arg) => + Achainable(AchainableParams::Amounts(AchainableAmounts { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + amount1: to_para_str(&arg.amount1), + amount2: to_para_str(&arg.amount2), + })), + AchainableCommand::Basic(arg) => + Achainable(AchainableParams::Basic(AchainableBasic { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + })), + AchainableCommand::BetweenPercents(arg) => + Achainable(AchainableParams::BetweenPercents(AchainableBetweenPercents { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + greater_than_or_equal_to: to_para_str(&arg.greater_than_or_equal_to), + less_than_or_equal_to: to_para_str(&arg.less_than_or_equal_to), + })), + AchainableCommand::ClassOfYear(arg) => + Achainable(AchainableParams::ClassOfYear(AchainableClassOfYear { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + })), + AchainableCommand::DateInterval(arg) => + Achainable(AchainableParams::DateInterval(AchainableDateInterval { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + start_date: to_para_str(&arg.start_date), + end_date: to_para_str(&arg.end_date), + })), + AchainableCommand::DatePercent(arg) => + Achainable(AchainableParams::DatePercent(AchainableDatePercent { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + date: to_para_str(&arg.date), + percent: to_para_str(&arg.percent), + token: to_para_str(&arg.token), + })), + AchainableCommand::Date(arg) => + Achainable(AchainableParams::Date(AchainableDate { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + date: to_para_str(&arg.date), + })), + AchainableCommand::Token(arg) => + Achainable(AchainableParams::Token(AchainableToken { + name: to_para_str(&arg.name), + chain: to_chains(&arg.chain), + token: to_para_str(&arg.token), + })), + }), + Command::A20 => Ok(A20), + Command::OneBlock(c) => Ok(match c { + OneblockCommand::Completion => OneBlock(OneBlockCourseType::CourseCompletion), + OneblockCommand::Outstanding => OneBlock(OneBlockCourseType::CourseOutstanding), + OneblockCommand::Participation => OneBlock(OneBlockCourseType::CourseParticipation), + }), + Command::GenericDiscordRole(c) => Ok(match c { + GenericDiscordRoleCommand::Contest(s) => match s { + ContestCommand::Legend => + GenericDiscordRole(GenericDiscordRoleType::Contest(ContestType::Legend)), + ContestCommand::Popularity => + GenericDiscordRole(GenericDiscordRoleType::Contest(ContestType::Popularity)), + ContestCommand::Participant => GenericDiscordRole( + GenericDiscordRoleType::Contest(ContestType::Participant), + ), + }, + GenericDiscordRoleCommand::SoraQuiz(s) => match s { + SoraQuizCommand::Attendee => + GenericDiscordRole(GenericDiscordRoleType::SoraQuiz(SoraQuizType::Attendee)), + SoraQuizCommand::Master => + GenericDiscordRole(GenericDiscordRoleType::SoraQuiz(SoraQuizType::Master)), + }, + }), + Command::BnbDomainHolding => Ok(BnbDomainHolding), + Command::BnbDigitalDomainClub(c) => Ok(match c { + BnbDigitalDomainClubCommand::Bnb999ClubMember => + BnbDigitDomainClub(BnbDigitDomainType::Bnb999ClubMember), + BnbDigitalDomainClubCommand::Bnb10kClubMember => + BnbDigitDomainClub(BnbDigitDomainType::Bnb10kClubMember), + }), + Command::VIP3MembershipCard(arg) => Ok(match arg { + VIP3MembershipCardLevelCommand::Gold => + VIP3MembershipCard(VIP3MembershipCardLevel::Gold), + VIP3MembershipCardLevelCommand::Silver => + VIP3MembershipCard(VIP3MembershipCardLevel::Silver), + }), + Command::WeirdoGhostGangHolder => Ok(WeirdoGhostGangHolder), + Command::EVMAmountHolding(c) => Ok(match c { + EVMAmountHoldingCommand::Ton => EVMAmountHolding(EVMTokenType::Ton), + EVMAmountHoldingCommand::Trx => EVMAmountHolding(EVMTokenType::Trx), + }), + Command::CryptoSummary => Ok(CryptoSummary), + Command::LITStaking => Ok(LITStaking), + Command::BRC20AmountHolder => Ok(BRC20AmountHolder), + Command::TokenHoldingAmount(arg) => Ok(match arg { + TokenHoldingAmountCommand::Bnb => TokenHoldingAmount(Web3TokenType::Bnb), + TokenHoldingAmountCommand::Eth => TokenHoldingAmount(Web3TokenType::Eth), + TokenHoldingAmountCommand::SpaceId => TokenHoldingAmount(Web3TokenType::SpaceId), + TokenHoldingAmountCommand::Lit => TokenHoldingAmount(Web3TokenType::Lit), + TokenHoldingAmountCommand::Wbtc => TokenHoldingAmount(Web3TokenType::Wbtc), + TokenHoldingAmountCommand::Usdc => TokenHoldingAmount(Web3TokenType::Usdc), + TokenHoldingAmountCommand::Usdt => TokenHoldingAmount(Web3TokenType::Usdt), + TokenHoldingAmountCommand::Crv => TokenHoldingAmount(Web3TokenType::Crv), + TokenHoldingAmountCommand::Matic => TokenHoldingAmount(Web3TokenType::Matic), + TokenHoldingAmountCommand::Dydx => TokenHoldingAmount(Web3TokenType::Dydx), + TokenHoldingAmountCommand::Amp => TokenHoldingAmount(Web3TokenType::Amp), + TokenHoldingAmountCommand::Cvx => TokenHoldingAmount(Web3TokenType::Cvx), + TokenHoldingAmountCommand::Tusd => TokenHoldingAmount(Web3TokenType::Tusd), + TokenHoldingAmountCommand::Usdd => TokenHoldingAmount(Web3TokenType::Usdd), + TokenHoldingAmountCommand::Gusd => TokenHoldingAmount(Web3TokenType::Gusd), + TokenHoldingAmountCommand::Link => TokenHoldingAmount(Web3TokenType::Link), + TokenHoldingAmountCommand::Grt => TokenHoldingAmount(Web3TokenType::Grt), + TokenHoldingAmountCommand::Comp => TokenHoldingAmount(Web3TokenType::Comp), + TokenHoldingAmountCommand::People => TokenHoldingAmount(Web3TokenType::People), + TokenHoldingAmountCommand::Gtc => TokenHoldingAmount(Web3TokenType::Gtc), + TokenHoldingAmountCommand::Ton => TokenHoldingAmount(Web3TokenType::Ton), + TokenHoldingAmountCommand::Trx => TokenHoldingAmount(Web3TokenType::Trx), + TokenHoldingAmountCommand::Nfp => TokenHoldingAmount(Web3TokenType::Nfp), + TokenHoldingAmountCommand::Sol => TokenHoldingAmount(Web3TokenType::Sol), + TokenHoldingAmountCommand::Mcrt => TokenHoldingAmount(Web3TokenType::Mcrt), + TokenHoldingAmountCommand::Btc => TokenHoldingAmount(Web3TokenType::Btc), + TokenHoldingAmountCommand::Bean => TokenHoldingAmount(Web3TokenType::Bean), + TokenHoldingAmountCommand::An => TokenHoldingAmount(Web3TokenType::An), + TokenHoldingAmountCommand::Tuna => TokenHoldingAmount(Web3TokenType::Tuna), + }), + Command::PlatformUser(arg) => Ok(match arg { + PlatformUserCommand::KaratDao => PlatformUser(PlatformUserType::KaratDao), + PlatformUserCommand::MagicCraftStaking => + PlatformUser(PlatformUserType::MagicCraftStaking), + PlatformUserCommand::DarenMarket => PlatformUser(PlatformUserType::DarenMarket), + }), + Command::NftHolder(arg) => Ok(match arg { + NftHolderCommand::WeirdoGhostGang => NftHolder(Web3NftType::WeirdoGhostGang), + NftHolderCommand::Club3Sbt => NftHolder(Web3NftType::Club3Sbt), + NftHolderCommand::MFan => NftHolder(Web3NftType::MFan), + NftHolderCommand::Mvp => NftHolder(Web3NftType::Mvp), + }), + Command::Dynamic(arg) => { + let decoded_id = hex::decode(&arg.smart_contract_id.clone()).unwrap(); + let id_bytes: [u8; 20] = decoded_id.try_into().unwrap(); + + let smart_contract_params = match &arg.smart_contract_param { + Some(p) => { + let params = hex::decode(p).unwrap(); + let params_len = params.len(); + let truncated_params = DynamicContractParams::truncate_from(params); + let truncated_params_len = truncated_params.len(); + if params_len > truncated_params_len { + println!( + "The dynamic params length {} is over the maximum value {}", + params_len, truncated_params_len + ); + Err(CliError::Extrinsic { + msg: format!( + "The dynamic params length {} is over the maximum value {}", + params_len, truncated_params_len + ), + }) + } else { + Ok(Some(truncated_params)) + } + }, + None => Ok(None), + }?; + + Ok(Assertion::Dynamic(DynamicParams { + smart_contract_id: H160::from(id_bytes), + smart_contract_params, + return_log: arg.return_log.unwrap_or_default(), + })) + }, + } + } +} diff --git a/tee-worker/cli/src/trusted_base_cli/mod.rs b/tee-worker/cli/src/trusted_base_cli/mod.rs index 0ed0e89ba7..dbeb797146 100644 --- a/tee-worker/cli/src/trusted_base_cli/mod.rs +++ b/tee-worker/cli/src/trusted_base_cli/mod.rs @@ -41,7 +41,7 @@ use substrate_client_keystore::LocalKeystore; use self::commands::litentry::id_graph::IDGraphCommand; -mod commands; +pub mod commands; #[derive(Subcommand)] pub enum TrustedBaseCommand { diff --git a/tee-worker/cli/src/trusted_cli.rs b/tee-worker/cli/src/trusted_cli.rs index 5c1f5d6553..170036341a 100644 --- a/tee-worker/cli/src/trusted_cli.rs +++ b/tee-worker/cli/src/trusted_cli.rs @@ -15,7 +15,10 @@ */ -use crate::{benchmark::BenchmarkCommand, Cli, CliResult}; +use crate::{ + benchmark::{request_vc::BenchmarkRequestVcCommand, stf::BenchmarkStfCommand}, + Cli, CliResult, +}; #[cfg(feature = "evm")] use crate::evm::EvmCommand; @@ -53,14 +56,18 @@ pub enum TrustedCommand { EvmCommands(EvmCommand), /// Run Benchmark - Benchmark(BenchmarkCommand), + BenchmarkStf(BenchmarkStfCommand), + + /// Benchmark direct request vc + BenchmarkRequestVc(BenchmarkRequestVcCommand), } impl TrustedCli { pub(crate) fn run(&self, cli: &Cli) -> CliResult { match &self.command { TrustedCommand::BaseTrusted(cmd) => cmd.run(cli, self), - TrustedCommand::Benchmark(cmd) => cmd.run(cli, self), + TrustedCommand::BenchmarkStf(cmd) => cmd.run(cli, self), + TrustedCommand::BenchmarkRequestVc(cmd) => cmd.run(cli, self), #[cfg(feature = "evm")] TrustedCommand::EvmCommands(cmd) => cmd.run(cli, self), } diff --git a/tee-worker/cli/src/trusted_operation.rs b/tee-worker/cli/src/trusted_operation.rs index 7e081bda8f..3285f72961 100644 --- a/tee-worker/cli/src/trusted_operation.rs +++ b/tee-worker/cli/src/trusted_operation.rs @@ -38,6 +38,7 @@ use itp_types::{ use itp_utils::{FromHexPrefixed, ToHexPrefixed}; use litentry_primitives::{aes_encrypt_default, AesRequest, RequestAesKey}; use log::*; +use sgx_crypto_helper::rsa3072::Rsa3072PubKey; use sp_core::H256; use std::{ fmt::Debug, @@ -365,21 +366,16 @@ fn send_direct_request( } pub(crate) fn send_direct_vc_request( - cli: &Cli, - trusted_args: &TrustedCli, + client: &DirectClient, + shard: ShardIdentifier, + shielding_key: &Rsa3072PubKey, + aes_key: RequestAesKey, top: &TrustedOperation, - key: RequestAesKey, ) -> TrustedOpResult> { - let encryption_key = get_shielding_key(cli).unwrap(); - let shard = read_shard(trusted_args, cli).unwrap(); - let jsonrpc_call: String = get_vc_json_request(shard, top, encryption_key, key); - - debug!("get direct api"); - let direct_api = get_worker_api_direct(cli); - + let jsonrpc_call: String = get_vc_json_request(shard, top, shielding_key, aes_key); debug!("setup sender and receiver"); let (sender, receiver) = channel(); - direct_api.watch(jsonrpc_call, sender); + client.watch(jsonrpc_call, sender); debug!("waiting for rpc response"); let mut req_cnt = 0u8; @@ -409,13 +405,13 @@ pub(crate) fn send_direct_vc_request( debug!("received request result, len: {:?}", len); vec_result.push(value); if req_cnt >= len { - direct_api.close().unwrap(); + client.close().unwrap(); return Ok(vec_result) } } else { // Should never happen. error!("failed to decode RequestVcResultOrError."); - direct_api.close().unwrap(); + client.close().unwrap(); return Err(TrustedOperationError::Default { msg: "[Error] failed to decode RequestVcResultOrError." .to_string(), @@ -425,7 +421,7 @@ pub(crate) fn send_direct_vc_request( _ => { // Should never happen. RpcReturnValue should always have DirectRequestStatus::TrustedOperationStatus. error!("Wrong RpcReturnValue. Should never happen."); - direct_api.close().unwrap(); + client.close().unwrap(); return Err(TrustedOperationError::Default { msg: "[Error] Wrong RpcReturnValue. Should never happen." .to_string(), @@ -436,7 +432,7 @@ pub(crate) fn send_direct_vc_request( }, Err(e) => { error!("failed to receive rpc response: {:?}", e); - direct_api.close().unwrap(); + client.close().unwrap(); return Err(TrustedOperationError::Default { msg: "failed to receive rpc response".to_string(), }) @@ -445,10 +441,22 @@ pub(crate) fn send_direct_vc_request( } } +pub(crate) fn prepare_request_data_and_send_direct_vc_request( + cli: &Cli, + trusted_args: &TrustedCli, + top: &TrustedOperation, + key: RequestAesKey, +) -> TrustedOpResult> { + let encryption_key = get_shielding_key(cli).unwrap(); + let shard = read_shard(trusted_args, cli).unwrap(); + let direct_api = get_worker_api_direct(cli); + send_direct_vc_request(&direct_api, shard, &encryption_key, key, top) +} + pub(crate) fn get_vc_json_request( shard: ShardIdentifier, top: &TrustedOperation, - shielding_pubkey: sgx_crypto_helper::rsa3072::Rsa3072PubKey, + shielding_pubkey: &sgx_crypto_helper::rsa3072::Rsa3072PubKey, key: RequestAesKey, ) -> String { let encrypted_key = shielding_pubkey.encrypt(&key).unwrap();