From 1004fb1fc2acdb09d85919f8be4557ab0fdf0728 Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Fri, 25 Oct 2024 10:27:26 +0200 Subject: [PATCH] charge all stf fees properly, with respect to decimals --- app-libs/stf/src/guess_the_number.rs | 52 +++++++++---------- app-libs/stf/src/lib.rs | 8 ++- app-libs/stf/src/trusted_call.rs | 70 +++++++++++++------------- cli/src/benchmark/mod.rs | 9 ++-- enclave-runtime/src/test/tests_main.rs | 4 +- 5 files changed, 71 insertions(+), 72 deletions(-) diff --git a/app-libs/stf/src/guess_the_number.rs b/app-libs/stf/src/guess_the_number.rs index 14067ace7..bf9aa4dd1 100644 --- a/app-libs/stf/src/guess_the_number.rs +++ b/app-libs/stf/src/guess_the_number.rs @@ -1,25 +1,37 @@ -use crate::helpers::{enclave_signer_account, shielding_target, shielding_target_genesis_hash}; +/* + 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. + +*/ + +// TrustedCalls and Getters for the Guess-The-Number game + +use crate::helpers::shielding_target_genesis_hash; #[cfg(not(feature = "std"))] use alloc::format; use codec::{Decode, Encode}; use frame_support::dispatch::UnfilteredDispatchable; use ita_parentchain_specs::MinimalChainSpec; -use ita_sgx_runtime::{ - GuessTheNumber, GuessType, ParentchainIntegritee, ParentchainTargetA, ParentchainTargetB, - Runtime, System, -}; +use ita_sgx_runtime::{GuessTheNumber, GuessType, Runtime, System}; use itp_node_api::metadata::provider::AccessNodeMetadata; use itp_node_api_metadata::NodeMetadataTrait; use itp_sgx_runtime_primitives::types::{Balance, Moment}; use itp_stf_interface::{ExecuteCall, ExecuteGetter}; use itp_stf_primitives::error::StfError; -use itp_types::{ - parentchain::{ParentchainCall, ParentchainId}, - AccountId, -}; +use itp_types::{parentchain::ParentchainCall, AccountId}; use itp_utils::stringify::account_id_to_string; -use log::{debug, info, trace}; -use sp_runtime::MultiAddress; +use log::*; use sp_std::{sync::Arc, vec::Vec}; /// General public information about the status of the guess-the-number game @@ -73,7 +85,6 @@ where _calls: &mut Vec, _node_metadata_repo: Arc, ) -> Result<(), Self::Error> { - let fee = get_fee_for(&self); match self { Self::set_winnings(sender, winnings) => { // authorization happens in pallet itself, we just pass authentication @@ -106,19 +117,6 @@ where Self::guess(sender, guess) => { let origin = ita_sgx_runtime::RuntimeOrigin::signed(sender); std::println!("⣿STF⣿ guess-the-number: someone is attempting a guess"); - // endow fee to enclave (self) - let fee_recipient: itp_stf_primitives::types::AccountId = enclave_signer_account(); - // fixme: apply fees through standard frame process and tune it - info!("guess fee {}", 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!("GuessTheNumber fee error: {:?}", e.error)) - })?; - ita_sgx_runtime::GuessTheNumberCall::::guess { guess } .dispatch_bypass_filter(origin) .map_err(|e| { @@ -136,10 +134,10 @@ where } } -fn get_fee_for(tc: &GuessTheNumberTrustedCall) -> Balance { +pub fn get_fee_for(tc: &GuessTheNumberTrustedCall) -> Balance { let one = MinimalChainSpec::one_unit(shielding_target_genesis_hash().unwrap_or_default()); match tc { - GuessTheNumberTrustedCall::guess(..) => one / crate::STF_GUESS_FEE_DIVIDER, + GuessTheNumberTrustedCall::guess(..) => one / crate::STF_GUESS_FEE_UNIT_DIVIDER, _ => Balance::from(0u32), } } diff --git a/app-libs/stf/src/lib.rs b/app-libs/stf/src/lib.rs index 847fdb42f..74405d07a 100644 --- a/app-libs/stf/src/lib.rs +++ b/app-libs/stf/src/lib.rs @@ -47,8 +47,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. double-check decimals for target chain -// as long as it is hard-coded, needs to be reasonable for 10 (Paseo) and 12 decimals -pub const STF_TX_FEE: Balance = 100_000_000; -pub const STF_GUESS_FEE_DIVIDER: Balance = 10; +pub const STF_SHIELDING_FEE_AMOUNT_DIVIDER: Balance = 571; // approx 0.175% +pub const STF_TX_FEE_UNIT_DIVIDER: Balance = 100; // 0.01 tokens +pub const STF_GUESS_FEE_UNIT_DIVIDER: Balance = 10; // 0.1 tokens diff --git a/app-libs/stf/src/trusted_call.rs b/app-libs/stf/src/trusted_call.rs index f6c58f394..6cf15d804 100644 --- a/app-libs/stf/src/trusted_call.rs +++ b/app-libs/stf/src/trusted_call.rs @@ -25,11 +25,15 @@ use std::vec::Vec; use crate::evm_helpers::{create_code_hash, evm_create2_address, evm_create_address}; use crate::{ guess_the_number::GuessTheNumberTrustedCall, - helpers::{enclave_signer_account, ensure_enclave_signer_account, shard_vault, wrap_bytes}, - Getter, + helpers::{ + enclave_signer_account, ensure_enclave_signer_account, shard_vault, + shielding_target_genesis_hash, wrap_bytes, + }, + Getter, STF_SHIELDING_FEE_AMOUNT_DIVIDER, }; use codec::{Compact, Decode, Encode}; use frame_support::{ensure, traits::UnfilteredDispatchable}; +use ita_parentchain_specs::MinimalChainSpec; #[cfg(feature = "evm")] use ita_sgx_runtime::{AddressMapping, HashedAddressMapping}; pub use ita_sgx_runtime::{Balance, Index}; @@ -244,6 +248,10 @@ where let system_nonce = System::account_nonce(&sender); ensure!(self.nonce == system_nonce, Self::Error::InvalidNonce(self.nonce, system_nonce)); + // try to charge fee first and fail early + let fee = get_fee_for(&self); + charge_fee(fee, &sender)?; + // increment the nonce, no matter if the call succeeds or fails. // The call must have entered the transaction pool already, // so it should be considered as valid @@ -283,25 +291,6 @@ where TrustedCall::balance_transfer(from, to, value) => { let origin = ita_sgx_runtime::RuntimeOrigin::signed(from.clone()); 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, - 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, @@ -318,11 +307,6 @@ where 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), @@ -332,15 +316,6 @@ where shard ); - 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, parentchain_id) = shard_vault().ok_or_else(|| { @@ -593,6 +568,29 @@ where } } +fn get_fee_for(tc: &TrustedCallSigned) -> Balance { + let one = MinimalChainSpec::one_unit(shielding_target_genesis_hash().unwrap_or_default()); + match &tc.call { + TrustedCall::balance_transfer(..) => one / crate::STF_TX_FEE_UNIT_DIVIDER, + TrustedCall::balance_unshield(..) => one / crate::STF_TX_FEE_UNIT_DIVIDER * 3, + TrustedCall::guess_the_number(call) => crate::guess_the_number::get_fee_for(&call), + _ => Balance::from(0u32), + } +} + +fn charge_fee(fee: Balance, payer: &AccountId) -> Result<(), StfError> { + debug!("attempting to charge fee for TrustedCall"); + let fee_recipient: AccountId = enclave_signer_account(); + let origin = ita_sgx_runtime::RuntimeOrigin::signed(payer.clone()); + ita_sgx_runtime::BalancesCall::::transfer { + dest: MultiAddress::Id(fee_recipient), + value: fee, + } + .dispatch_bypass_filter(origin) + .map_err(|e| StfError::Dispatch(format!("Fee Payment Error: {:?}", e.error)))?; + Ok(()) +} + fn burn_funds(account: AccountId, amount: u128) -> Result<(), StfError> { let account_info = System::account(&account); if account_info.data.free < amount { @@ -610,7 +608,7 @@ fn burn_funds(account: AccountId, amount: u128) -> Result<(), StfError> { 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% + let fee = amount / STF_SHIELDING_FEE_AMOUNT_DIVIDER; // endow fee to enclave (self) let fee_recipient: AccountId = enclave_signer_account(); diff --git a/cli/src/benchmark/mod.rs b/cli/src/benchmark/mod.rs index 550bc18cc..d514f35a6 100644 --- a/cli/src/benchmark/mod.rs +++ b/cli/src/benchmark/mod.rs @@ -25,7 +25,9 @@ use crate::{ }; use codec::Decode; use hdrhistogram::Histogram; -use ita_stf::{Getter, Index, TrustedCall, TrustedCallSigned, TrustedGetter, STF_TX_FEE}; +use ita_stf::{ + Getter, Index, TrustedCall, TrustedCallSigned, TrustedGetter, STF_TX_FEE_UNIT_DIVIDER, +}; use itc_rpc_client::direct_client::{DirectApi, DirectClient}; use itp_stf_primitives::{ traits::TrustedCallSigning, @@ -136,7 +138,8 @@ 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); + let initial_balance = (self.number_iterations + 1) + * (1_000_000_000_000 / STF_TX_FEE_UNIT_DIVIDER + EXISTENTIAL_DEPOSIT); // Setup new accounts and initialize them with money from Alice. for i in 0..self.number_clients { let nonce = i + nonce_start; @@ -230,7 +233,7 @@ impl BenchmarkCommand { output.push(result); // FIXME: We probably should re-fund the account in this case. - if client.current_balance <= EXISTENTIAL_DEPOSIT + STF_TX_FEE { + if client.current_balance <= 1_000_000_000_000 / STF_TX_FEE_UNIT_DIVIDER + EXISTENTIAL_DEPOSIT { error!("Account {:?} does not have enough balance anymore. Finishing benchmark early", client.account.public()); break; } diff --git a/enclave-runtime/src/test/tests_main.rs b/enclave-runtime/src/test/tests_main.rs index 6e737d8c5..dc3047ce1 100644 --- a/enclave-runtime/src/test/tests_main.rs +++ b/enclave-runtime/src/test/tests_main.rs @@ -428,7 +428,9 @@ fn test_create_state_diff() { 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 + ita_stf::test_genesis::ENDOWED_ACC_FUNDS + - TX_AMOUNT + - 1_000_000_000_000 / ita_stf::STF_TX_FEE_UNIT_DIVIDER ); }