Skip to content

Commit

Permalink
adjust fee to decimals by genesis and properly charge it before bumpi…
Browse files Browse the repository at this point in the history
…ng nonce (#1622)

* adjust guess fee to decimals

* charge all stf fees properly, with respect to decimals

* clippy&taplo

* add missing new lib

* fmt

* double fee tolerance because fees went up

* fix dirct call test by increasing amounts

* iprovements of direct call test

* fix doeble dep on log
  • Loading branch information
brenzi authored Oct 26, 2024
1 parent ff397d5 commit 036e859
Show file tree
Hide file tree
Showing 20 changed files with 199 additions and 78 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2794,6 +2794,15 @@ dependencies = [
"substrate-api-client",
]

[[package]]
name = "ita-parentchain-specs"
version = "0.1.0"
dependencies = [
"hex",
"itp-types",
"log 0.4.20",
]

[[package]]
name = "ita-sgx-runtime"
version = "0.9.0"
Expand Down Expand Up @@ -2826,6 +2835,7 @@ dependencies = [
"base58",
"frame-support",
"frame-system",
"ita-parentchain-specs",
"ita-sgx-runtime",
"itp-hashing",
"itp-node-api",
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"app-libs/oracle",
"app-libs/parentchain-interface",
"app-libs/parentchain-specs",
"app-libs/sgx-runtime",
"app-libs/sgx-runtime/pallets/parentchain",
"app-libs/sgx-runtime/pallets/guess-the-number",
Expand Down
17 changes: 17 additions & 0 deletions app-libs/parentchain-specs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "ita-parentchain-specs"
version = "0.1.0"
authors = ["Integritee AG <[email protected]>"]
edition = "2021"

[dependencies]
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
itp-types = { path = "../../core-primitives/types", default-features = false }
log = { version = "0.4", default-features = false }

[features]
default = ["std"]
std = [
"hex/std",
"log/std",
]
56 changes: 56 additions & 0 deletions app-libs/parentchain-specs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
Copyright 2021 Integritee AG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// chain specs which can't be derived from chain state trustlessly by the light client
// we hardcode them here so they can't be changed by an adversarial enclave operator

#![cfg_attr(all(not(target_env = "sgx"), not(feature = "std")), no_std)]
#![cfg_attr(target_env = "sgx", feature(rustc_private))]
use itp_types::parentchain::{Balance, Hash};
use log::warn;

const PASEO_RELAY_GENESIS_HASH_HEX: &str =
"77afd6190f1554ad45fd0d31aee62aacc33c6db0ea801129acb813f913e0764f";
const INTEGRITEE_PASEO_GENESIS_HASH_HEX: &str =
"1b69c462cd7dfea0e855c2008b66490cc8bbe90bc80b297ec0896a1c0941ce15";
const INTEGRITEE_KUSAMA_GENESIS_HASH_HEX: &str =
"cdedc8eadbfa209d3f207bba541e57c3c58a667b05a2e1d1e86353c9000758da";

/// modify this for testing if necessary
const LOCAL_TEST_GENESIS_HASH_HEX: &str =
"6ca6d29ad6c4a200c4af356f74f03d6467dbc8a6e9ef225a2e672a990e1c7ead";
pub struct MinimalChainSpec {}

impl MinimalChainSpec {
pub fn decimals(genesis_hash: Hash) -> u8 {
let genesis_hash_hex = hex::encode(genesis_hash);
match genesis_hash_hex.as_ref() {
PASEO_RELAY_GENESIS_HASH_HEX => 10,
INTEGRITEE_PASEO_GENESIS_HASH_HEX | INTEGRITEE_KUSAMA_GENESIS_HASH_HEX => 12,
LOCAL_TEST_GENESIS_HASH_HEX => 10,
_ => {
warn!(
"parentchain spec for genesis {} unknown. defaulting to 12 decimals",
genesis_hash_hex
);
12
},
}
}
pub fn one_unit(genesis_hash: Hash) -> Balance {
10u128.pow(Self::decimals(genesis_hash) as u32)
}
}
2 changes: 2 additions & 0 deletions app-libs/stf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ sha3 = { version = "0.10", default-features = false }
sgx_tstd = { branch = "master", features = ["untrusted_fs", "net", "backtrace"], git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true }

# local crates
ita-parentchain-specs = { default-features = false, path = "../parentchain-specs" }
ita-sgx-runtime = { default-features = false, path = "../sgx-runtime" }
itp-hashing = { default-features = false, path = "../../core-primitives/hashing" }
itp-node-api = { default-features = false, path = "../../core-primitives/node-api" }
Expand Down Expand Up @@ -61,6 +62,7 @@ std = [
"rlp/std",
# local
"ita-sgx-runtime/std",
"ita-parentchain-specs/std",
"itp-hashing/std",
"itp-sgx-externalities/std",
"itp-stf-interface/std",
Expand Down
6 changes: 2 additions & 4 deletions app-libs/stf/src/getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use crate::evm_helpers::{get_evm_account, get_evm_account_codes, get_evm_account

use crate::{
guess_the_number::{GuessTheNumberPublicGetter, GuessTheNumberTrustedGetter},
helpers::{shard_vault, wrap_bytes},
helpers::{shielding_target, wrap_bytes},
};
use itp_sgx_runtime_primitives::types::Moment;
use itp_stf_primitives::traits::PoolTransactionValidation;
Expand Down Expand Up @@ -272,9 +272,7 @@ impl ExecuteGetter for PublicGetter {
integritee,
target_a,
target_b,
shielding_target: shard_vault()
.map(|v| v.1)
.unwrap_or(ParentchainId::Integritee),
shielding_target: shielding_target(),
};
Some(parentchains_info.encode())
},
Expand Down
47 changes: 30 additions & 17 deletions app-libs/stf/src/guess_the_number.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
use crate::helpers::enclave_signer_account;
/*
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, Runtime, System};
use itp_node_api::metadata::provider::AccessNodeMetadata;
use itp_node_api_metadata::NodeMetadataTrait;
Expand All @@ -11,8 +31,7 @@ use itp_stf_interface::{ExecuteCall, ExecuteGetter};
use itp_stf_primitives::error::StfError;
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
Expand Down Expand Up @@ -98,20 +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
let fee = crate::STF_GUESS_FEE;
info!("guess fee {}", fee);
ita_sgx_runtime::BalancesCall::<Runtime>::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::<Runtime>::guess { guess }
.dispatch_bypass_filter(origin)
.map_err(|e| {
Expand All @@ -129,6 +134,14 @@ where
}
}

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_UNIT_DIVIDER,
_ => Balance::from(0u32),
}
}

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
#[allow(non_camel_case_types)]
pub enum GuessTheNumberPublicGetter {
Expand Down
16 changes: 15 additions & 1 deletion app-libs/stf/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use itp_stf_primitives::{
types::AccountId,
};
use itp_storage::{storage_double_map_key, storage_map_key, storage_value_key, StorageHasher};
use itp_types::parentchain::ParentchainId;
use itp_types::parentchain::{Hash, ParentchainId};
use itp_utils::stringify::account_id_to_string;
use log::*;
use std::prelude::v1::*;
Expand Down Expand Up @@ -116,6 +116,20 @@ pub fn shard_vault() -> Option<(AccountId, ParentchainId)> {
get_shard_vaults().into_iter().next()
}

/// get shielding target from parentchain pallets
pub fn shielding_target() -> ParentchainId {
shard_vault().map(|v| v.1).unwrap_or(ParentchainId::Integritee)
}

/// get genesis hash of shielding target parentchain, if available
pub fn shielding_target_genesis_hash() -> Option<Hash> {
match shielding_target() {
ParentchainId::Integritee => ParentchainIntegritee::parentchain_genesis_hash(),
ParentchainId::TargetA => ParentchainTargetA::parentchain_genesis_hash(),
ParentchainId::TargetB => ParentchainTargetB::parentchain_genesis_hash(),
}
}

/// We assume it has been ensured elsewhere that there can't be multiple shard vaults on multiple parentchains
pub fn get_shard_vaults() -> Vec<(AccountId, ParentchainId)> {
[
Expand Down
8 changes: 3 additions & 5 deletions app-libs/stf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: Balance = 10_000_000_000;
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
72 changes: 35 additions & 37 deletions app-libs/stf/src/trusted_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -281,27 +289,8 @@ where
Ok::<(), Self::Error>(())
},
TrustedCall::balance_transfer(from, to, value) => {
let origin = ita_sgx_runtime::RuntimeOrigin::signed(from.clone());
let origin = ita_sgx_runtime::RuntimeOrigin::signed(from);
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::<Runtime>::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::<Runtime>::transfer {
dest: MultiAddress::Id(to),
value,
Expand All @@ -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),
Expand All @@ -332,15 +316,6 @@ where
shard
);

let origin = ita_sgx_runtime::RuntimeOrigin::signed(account_incognito.clone());
ita_sgx_runtime::BalancesCall::<Runtime>::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(|| {
Expand Down Expand Up @@ -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::<Runtime>::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 {
Expand All @@ -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();
Expand Down
Loading

0 comments on commit 036e859

Please sign in to comment.