diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 2a79d8546f..9e631e18c9 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -7448,6 +7448,7 @@ dependencies = [ "pallet-evm", "pallet-parachain-staking", "pallet-score-staking", + "pallet-teebag", "pallet-timestamp", "parity-scale-codec", "precompile-utils", @@ -7941,6 +7942,8 @@ dependencies = [ "num-integer", "pallet-balances", "pallet-parachain-staking", + "pallet-teebag", + "pallet-timestamp", "parity-scale-codec", "scale-info", "serde", diff --git a/parachain/pallets/score-staking/Cargo.toml b/parachain/pallets/score-staking/Cargo.toml index a4869ecd19..f6c91f9a8d 100644 --- a/parachain/pallets/score-staking/Cargo.toml +++ b/parachain/pallets/score-staking/Cargo.toml @@ -13,12 +13,14 @@ serde = { workspace = true } frame-benchmarking = { workspace = true, optional = true } frame-support = { workspace = true } frame-system = { workspace = true } +pallet-timestamp = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } core-primitives = { workspace = true } pallet-parachain-staking = { workspace = true } +pallet-teebag = { workspace = true } [dev-dependencies] sp-io = { workspace = true } @@ -42,12 +44,15 @@ std = [ "pallet-balances/std", "core-primitives/std", "pallet-parachain-staking/std", + "pallet-teebag/std", + "pallet-timestamp/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", diff --git a/parachain/pallets/score-staking/src/lib.rs b/parachain/pallets/score-staking/src/lib.rs index 9d8b09aa7b..52c92af750 100644 --- a/parachain/pallets/score-staking/src/lib.rs +++ b/parachain/pallets/score-staking/src/lib.rs @@ -74,7 +74,6 @@ pub mod pallet { use core_primitives::Identity; use frame_system::pallet_prelude::*; - use sp_runtime::traits::Zero; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -114,6 +113,8 @@ pub mod pallet { type AdminOrigin: EnsureOrigin; /// AccountId converter type AccountIdConvert: AccountIdConvert; + // For extrinsics that should only be called by origins from TEE + type TEECallOrigin: EnsureOrigin; } #[pallet::error] @@ -150,20 +151,50 @@ pub mod pallet { ScoreUserCountUnderflow, // when the score user count would exceed `MaxScoreUserCount` MaxScoreUserCountReached, + // when the token staking amount has been updated already for the round + TotalStakingAmountAlreadyUpdated, + // the rewards have been distributed for the round + RoundRewardsAlreadyDistributed, } #[pallet::event] #[pallet::generate_deposit(pub (crate) fn deposit_event)] pub enum Event { - PoolStarted { start_block: BlockNumberFor }, + PoolStarted { + start_block: BlockNumberFor, + }, PoolStopped {}, - ScoreFeederSet { new_score_feeder: Option }, - RoundConfigSet { new_config: RoundSetting }, - ScoreUpdated { who: Identity, new_score: Score }, - ScoreRemoved { who: Identity }, + ScoreFeederSet { + new_score_feeder: Option, + }, + RoundConfigSet { + new_config: RoundSetting, + }, + ScoreUpdated { + who: Identity, + new_score: Score, + }, + ScoreRemoved { + who: Identity, + }, ScoreCleared {}, - RewardCalculated { total: BalanceOf, distributed: BalanceOf }, - RewardClaimed { who: T::AccountId, amount: BalanceOf }, + RewardDistributionStarted { + round_index: RoundIndex, + total_stake: BalanceOf, + total_score: Score, + }, + RewardDistributed { + who: T::AccountId, + amount: BalanceOf, + round_index: RoundIndex, + }, + RewardDistributionCompleted { + round_index: RoundIndex, + }, + RewardClaimed { + who: T::AccountId, + amount: BalanceOf, + }, } #[pallet::storage] @@ -226,14 +257,14 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(now: BlockNumberFor) -> Weight { - let mut weight = T::DbWeight::get().reads_writes(1, 0); // Self::state() + let mut weight = T::DbWeight::get().reads(1); // Self::state() if Self::state() == PoolState::Stopped { return weight; } let mut r = Round::::get(); - weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 0)); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); if !is_modulo(now - r.start_block, Self::round_config().interval.into()) { // nothing to do there @@ -241,47 +272,21 @@ pub mod pallet { } // We are about to start a new round - // 1. update round info - r.index = r.index.saturating_add(1); + // update round info + let round_index = r.index.saturating_add(1); + r.index = round_index; r.start_block = now; Round::::put(r); weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - // 2. calculate payout - let round_reward: BalanceOf = (T::YearlyInflation::get() * T::YearlyIssuance::get() - / YEARS.into()) * Self::round_config().interval.into(); - let round_reward_u128 = round_reward.saturated_into::(); - let total_stake_u128 = ParaStaking::Pallet::::total().saturated_into::(); let total_score = Self::total_score(); - let n = Self::round_config().stake_coef_n; - let m = Self::round_config().stake_coef_m; - - let mut all_user_reward = BalanceOf::::zero(); - - for (a, mut p) in Scores::::iter() { - let user_stake_u128 = ParaStaking::Pallet::::delegator_state(&a) - .map(|s| s.total) - .unwrap_or_default() - .saturated_into::(); - let user_reward_u128 = round_reward_u128 - .saturating_mul(p.score.into()) - .saturating_div(total_score.into()) - .saturating_mul(num_integer::Roots::nth_root(&user_stake_u128.pow(n), m)) - .saturating_div(num_integer::Roots::nth_root(&total_stake_u128.pow(n), m)); - let user_reward = user_reward_u128.saturated_into::>(); - - p.last_round_reward = user_reward; - p.total_reward += user_reward; - p.unpaid_reward += user_reward; - all_user_reward += user_reward; - Scores::::insert(&a, p); - weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); - } + weight = weight.saturating_add(T::DbWeight::get().reads(2)); - Self::deposit_event(Event::::RewardCalculated { - total: round_reward, - distributed: all_user_reward, + Self::deposit_event(Event::::RewardDistributionStarted { + round_index, + total_stake: total_stake_u128.saturated_into::>(), + total_score, }); weight @@ -445,6 +450,72 @@ pub mod pallet { let payment = Scores::::get(&account).ok_or(Error::::UserNotExist)?; Self::claim(origin, payment.unpaid_reward) } + + #[pallet::call_index(9)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn distribute_rewards( + origin: OriginFor, + account_id: T::AccountId, + user_stake: BalanceOf, + round_index: RoundIndex, + total_stake: BalanceOf, + total_score: Score, + ) -> DispatchResultWithPostInfo { + let _ = T::TEECallOrigin::ensure_origin(origin)?; + + match Scores::::get(&account_id) { + Some(mut s) => { + if round_index <= s.last_token_distribution_round { + return Err(Error::::RoundRewardsAlreadyDistributed.into()); + } + let round_reward: BalanceOf = + (T::YearlyInflation::get() * T::YearlyIssuance::get() / YEARS.into()) + * Self::round_config().interval.into(); + let round_reward_u128 = round_reward.saturated_into::(); + + let n = Self::round_config().stake_coef_n; + let m = Self::round_config().stake_coef_m; + + let total_stake_u128 = total_stake.saturated_into::(); + let user_stake_u128 = user_stake.saturated_into::(); + + let user_reward_u128 = round_reward_u128 + .saturating_mul(s.score.into()) + .saturating_div(total_score.into()) + .saturating_mul(num_integer::Roots::nth_root(&user_stake_u128.pow(n), m)) + .saturating_div(num_integer::Roots::nth_root(&total_stake_u128.pow(n), m)); + let user_reward = user_reward_u128.saturated_into::>(); + + s.last_round_reward = user_reward; + s.total_reward += user_reward; + s.unpaid_reward += user_reward; + s.last_token_distribution_round = round_index; + Scores::::insert(&account_id, s); + + Self::deposit_event(Event::RewardDistributed { + who: account_id, + amount: user_reward, + round_index, + }); + + Ok(Pays::No.into()) + }, + None => Err(Error::::UserNotExist.into()), + } + } + + #[pallet::call_index(10)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn complete_rewards_distribution( + origin: OriginFor, + round_index: RoundIndex, + ) -> DispatchResultWithPostInfo { + let _ = T::TEECallOrigin::ensure_origin(origin)?; + + Self::deposit_event(Event::RewardDistributionCompleted { round_index }); + + Ok(Pays::No.into()) + } } } diff --git a/parachain/pallets/score-staking/src/mock.rs b/parachain/pallets/score-staking/src/mock.rs index 2463ac0540..7e815d464a 100644 --- a/parachain/pallets/score-staking/src/mock.rs +++ b/parachain/pallets/score-staking/src/mock.rs @@ -18,12 +18,15 @@ use crate::{ self as pallet_score_staking, AccountIdConvert, Config, Perbill, PoolState, RoundSetting, }; +use core::marker::PhantomData; use frame_support::{ - assert_ok, construct_runtime, ord_parameter_types, parameter_types, + assert_ok, construct_runtime, ord_parameter_types, + pallet_prelude::EnsureOrigin, + parameter_types, traits::{OnFinalize, OnInitialize}, }; use frame_system::{EnsureRoot, EnsureSignedBy}; -use sp_core::{ConstU128, ConstU32, H256}; +use sp_core::{ConstU128, ConstU16, ConstU32, H256}; use sp_keyring::AccountKeyring; use sp_runtime::{ generic, @@ -51,6 +54,7 @@ construct_runtime!( Balances: pallet_balances, ParachainStaking: pallet_parachain_staking, ScoreStaking: pallet_score_staking, + Teebag: pallet_teebag, } ); @@ -166,6 +170,66 @@ impl pallet_score_staking::Config for Test { type YearlyIssuance = ConstU128<{ 100_000_000 * UNIT }>; type YearlyInflation = DefaultYearlyInflation; type MaxScoreUserCount = ConstU32<2>; + type TEECallOrigin = EnsureEnclaveSigner; +} + +parameter_types! { + pub const MinimumPeriod: u64 = 6000 / 2; +} + +pub type Moment = u64; + +impl pallet_timestamp::Config for Test { + type Moment = Moment; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +parameter_types! { + pub const MomentsPerDay: u64 = 86_400_000; // [ms/d] +} + +impl pallet_teebag::Config for Test { + type RuntimeEvent = RuntimeEvent; + type MomentsPerDay = MomentsPerDay; + type SetAdminOrigin = EnsureRoot; + type MaxEnclaveIdentifier = ConstU32<1>; + type MaxAuthorizedEnclave = ConstU32<2>; + type WeightInfo = (); +} + +pub struct EnsureEnclaveSigner(PhantomData); +impl EnsureOrigin for EnsureEnclaveSigner +where + T: frame_system::Config + pallet_teebag::Config + pallet_timestamp::Config, + ::AccountId: From<[u8; 32]>, + ::Hash: From<[u8; 32]>, +{ + type Success = T::AccountId; + fn try_origin(o: T::RuntimeOrigin) -> Result { + o.into().and_then(|o| match o { + frame_system::RawOrigin::Signed(who) + if pallet_teebag::EnclaveRegistry::::contains_key(&who) => + { + Ok(who) + }, + r => Err(T::RuntimeOrigin::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + use pallet_teebag::test_util::{get_signer, TEST8_MRENCLAVE, TEST8_SIGNER_PUB}; + let signer: ::AccountId = get_signer(TEST8_SIGNER_PUB); + if !pallet_teebag::EnclaveRegistry::::contains_key(signer.clone()) { + assert_ok!(pallet_teebag::Pallet::::add_enclave( + &signer, + &pallet_teebag::Enclave::default().with_mrenclave(TEST8_MRENCLAVE), + )); + } + Ok(frame_system::RawOrigin::Signed(signer).into()) + } } pub fn alice() -> AccountId { @@ -186,6 +250,14 @@ pub fn new_test_ext(fast_round: bool) -> sp_io::TestExternalities { .assimilate_storage(&mut t) .unwrap(); + pallet_teebag::GenesisConfig:: { + allow_sgx_debug_mode: true, + admin: Some(AccountKeyring::Alice.to_account_id()), + mode: pallet_teebag::OperationalMode::Production, + } + .assimilate_storage(&mut t) + .unwrap(); + pallet_score_staking::GenesisConfig:: { state: PoolState::Stopped, marker: Default::default(), diff --git a/parachain/pallets/score-staking/src/tests.rs b/parachain/pallets/score-staking/src/tests.rs index 77b87b4dcc..2e31c00c96 100644 --- a/parachain/pallets/score-staking/src/tests.rs +++ b/parachain/pallets/score-staking/src/tests.rs @@ -18,9 +18,11 @@ use crate::{mock::*, Error, Event, PoolState, RoundInfo, RoundSetting, ScorePayment, Scores}; use core_primitives::{Identity, DAYS, YEARS}; -use frame_support::{assert_err, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok}; use pallet_parachain_staking::{Delegator, OnAllDelegationRemoved}; +use pallet_teebag::{Enclave, WorkerType}; use sp_runtime::Perbill; +use sp_std::vec; fn round_reward() -> Balance { (Perbill::from_perthousand(5) * 100_000_000 * UNIT / (YEARS as u128)) * 5 @@ -127,10 +129,13 @@ fn default_mint_works() { // run to next reward distribution round run_to_block(7); - System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { - total: round_reward(), - distributed: 0, - })); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 2, + total_stake: 0, + total_score: 0, + }, + )); }); } @@ -152,121 +157,288 @@ fn score_update_checks_staking() { #[allow(clippy::identity_op)] fn score_staking_works() { new_test_ext_with_parachain_staking().execute_with(|| { + let enclave = Enclave::new(WorkerType::Identity); + pallet_teebag::EnclaveRegistry::::insert(alice(), enclave); + run_to_block(2); assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + let alice_staking = 900; + let mut alice_score = 500; + run_to_block(3); pallet_parachain_staking::DelegatorState::::insert( alice(), - Delegator::new(bob(), bob(), 900), + Delegator::new(bob(), bob(), alice_staking), ); - pallet_parachain_staking::Total::::put(900); + pallet_parachain_staking::Total::::put(alice_staking); - assert_ok!(ScoreStaking::update_score(RuntimeOrigin::signed(alice()), alice().into(), 500)); + assert_ok!(ScoreStaking::update_score( + RuntimeOrigin::signed(alice()), + alice().into(), + alice_score + )); assert_eq!( ScoreStaking::scores(alice()).unwrap(), - ScorePayment { score: 500, total_reward: 0, last_round_reward: 0, unpaid_reward: 0 } + ScorePayment { + score: alice_score, + total_reward: 0, + last_round_reward: 0, + unpaid_reward: 0, + last_token_distribution_round: 0, + } ); - assert_eq!(ScoreStaking::total_score(), 500); + + assert_eq!(ScoreStaking::total_score(), alice_score); assert_eq!(ScoreStaking::score_user_count(), 1); + alice_score = 2000; + assert_ok!(ScoreStaking::update_score( RuntimeOrigin::signed(alice()), alice().into(), - 2000 + alice_score )); - assert_eq!(ScoreStaking::scores(alice()).unwrap().score, 2000); - assert_eq!(ScoreStaking::total_score(), 2000); + assert_eq!(ScoreStaking::scores(alice()).unwrap().score, alice_score); + assert_eq!(ScoreStaking::total_score(), alice_score); assert_eq!(ScoreStaking::score_user_count(), 1); // run to next reward distribution round, alice should win all rewards run_to_block(7); - System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { - total: round_reward(), - distributed: round_reward(), + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 2, + total_stake: alice_staking, + total_score: alice_score, + }, + )); + // total reward first distribution + let mut alice_total_reward = 0; + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + let round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + alice_total_reward += round_reward; + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 2, + total_staking, + total_score + )); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward, + round_index: 2, })); - // total reward round 1 - let mut alice_total_reward = round_reward(); + assert_eq!( ScoreStaking::scores(alice()).unwrap(), ScorePayment { - score: 2000, + score: alice_score, total_reward: alice_total_reward, - last_round_reward: alice_total_reward, + last_round_reward: round_reward, unpaid_reward: alice_total_reward, + last_token_distribution_round: 2, } ); // alice's winning should accumulate run_to_block(12); - // total reward round 2 - alice_total_reward += round_reward(); + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 3, + total_stake: total_staking, + total_score, + }, + )); + // total reward second distribution + let round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + alice_total_reward += round_reward; - System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { - total: round_reward(), - distributed: round_reward(), + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 3, + total_staking, + total_score + )); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward, + round_index: 3, })); + assert_eq!( ScoreStaking::scores(alice()).unwrap(), ScorePayment { - score: 2000, + score: alice_score, total_reward: alice_total_reward, - last_round_reward: round_reward(), + last_round_reward: round_reward, unpaid_reward: alice_total_reward, + last_token_distribution_round: 3, } ); + let other_staking = 1000; + // increase the total staked amount, alice should win less run_to_block(13); - pallet_parachain_staking::Total::::put(1600); + pallet_parachain_staking::Total::::put(alice_staking + other_staking); run_to_block(17); - // total reward round 3 - alice_total_reward += calculate_round_reward(2000, 2000, 900, 1600); + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 4, + total_stake: total_staking, + total_score, + }, + )); - System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { - total: round_reward(), - distributed: calculate_round_reward(2000, 2000, 900, 1600), + let round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 4, + total_staking, + total_score + )); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward, + round_index: 4, })); + + // total reward third distribution + alice_total_reward += round_reward; + assert_eq!( ScoreStaking::scores(alice()).unwrap(), ScorePayment { - score: 2000, + score: alice_score, total_reward: alice_total_reward, - last_round_reward: calculate_round_reward(2000, 2000, 900, 1600), + last_round_reward: round_reward, unpaid_reward: alice_total_reward, + last_token_distribution_round: 4, } ); - // add bob's score run_to_block(18); - assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(bob()), alice(), 1600)); - assert_eq!(pallet_parachain_staking::Total::::get(), 3200); - assert_ok!(ScoreStaking::update_score(RuntimeOrigin::signed(alice()), bob().into(), 1000)); - assert_eq!(ScoreStaking::total_score(), 3000); + + // add bob's score + let mut bob_staking = 1600; + let mut bob_score = 1000; + + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(bob()), alice(), bob_staking)); + assert_eq!( + pallet_parachain_staking::Total::::get(), + alice_staking + bob_staking + other_staking + ); + assert_ok!(ScoreStaking::update_score( + RuntimeOrigin::signed(alice()), + bob().into(), + bob_score + )); + assert_eq!(ScoreStaking::total_score(), alice_score + bob_score); assert_eq!(ScoreStaking::score_user_count(), 2); run_to_block(22); - // total rewards round 4 - alice_total_reward += calculate_round_reward(2000, 3000, 900, 3200); - let mut bob_total_reward = calculate_round_reward(1000, 3000, 1600, 3200); + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 5, + total_stake: total_staking, + total_score, + }, + )); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 5, + total_staking, + total_score + )); + let alice_round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: alice_round_reward, + round_index: 5, + })); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + bob(), + bob_staking, + 5, + total_staking, + total_score + )); + let bob_round_reward = calculate_round_reward( + bob_score.into(), + total_score.into(), + bob_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: bob(), + amount: bob_round_reward, + round_index: 5, + })); + + alice_total_reward += alice_round_reward; + let mut bob_total_reward = 0; + bob_total_reward += bob_round_reward; assert_eq!( ScoreStaking::scores(alice()).unwrap(), ScorePayment { - score: 2000, + score: alice_score, total_reward: alice_total_reward, - last_round_reward: calculate_round_reward(2000, 3000, 900, 3200), + last_round_reward: alice_round_reward, unpaid_reward: alice_total_reward, + last_token_distribution_round: 5, } ); assert_eq!( ScoreStaking::scores(bob()).unwrap(), ScorePayment { - score: 1000, + score: bob_score, total_reward: bob_total_reward, - last_round_reward: bob_total_reward, + last_round_reward: bob_round_reward, unpaid_reward: bob_total_reward, + last_token_distribution_round: 5, } ); @@ -287,10 +459,82 @@ fn score_staking_works() { alice() )); - run_to_block(25); - // total rewards round 5 - alice_total_reward += calculate_round_reward(2000, 3000, 900, 3200); - bob_total_reward += calculate_round_reward(1000, 3000, 1600, 3200); + run_to_block(27); + + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 6, + total_stake: total_staking, + total_score, + }, + )); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 6, + total_staking, + total_score + )); + let alice_round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: alice_round_reward, + round_index: 6, + })); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + bob(), + bob_staking, + 6, + total_staking, + total_score + )); + let bob_round_reward = calculate_round_reward( + bob_score.into(), + total_score.into(), + bob_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: bob(), + amount: bob_round_reward, + round_index: 6, + })); + + // total rewards fifth distribution + alice_total_reward += alice_round_reward; + bob_total_reward += bob_round_reward; + + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: alice_score, + total_reward: alice_total_reward, + last_round_reward: alice_round_reward, + unpaid_reward: alice_total_reward, + last_token_distribution_round: 6, + } + ); + assert_eq!( + ScoreStaking::scores(bob()).unwrap(), + ScorePayment { + score: bob_score, + total_reward: bob_total_reward, + last_round_reward: bob_round_reward, + unpaid_reward: bob_total_reward, + last_token_distribution_round: 6, + } + ); run_to_block(30); assert_ok!(ParachainStaking::execute_delegation_request( @@ -298,27 +542,144 @@ fn score_staking_works() { bob(), alice() )); + bob_staking = 0; + bob_score = 0; - run_to_block(31); - // total reward round 6 - alice_total_reward += calculate_round_reward(2000, 2000, 900, 900); + run_to_block(33); - // remove increased stake (keep only alice's stake) - pallet_parachain_staking::Total::::put(900); + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 7, + total_stake: total_staking, + total_score, + }, + )); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 7, + total_staking, + total_score + )); + let alice_round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward, + round_index: 7, + })); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + bob(), + bob_staking, + 7, + total_staking, + total_score + )); + let bob_round_reward = calculate_round_reward( + bob_score.into(), + total_score.into(), + bob_staking, + total_staking, + ); - run_to_block(32); + // total reward sixth distribution + alice_total_reward += alice_round_reward; + bob_total_reward += bob_round_reward; - // alice should get all rewards assert_eq!( ScoreStaking::scores(alice()).unwrap(), ScorePayment { - score: 2000, + score: alice_score, total_reward: alice_total_reward, - last_round_reward: round_reward(), + last_round_reward: alice_round_reward, unpaid_reward: alice_total_reward, + last_token_distribution_round: 7, + } + ); + assert_eq!( + ScoreStaking::scores(bob()).unwrap(), + ScorePayment { + score: bob_score, + total_reward: bob_total_reward, + last_round_reward: bob_round_reward, + unpaid_reward: bob_total_reward, + last_token_distribution_round: 7, } ); + // remove increased stake (keep only alice's stake) + pallet_parachain_staking::Total::::put(alice_staking); + + run_to_block(37); + + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 8, + total_stake: total_staking, + total_score, + }, + )); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 8, + total_staking, + total_score + )); + let alice_round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: alice_round_reward, + round_index: 8, + })); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + bob(), + bob_staking, + 8, + total_staking, + total_score + )); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: bob(), + amount: 0, + round_index: 8, + })); + + // total reward sixth distribution + alice_total_reward += alice_round_reward; + + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: alice_score, + total_reward: alice_total_reward, + last_round_reward: alice_round_reward, + unpaid_reward: alice_total_reward, + last_token_distribution_round: 8, + } + ); // bob should not participate in the reward calculation assert_eq!( ScoreStaking::scores(bob()).unwrap(), @@ -327,14 +688,15 @@ fn score_staking_works() { total_reward: bob_total_reward, last_round_reward: 0, unpaid_reward: bob_total_reward, + last_token_distribution_round: 8, } ); - assert_eq!(ScoreStaking::total_score(), 2000); + assert_eq!(ScoreStaking::total_score(), alice_score); assert_eq!(ScoreStaking::score_user_count(), 2); // entry is not yet removed // remove_score works assert_ok!(ScoreStaking::remove_score(RuntimeOrigin::signed(alice()), bob().into())); - assert_eq!(ScoreStaking::total_score(), 2000); + assert_eq!(ScoreStaking::total_score(), alice_score); assert_eq!(ScoreStaking::score_user_count(), 1); }); } @@ -342,15 +704,19 @@ fn score_staking_works() { #[test] fn claim_works() { new_test_ext(true).execute_with(|| { + let enclave = Enclave::new(WorkerType::Identity); + pallet_teebag::EnclaveRegistry::::insert(alice(), enclave); + run_to_block(2); assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); run_to_block(3); + let alice_staking = 1000; pallet_parachain_staking::DelegatorState::::insert( alice(), - Delegator::new(bob(), bob(), 1000), + Delegator::new(bob(), bob(), alice_staking), ); - pallet_parachain_staking::Total::::put(1000); + pallet_parachain_staking::Total::::put(alice_staking); assert_ok!(ScoreStaking::update_score( RuntimeOrigin::signed(alice()), @@ -360,10 +726,41 @@ fn claim_works() { // run to next reward distribution round, alice should win all rewards run_to_block(7); - System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { - total: round_reward(), - distributed: round_reward(), + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 2, + total_stake: total_staking, + total_score, + }, + )); + + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: 0, + last_round_reward: 0, + unpaid_reward: 0, + last_token_distribution_round: 0, + } + ); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 2, + total_staking, + total_score + )); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward(), + round_index: 2, })); + assert_eq!( ScoreStaking::scores(alice()).unwrap(), ScorePayment { @@ -371,6 +768,7 @@ fn claim_works() { total_reward: round_reward(), last_round_reward: round_reward(), unpaid_reward: round_reward(), + last_token_distribution_round: 2, } ); @@ -386,6 +784,7 @@ fn claim_works() { total_reward: round_reward(), last_round_reward: round_reward(), unpaid_reward: round_reward() - 200, + last_token_distribution_round: 2, } ); @@ -401,6 +800,7 @@ fn claim_works() { total_reward: round_reward(), last_round_reward: round_reward(), unpaid_reward: 0, + last_token_distribution_round: 2, } ); @@ -412,6 +812,200 @@ fn claim_works() { }); } +#[test] +fn distribute_rewards_works() { + new_test_ext_with_parachain_staking().execute_with(|| { + let enclave = Enclave::new(WorkerType::Identity); + pallet_teebag::EnclaveRegistry::::insert(alice(), enclave); + + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + + let mut alice_staking = 900; + let alice_score = 500; + + run_to_block(3); + pallet_parachain_staking::DelegatorState::::insert( + alice(), + Delegator::new(bob(), bob(), alice_staking), + ); + pallet_parachain_staking::Total::::put(alice_staking); + assert_ok!(ScoreStaking::update_score( + RuntimeOrigin::signed(alice()), + alice().into(), + alice_score + )); + + // run to next reward distribution round, alice should win all rewards + run_to_block(7); + + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 2, + total_stake: total_staking, + total_score, + }, + )); + + let alice_id_graph_staking = 1900; + alice_staking = alice_id_graph_staking; + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 2, + total_staking, + total_score + )); + let round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward, + round_index: 2, + })); + + let mut alice_total_reward = 0; + alice_total_reward += round_reward; + + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: alice_score, + total_reward: alice_total_reward, + last_round_reward: round_reward, + unpaid_reward: alice_total_reward, + last_token_distribution_round: 2, + } + ); + + run_to_block(12); + + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 3, + total_stake: total_staking, + total_score, + }, + )); + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 3, + total_staking, + total_score + )); + let round_reward = calculate_round_reward( + alice_score.into(), + total_score.into(), + alice_staking, + total_staking, + ); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward, + round_index: 3, + })); + + alice_total_reward += round_reward; + + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: alice_score, + total_reward: alice_total_reward, + last_round_reward: round_reward, + unpaid_reward: alice_total_reward, + last_token_distribution_round: 3, + } + ); + }) +} + +#[test] +fn distribute_rewards_round_rewards_already_distributed_works() { + new_test_ext_with_parachain_staking().execute_with(|| { + let enclave = Enclave::new(WorkerType::Identity); + pallet_teebag::EnclaveRegistry::::insert(alice(), enclave); + + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + + let alice_staking = 900; + let alice_score = 500; + + run_to_block(3); + pallet_parachain_staking::DelegatorState::::insert( + alice(), + Delegator::new(bob(), bob(), alice_staking), + ); + pallet_parachain_staking::Total::::put(alice_staking); + assert_ok!(ScoreStaking::update_score( + RuntimeOrigin::signed(alice()), + alice().into(), + alice_score + )); + + // run to next reward distribution round, alice should win all rewards + run_to_block(7); + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 2, + total_stake: total_staking, + total_score, + }, + )); + + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 2, + total_staking, + total_score + )); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward(), + round_index: 2, + })); + + assert_noop!( + ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 2, + total_staking, + total_score + ), + Error::::RoundRewardsAlreadyDistributed + ); + }) +} + +#[test] +fn distribute_rewards_origin_check_works() { + new_test_ext(false).execute_with(|| { + assert_noop!( + ScoreStaking::distribute_rewards(RuntimeOrigin::signed(bob()), alice(), 10, 1, 10, 10), + sp_runtime::DispatchError::BadOrigin + ); + }) +} + #[test] fn on_all_delegation_removed_works() { new_test_ext(true).execute_with(|| { diff --git a/parachain/pallets/score-staking/src/types.rs b/parachain/pallets/score-staking/src/types.rs index 1456f4e67d..680c457299 100644 --- a/parachain/pallets/score-staking/src/types.rs +++ b/parachain/pallets/score-staking/src/types.rs @@ -83,4 +83,5 @@ pub struct ScorePayment { pub total_reward: Balance, pub last_round_reward: Balance, pub unpaid_reward: Balance, + pub last_token_distribution_round: RoundIndex, } diff --git a/parachain/precompiles/score-staking/Cargo.toml b/parachain/precompiles/score-staking/Cargo.toml index e9bc95f33d..0913f0877b 100644 --- a/parachain/precompiles/score-staking/Cargo.toml +++ b/parachain/precompiles/score-staking/Cargo.toml @@ -6,6 +6,7 @@ version = '0.1.0' [dependencies] pallet-score-staking = { workspace = true } +pallet-teebag = { workspace = true } precompile-utils = { workspace = true } fp-evm = { workspace = true } @@ -38,9 +39,11 @@ std = [ "frame-system/std", "pallet-evm/std", "pallet-score-staking/std", + "pallet-teebag/std", "precompile-utils/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", ] +runtime-benchmarks = [] diff --git a/parachain/precompiles/score-staking/src/mock.rs b/parachain/precompiles/score-staking/src/mock.rs index 6c5cbb288c..c127b263d8 100644 --- a/parachain/precompiles/score-staking/src/mock.rs +++ b/parachain/precompiles/score-staking/src/mock.rs @@ -15,8 +15,11 @@ // along with Litentry. If not, see . use super::*; +use core::marker::PhantomData; use frame_support::{ - assert_ok, construct_runtime, parameter_types, + assert_ok, construct_runtime, + pallet_prelude::EnsureOrigin, + parameter_types, traits::{OnFinalize, OnInitialize}, weights::Weight, }; @@ -43,6 +46,7 @@ construct_runtime!( Evm: pallet_evm, ParachainStaking: pallet_parachain_staking, ScoreStaking: pallet_score_staking, + Teebag: pallet_teebag, } ); @@ -164,6 +168,7 @@ impl pallet_score_staking::Config for Test { type YearlyIssuance = ConstU128<{ 100_000_000 * UNIT }>; type YearlyInflation = DefaultYearlyInflation; type MaxScoreUserCount = ConstU32<2>; + type TEECallOrigin = EnsureEnclaveSigner; } pub fn precompile_address() -> H160 { @@ -245,6 +250,52 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } +parameter_types! { + pub const MomentsPerDay: u64 = 86_400_000; // [ms/d] +} + +impl pallet_teebag::Config for Test { + type RuntimeEvent = RuntimeEvent; + type MomentsPerDay = MomentsPerDay; + type SetAdminOrigin = EnsureRoot; + type MaxEnclaveIdentifier = ConstU32<1>; + type MaxAuthorizedEnclave = ConstU32<2>; + type WeightInfo = (); +} + +pub struct EnsureEnclaveSigner(PhantomData); +impl EnsureOrigin for EnsureEnclaveSigner +where + T: frame_system::Config + pallet_teebag::Config + pallet_timestamp::Config, + ::AccountId: From<[u8; 32]>, + ::Hash: From<[u8; 32]>, +{ + type Success = T::AccountId; + fn try_origin(o: T::RuntimeOrigin) -> Result { + o.into().and_then(|o| match o { + frame_system::RawOrigin::Signed(who) + if pallet_teebag::EnclaveRegistry::::contains_key(&who) => + { + Ok(who) + }, + r => Err(T::RuntimeOrigin::from(r)), + }) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + use pallet_teebag::test_util::{get_signer, TEST8_MRENCLAVE, TEST8_SIGNER_PUB}; + let signer: ::AccountId = get_signer(TEST8_SIGNER_PUB); + if !pallet_teebag::EnclaveRegistry::::contains_key(signer.clone()) { + assert_ok!(pallet_teebag::Pallet::::add_enclave( + &signer, + &pallet_teebag::Enclave::default().with_mrenclave(TEST8_MRENCLAVE), + )); + } + Ok(frame_system::RawOrigin::Signed(signer).into()) + } +} + pub fn alice() -> AccountId { U8Wrapper(1u8).into() } @@ -259,6 +310,14 @@ pub fn new_test_ext(fast_round: bool) -> sp_io::TestExternalities { .assimilate_storage(&mut t) .unwrap(); + pallet_teebag::GenesisConfig:: { + allow_sgx_debug_mode: true, + admin: Some(alice()), + mode: pallet_teebag::OperationalMode::Production, + } + .assimilate_storage(&mut t) + .unwrap(); + pallet_score_staking::GenesisConfig:: { state: PoolState::Stopped, marker: Default::default(), diff --git a/parachain/precompiles/score-staking/src/tests.rs b/parachain/precompiles/score-staking/src/tests.rs index b3e61b6e0e..fe4fb09f24 100644 --- a/parachain/precompiles/score-staking/src/tests.rs +++ b/parachain/precompiles/score-staking/src/tests.rs @@ -20,6 +20,7 @@ use core_primitives::YEARS; use frame_support::{assert_err, assert_ok}; use pallet_parachain_staking::Delegator; use pallet_score_staking::{Error, Event, ScorePayment}; +use pallet_teebag::{Enclave, WorkerType}; use precompile_utils::testing::*; use sp_runtime::Perbill; @@ -34,15 +35,19 @@ fn precompiles() -> ScoreStakingMockPrecompile { #[test] fn claim_is_ok() { new_test_ext(true).execute_with(|| { + let enclave = Enclave::new(WorkerType::Identity); + pallet_teebag::EnclaveRegistry::::insert(alice(), enclave); + run_to_block(2); assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); run_to_block(3); + let alice_staking = 1000; pallet_parachain_staking::DelegatorState::::insert( alice(), - Delegator::new(bob(), bob(), 1000), + Delegator::new(bob(), bob(), alice_staking), ); - pallet_parachain_staking::Total::::put(1000); + pallet_parachain_staking::Total::::put(alice_staking); assert_ok!(ScoreStaking::update_score( RuntimeOrigin::signed(alice()), @@ -52,10 +57,31 @@ fn claim_is_ok() { // run to next reward distribution round, alice should win all rewards run_to_block(7); - System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { - total: round_reward(), - distributed: round_reward(), + let total_staking = pallet_parachain_staking::Total::::get(); + let total_score = ScoreStaking::total_score(); + System::assert_last_event(RuntimeEvent::ScoreStaking( + Event::::RewardDistributionStarted { + round_index: 2, + total_stake: total_staking, + total_score, + }, + )); + + // calculates the rewards + assert_ok!(ScoreStaking::distribute_rewards( + RuntimeOrigin::signed(alice()), + alice(), + alice_staking, + 2, + total_staking, + total_score + )); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::RewardDistributed { + who: alice(), + amount: round_reward(), + round_index: 2, })); + assert_eq!( ScoreStaking::scores(alice()).unwrap(), ScorePayment { @@ -63,6 +89,7 @@ fn claim_is_ok() { total_reward: round_reward(), last_round_reward: round_reward(), unpaid_reward: round_reward(), + last_token_distribution_round: 2, } ); @@ -86,6 +113,7 @@ fn claim_is_ok() { total_reward: round_reward(), last_round_reward: round_reward(), unpaid_reward: round_reward() - 200, + last_token_distribution_round: 2, } ); @@ -109,6 +137,7 @@ fn claim_is_ok() { total_reward: round_reward(), last_round_reward: round_reward(), unpaid_reward: 0, + last_token_distribution_round: 2, } ); diff --git a/parachain/runtime/litentry/src/lib.rs b/parachain/runtime/litentry/src/lib.rs index 0fe656a87f..218421d4d5 100644 --- a/parachain/runtime/litentry/src/lib.rs +++ b/parachain/runtime/litentry/src/lib.rs @@ -1127,6 +1127,7 @@ impl pallet_score_staking::Config for Runtime { type YearlyIssuance = ConstU128<{ 100_000_000 * UNIT }>; type YearlyInflation = DefaultYearlyInflation; type MaxScoreUserCount = ConstU32<1_000_000>; + type TEECallOrigin = EnsureEnclaveSigner; } impl runtime_common::BaseRuntimeRequirements for Runtime {} diff --git a/parachain/runtime/paseo/src/lib.rs b/parachain/runtime/paseo/src/lib.rs index 8c5267e471..336d69e59c 100644 --- a/parachain/runtime/paseo/src/lib.rs +++ b/parachain/runtime/paseo/src/lib.rs @@ -1169,6 +1169,7 @@ impl pallet_score_staking::Config for Runtime { type YearlyIssuance = ConstU128<{ 100_000_000 * UNIT }>; type YearlyInflation = DefaultYearlyInflation; type MaxScoreUserCount = ConstU32<1_000_000>; + type TEECallOrigin = EnsureEnclaveSigner; } impl runtime_common::BaseRuntimeRequirements for Runtime {} diff --git a/parachain/runtime/rococo/src/lib.rs b/parachain/runtime/rococo/src/lib.rs index ba7f2ca240..a4d6a15f3b 100644 --- a/parachain/runtime/rococo/src/lib.rs +++ b/parachain/runtime/rococo/src/lib.rs @@ -1168,6 +1168,7 @@ impl pallet_score_staking::Config for Runtime { type YearlyIssuance = ConstU128<{ 100_000_000 * UNIT }>; type YearlyInflation = DefaultYearlyInflation; type MaxScoreUserCount = ConstU32<1_000_000>; + type TEECallOrigin = EnsureEnclaveSigner; } impl runtime_common::BaseRuntimeRequirements for Runtime {} diff --git a/tee-worker/Cargo.lock b/tee-worker/Cargo.lock index 3598a69365..8289290664 100644 --- a/tee-worker/Cargo.lock +++ b/tee-worker/Cargo.lock @@ -3331,6 +3331,7 @@ name = "id-ita-parentchain-interface" version = "0.1.0" dependencies = [ "env_logger 0.10.2", + "frame-support", "id-ita-sgx-runtime", "id-ita-stf", "id-itc-parentchain-indirect-calls-executor", @@ -3342,13 +3343,19 @@ dependencies = [ "itp-node-api", "itp-ocall-api", "itp-sgx-crypto", + "itp-sgx-externalities", "itp-stf-primitives", + "itp-stf-state-handler", + "itp-storage", "itp-test", "itp-types", "lc-dynamic-assertion", "lc-evm-dynamic-assertions", + "lc-parachain-extrinsic-task-sender", + "litentry-hex-utils 0.1.0", "litentry-primitives", "log 0.4.20", + "pallet-identity-management-tee", "parity-scale-codec", "sgx_tstd", "sp-core", @@ -5619,6 +5626,7 @@ dependencies = [ "itp-sgx-crypto", "itp-sgx-runtime-primitives", "log 0.4.20", + "pallet-parachain-staking", "pallet-teebag", "parity-scale-codec", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_filter.rs b/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_filter.rs index 2294044191..a5dc1e733d 100644 --- a/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_filter.rs +++ b/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_filter.rs @@ -117,4 +117,10 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + self.filter() + } } diff --git a/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_handler.rs b/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_handler.rs index 94b3ba3efb..ad41d8a11d 100644 --- a/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_handler.rs +++ b/tee-worker/bitacross/app-libs/parentchain-interface/src/integritee/event_handler.rs @@ -32,6 +32,7 @@ use itp_types::{ use litentry_primitives::{Address32, Identity}; use log::*; use sp_core::{blake2_256, H256}; +use sp_runtime::traits::Header; use sp_std::vec::Vec; use std::string::ToString; @@ -133,6 +134,7 @@ where &self, executor: &Executor, events: impl FilterEvents, + _header: impl Header, ) -> Result, Error> { let mut handled_events: Vec = Vec::new(); diff --git a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_filter.rs b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_filter.rs index 56b5365130..4c9d788e49 100644 --- a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_filter.rs +++ b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_filter.rs @@ -115,4 +115,10 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + self.filter() + } } diff --git a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_handler.rs b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_handler.rs index 1a6a9188b3..21aab62926 100644 --- a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_handler.rs +++ b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_a/event_handler.rs @@ -28,6 +28,7 @@ use itp_types::{ H256, }; use log::*; +use sp_runtime::traits::Header; use std::vec::Vec; pub struct ParentchainEventHandler {} @@ -56,6 +57,7 @@ where &self, _executor: &Executor, _events: impl FilterEvents, + _header: impl Header, ) -> Result, Error> { debug!("not handling any events for target a"); Ok(Vec::new()) diff --git a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_filter.rs b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_filter.rs index 56b5365130..4c9d788e49 100644 --- a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_filter.rs +++ b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_filter.rs @@ -115,4 +115,10 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + self.filter() + } } diff --git a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_handler.rs b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_handler.rs index a822fc6919..dc5b153dd7 100644 --- a/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_handler.rs +++ b/tee-worker/bitacross/app-libs/parentchain-interface/src/target_b/event_handler.rs @@ -28,6 +28,7 @@ use itp_types::{ H256, }; use log::*; +use sp_runtime::traits::Header; use std::vec::Vec; pub struct ParentchainEventHandler {} @@ -56,6 +57,7 @@ where &self, _executor: &Executor, _events: impl FilterEvents, + _header: impl Header, ) -> Result, Error> { debug!("not handling any events for target B"); Ok(Vec::new()) diff --git a/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/executor.rs b/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/executor.rs index 009a996f57..2057e00ce3 100644 --- a/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/executor.rs +++ b/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/executor.rs @@ -195,7 +195,9 @@ impl< })? .ok_or_else(|| Error::Other("Could not create events from metadata".into()))?; - let processed_events = self.parentchain_event_handler.handle_events(self, events)?; + let processed_events = + self.parentchain_event_handler + .handle_events(self, events, block.header().clone())?; if self.parentchain_id == ParentchainId::Litentry { // Include a processed parentchain block confirmation for each block. diff --git a/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/mock.rs b/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/mock.rs index d49e12b18f..bc7f51fe97 100644 --- a/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/mock.rs +++ b/tee-worker/bitacross/core/parentchain/indirect-calls-executor/src/mock.rs @@ -8,6 +8,7 @@ use bc_signer_registry::SignerRegistry; use codec::{Decode, Encode}; use core::marker::PhantomData; use litentry_primitives::DecryptableRequest; +use sp_runtime::traits::Header; use bc_enclave_registry::EnclaveRegistry; use itp_node_api::api_client::{CallIndex, PairSignature, UncheckedExtrinsicV4}; @@ -196,6 +197,12 @@ impl FilterEvents for MockEvents { ) -> Result, Self::Error> { Ok(Vec::new()) } + + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + Ok(Vec::new()) + } } pub struct MockParentchainEventHandler {} @@ -224,6 +231,7 @@ where &self, _: &Executor, _: impl itp_types::parentchain::FilterEvents, + _: impl Header, ) -> core::result::Result, Error> { Ok(Vec::from([H256::default()])) } diff --git a/tee-worker/bitacross/enclave-runtime/Cargo.lock b/tee-worker/bitacross/enclave-runtime/Cargo.lock index 0062a3972d..0642f5f5b4 100644 --- a/tee-worker/bitacross/enclave-runtime/Cargo.lock +++ b/tee-worker/bitacross/enclave-runtime/Cargo.lock @@ -969,7 +969,7 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-primitives" version = "0.1.0" -source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#ea133d42f915d6e3cbbc51304f534d0b9f42e5d3" +source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#cdbe9b02c1c58ca3d0063bf2eaf26a1f9da314e9" dependencies = [ "base58", "frame-support", @@ -2764,7 +2764,7 @@ dependencies = [ [[package]] name = "litentry-hex-utils" version = "0.1.0" -source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#ea133d42f915d6e3cbbc51304f534d0b9f42e5d3" +source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#cdbe9b02c1c58ca3d0063bf2eaf26a1f9da314e9" dependencies = [ "hex", ] @@ -2776,7 +2776,7 @@ version = "0.1.0" [[package]] name = "litentry-macros" version = "0.1.0" -source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#ea133d42f915d6e3cbbc51304f534d0b9f42e5d3" +source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#cdbe9b02c1c58ca3d0063bf2eaf26a1f9da314e9" [[package]] name = "litentry-primitives" @@ -2788,6 +2788,7 @@ dependencies = [ "itp-sgx-crypto", "itp-sgx-runtime-primitives", "log 0.4.21", + "pallet-parachain-staking", "pallet-teebag", "parity-scale-codec", "rand 0.7.3", @@ -2815,7 +2816,7 @@ dependencies = [ [[package]] name = "litentry-proc-macros" version = "0.1.0" -source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#ea133d42f915d6e3cbbc51304f534d0b9f42e5d3" +source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#cdbe9b02c1c58ca3d0063bf2eaf26a1f9da314e9" dependencies = [ "cargo_toml", "proc-macro2", @@ -3122,6 +3123,20 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "pallet-authorship" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-balances" version = "4.0.0-dev" @@ -3160,6 +3175,26 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-parachain-staking" +version = "0.1.0" +source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#cdbe9b02c1c58ca3d0063bf2eaf26a1f9da314e9" +dependencies = [ + "core-primitives", + "frame-support", + "frame-system", + "log 0.4.21", + "pallet-authorship", + "pallet-balances", + "pallet-session", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-staking", + "sp-std", + "substrate-fixed", +] + [[package]] name = "pallet-parentchain" version = "0.1.0" @@ -3173,6 +3208,26 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "pallet-session" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log 0.4.21", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", +] + [[package]] name = "pallet-sudo" version = "4.0.0-dev" @@ -3190,7 +3245,7 @@ dependencies = [ [[package]] name = "pallet-teebag" version = "0.1.0" -source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#ea133d42f915d6e3cbbc51304f534d0b9f42e5d3" +source = "git+https://github.com/litentry/litentry-parachain?branch=release-v0.9.19#cdbe9b02c1c58ca3d0063bf2eaf26a1f9da314e9" dependencies = [ "base64 0.13.1", "chrono 0.4.31", @@ -4588,6 +4643,19 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "sp-session" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-staking", + "sp-std", +] + [[package]] name = "sp-staking" version = "4.0.0-dev" @@ -4793,6 +4861,26 @@ dependencies = [ "sp-runtime-interface", ] +[[package]] +name = "substrate-fixed" +version = "0.5.9" +source = "git+https://github.com/encointer/substrate-fixed#879c58bcc6fd676a74315dcd38b598f28708b0b5" +dependencies = [ + "parity-scale-codec", + "scale-info", + "substrate-typenum", +] + +[[package]] +name = "substrate-typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f0091e93c2c75b233ae39424c52cb8a662c0811fb68add149e20e5d7e8a788" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "subtle" version = "2.4.1" @@ -5050,7 +5138,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "digest 0.10.7", "static_assertions", ] diff --git a/tee-worker/common/core-primitives/extrinsics-factory/src/lib.rs b/tee-worker/common/core-primitives/extrinsics-factory/src/lib.rs index ab58d65853..f869917b27 100644 --- a/tee-worker/common/core-primitives/extrinsics-factory/src/lib.rs +++ b/tee-worker/common/core-primitives/extrinsics-factory/src/lib.rs @@ -35,7 +35,7 @@ use itp_node_api::{ api_client::{ ExtrinsicParams, ParentchainAdditionalParams, ParentchainExtrinsicParams, SignExtrinsic, }, - metadata::{provider::AccessNodeMetadata, NodeMetadata}, + metadata::{provider::AccessNodeMetadata, NodeMetadata, NodeMetadataProvider}, }; use itp_nonce_cache::{MutateNonce, Nonce}; use itp_types::{parentchain::AccountId, OpaqueCall}; diff --git a/tee-worker/common/core-primitives/node-api/metadata/src/lib.rs b/tee-worker/common/core-primitives/node-api/metadata/src/lib.rs index 352decf8ca..689682570a 100644 --- a/tee-worker/common/core-primitives/node-api/metadata/src/lib.rs +++ b/tee-worker/common/core-primitives/node-api/metadata/src/lib.rs @@ -22,9 +22,10 @@ use crate::{ error::Result, pallet_balances::BalancesCallIndexes, pallet_bitacross::BitAcrossCallIndexes, pallet_evm_assertion::EvmAssertionsCallIndexes, pallet_imp::IMPCallIndexes, - pallet_proxy::ProxyCallIndexes, pallet_system::SystemConstants, - pallet_teebag::TeebagCallIndexes, pallet_timestamp::TimestampCallIndexes, - pallet_utility::UtilityCallIndexes, pallet_vcmp::VCMPCallIndexes, + pallet_proxy::ProxyCallIndexes, pallet_score_staking::ScoreStakingCallIndexes, + pallet_system::SystemConstants, pallet_teebag::TeebagCallIndexes, + pallet_timestamp::TimestampCallIndexes, pallet_utility::UtilityCallIndexes, + pallet_vcmp::VCMPCallIndexes, }; use codec::{Decode, Encode}; use sp_core::storage::StorageKey; @@ -38,6 +39,7 @@ pub mod pallet_bitacross; pub mod pallet_evm_assertion; pub mod pallet_imp; pub mod pallet_proxy; +pub mod pallet_score_staking; pub mod pallet_system; pub mod pallet_teebag; pub mod pallet_utility; @@ -49,6 +51,10 @@ pub mod pallet_timestamp; #[cfg(feature = "mocks")] pub mod metadata_mocks; +pub trait NodeMetadataProvider { + fn get_metadata(&self) -> Option<&Metadata>; +} + pub trait NodeMetadataTrait: TeebagCallIndexes + IMPCallIndexes @@ -59,6 +65,8 @@ pub trait NodeMetadataTrait: + BalancesCallIndexes + TimestampCallIndexes + EvmAssertionsCallIndexes + + ScoreStakingCallIndexes + + NodeMetadataProvider + BitAcrossCallIndexes { } @@ -73,6 +81,8 @@ impl< + BalancesCallIndexes + TimestampCallIndexes + EvmAssertionsCallIndexes + + ScoreStakingCallIndexes + + NodeMetadataProvider + BitAcrossCallIndexes, > NodeMetadataTrait for T { @@ -106,10 +116,6 @@ impl NodeMetadata { } } - pub fn get_metadata(&self) -> Option<&Metadata> { - self.node_metadata.as_ref() - } - /// Return the substrate chain runtime version. pub fn get_runtime_version(&self) -> u32 { self.runtime_spec_version @@ -184,3 +190,9 @@ impl NodeMetadata { } } } + +impl NodeMetadataProvider for NodeMetadata { + fn get_metadata(&self) -> Option<&Metadata> { + self.node_metadata.as_ref() + } +} diff --git a/tee-worker/common/core-primitives/node-api/metadata/src/metadata_mocks.rs b/tee-worker/common/core-primitives/node-api/metadata/src/metadata_mocks.rs index 6fb986da21..e558c17cee 100644 --- a/tee-worker/common/core-primitives/node-api/metadata/src/metadata_mocks.rs +++ b/tee-worker/common/core-primitives/node-api/metadata/src/metadata_mocks.rs @@ -18,9 +18,10 @@ use crate::{ error::Result, pallet_balances::BalancesCallIndexes, pallet_bitacross::BitAcrossCallIndexes, pallet_evm_assertion::EvmAssertionsCallIndexes, pallet_imp::IMPCallIndexes, - pallet_proxy::ProxyCallIndexes, pallet_system::SystemConstants, - pallet_teebag::TeebagCallIndexes, pallet_timestamp::TimestampCallIndexes, - pallet_utility::UtilityCallIndexes, pallet_vcmp::VCMPCallIndexes, runtime_call::RuntimeCall, + pallet_proxy::ProxyCallIndexes, pallet_score_staking::ScoreStakingCallIndexes, + pallet_system::SystemConstants, pallet_teebag::TeebagCallIndexes, + pallet_timestamp::TimestampCallIndexes, pallet_utility::UtilityCallIndexes, + pallet_vcmp::VCMPCallIndexes, runtime_call::RuntimeCall, NodeMetadataProvider, }; use codec::{Decode, Encode}; @@ -89,6 +90,11 @@ pub struct NodeMetadataMock { runtime_spec_version: u32, runtime_transaction_version: u32, + //ScoreStaking + score_staking_module: u8, + distribute_rewards: u8, + complete_rewards_distribution: u8, + bitacross_module: u8, bitacross_add_relayer: u8, bitacross_remove_relayer: u8, @@ -151,6 +157,10 @@ impl NodeMetadataMock { runtime_spec_version: 25, runtime_transaction_version: 4, + score_staking_module: 100u8, + distribute_rewards: 10u8, + complete_rewards_distribution: 11u8, + bitacross_module: 69u8, bitacross_add_relayer: 0u8, bitacross_remove_relayer: 1u8, @@ -191,6 +201,16 @@ impl TeebagCallIndexes for NodeMetadataMock { } } +impl ScoreStakingCallIndexes for NodeMetadataMock { + fn distribute_rewards_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.score_staking_module, self.distribute_rewards]) + } + + fn complete_rewards_distribution_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.score_staking_module, self.complete_rewards_distribution]) + } +} + impl IMPCallIndexes for NodeMetadataMock { fn link_identity_call_indexes(&self) -> Result<[u8; 2]> { Ok([self.imp_module, self.imp_link_identity]) @@ -346,3 +366,9 @@ impl EvmAssertionsCallIndexes for NodeMetadataMock { Ok([self.evm_assertions_module, self.evm_assertions_void_assertion]) } } + +impl NodeMetadataProvider for NodeMetadataMock { + fn get_metadata(&self) -> Option<&Metadata> { + None + } +} diff --git a/tee-worker/common/core-primitives/node-api/metadata/src/pallet_score_staking.rs b/tee-worker/common/core-primitives/node-api/metadata/src/pallet_score_staking.rs new file mode 100644 index 0000000000..6a3f934237 --- /dev/null +++ b/tee-worker/common/core-primitives/node-api/metadata/src/pallet_score_staking.rs @@ -0,0 +1,37 @@ +/* + Copyright 2021 Integritee AG and Supercomputing Systems AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +use crate::{error::Result, NodeMetadata}; + +/// Pallet' name: +pub const SCORE_STAKING: &str = "ScoreStaking"; + +// we only list the extrinsics that we care +pub trait ScoreStakingCallIndexes { + fn distribute_rewards_call_indexes(&self) -> Result<[u8; 2]>; + + fn complete_rewards_distribution_call_indexes(&self) -> Result<[u8; 2]>; +} + +impl ScoreStakingCallIndexes for NodeMetadata { + fn distribute_rewards_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(SCORE_STAKING, "distribute_rewards") + } + + fn complete_rewards_distribution_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(SCORE_STAKING, "complete_rewards_distribution") + } +} diff --git a/tee-worker/common/core-primitives/storage/src/keys.rs b/tee-worker/common/core-primitives/storage/src/keys.rs index 43de4f667e..34520a405f 100644 --- a/tee-worker/common/core-primitives/storage/src/keys.rs +++ b/tee-worker/common/core-primitives/storage/src/keys.rs @@ -17,6 +17,7 @@ use codec::Encode; use frame_metadata::v14::StorageHasher; +use sp_core::crypto::AccountId32 as AccountId; use sp_std::vec::Vec; pub fn storage_value_key(module_prefix: &str, storage_prefix: &str) -> Vec { @@ -25,6 +26,19 @@ pub fn storage_value_key(module_prefix: &str, storage_prefix: &str) -> Vec { bytes } +/// Extracts the AccountId from a storage key +pub fn key_to_account_id(key: &Vec) -> Option { + if key.len() >= 32 { + let account_id_bytes = &key[key.len() - 32..]; + let mut account_id_32_bytes = [0; 32]; + account_id_32_bytes.copy_from_slice(account_id_bytes); + + Some(AccountId::new(account_id_32_bytes)) + } else { + None + } +} + pub fn storage_map_key( module_prefix: &str, storage_prefix: &str, diff --git a/tee-worker/common/core-primitives/types/src/lib.rs b/tee-worker/common/core-primitives/types/src/lib.rs index b224381f63..e1c917f688 100644 --- a/tee-worker/common/core-primitives/types/src/lib.rs +++ b/tee-worker/common/core-primitives/types/src/lib.rs @@ -31,8 +31,8 @@ pub use sidechain::SidechainBlockHash; pub use itp_sgx_runtime_primitives::types::*; pub use litentry_primitives::{ - Assertion, AttestationType, DcapProvider, DecryptableRequest, Enclave, EnclaveFingerprint, - MrEnclave, SidechainBlockNumber, WorkerType, + Assertion, AttestationType, DcapProvider, DecryptableRequest, Delegator, Enclave, + EnclaveFingerprint, MrEnclave, SidechainBlockNumber, WorkerType, }; pub use sp_core::{crypto::AccountId32 as AccountId, H256}; diff --git a/tee-worker/common/core-primitives/types/src/parentchain/events.rs b/tee-worker/common/core-primitives/types/src/parentchain/events.rs index 0442e2094d..876ecc1bf6 100644 --- a/tee-worker/common/core-primitives/types/src/parentchain/events.rs +++ b/tee-worker/common/core-primitives/types/src/parentchain/events.rs @@ -284,6 +284,26 @@ impl StaticEvent for AssertionCreated { const EVENT: &'static str = "AssertionCreated"; } +#[derive(Encode, Decode, Debug)] +pub struct RewardDistributionStarted { + pub round_index: u32, + pub total_stake: Balance, + pub total_score: Balance, +} + +impl core::fmt::Display for RewardDistributionStarted { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let message = format!( + "{:?} :: round_index: {}, total_stake: {}, total_score: {}", + RewardDistributionStarted::EVENT, + self.round_index, + self.total_stake, + self.total_score + ); + write!(f, "{}", message) + } +} + // Bitacross pallet events #[derive(Encode, Decode, Debug)] @@ -342,6 +362,11 @@ impl core::fmt::Display for BtcWalletGenerated { } } +impl StaticEvent for RewardDistributionStarted { + const PALLET: &'static str = "ScoreStaking"; + const EVENT: &'static str = "RewardDistributionStarted"; +} + impl StaticEvent for BtcWalletGenerated { const PALLET: &'static str = "Bitacross"; const EVENT: &'static str = "BtcWalletGenerated"; diff --git a/tee-worker/common/core-primitives/types/src/parentchain/mod.rs b/tee-worker/common/core-primitives/types/src/parentchain/mod.rs index 6c4d9135c7..689f8ef82b 100644 --- a/tee-worker/common/core-primitives/types/src/parentchain/mod.rs +++ b/tee-worker/common/core-primitives/types/src/parentchain/mod.rs @@ -26,7 +26,11 @@ use itp_stf_primitives::traits::{IndirectExecutor, TrustedCallVerification}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_core::{bounded::alloc, H160, H256}; -use sp_runtime::{generic::Header as HeaderG, traits::BlakeTwo256, MultiAddress, MultiSignature}; +use sp_runtime::{ + generic::Header as HeaderG, + traits::{BlakeTwo256, Header as HeaderT}, + MultiAddress, MultiSignature, +}; use self::events::ParentchainBlockProcessed; @@ -114,6 +118,10 @@ pub trait FilterEvents { &self, ) -> Result, Self::Error>; + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error>; + fn get_relayer_added_events(&self) -> Result, Self::Error>; fn get_relayers_removed_events(&self) -> Result, Self::Error>; @@ -144,6 +152,7 @@ where &self, executor: &Executor, events: impl FilterEvents, + block_header: impl HeaderT, ) -> Result; } @@ -158,6 +167,7 @@ pub enum ParentchainEventProcessingError { OpaqueTaskPostedFailure, AssertionCreatedFailure, ParentchainBlockProcessedFailure, + RewardDistributionStartedFailure, RelayerAddFailure, RelayerRemoveFailure, EnclaveAddFailure, @@ -186,6 +196,8 @@ impl core::fmt::Display for ParentchainEventProcessingError { "Parentchain Event Processing Error: AssertionCreatedFailure", ParentchainEventProcessingError::ParentchainBlockProcessedFailure => "Parentchain Event Processing Error: ParentchainBlockProcessedFailure", + ParentchainEventProcessingError::RewardDistributionStartedFailure => + "Parentchain Event Processing Error: RewardDistributionStartedFailure", ParentchainEventProcessingError::RelayerAddFailure => "Parentchain Event Processing Error: RelayerAddFailure", ParentchainEventProcessingError::RelayerRemoveFailure => diff --git a/tee-worker/common/litentry/primitives/Cargo.toml b/tee-worker/common/litentry/primitives/Cargo.toml index 9a1c2bd38b..f0df1f58f4 100644 --- a/tee-worker/common/litentry/primitives/Cargo.toml +++ b/tee-worker/common/litentry/primitives/Cargo.toml @@ -28,6 +28,8 @@ itp-sgx-runtime-primitives = { workspace = true } pallet-teebag = { workspace = true } parentchain-primitives = { workspace = true } +pallet-parachain-staking = { workspace = true } + [dev-dependencies] base64 = { workspace = true } diff --git a/tee-worker/common/litentry/primitives/src/lib.rs b/tee-worker/common/litentry/primitives/src/lib.rs index 2a14a12b82..07bd6039f8 100644 --- a/tee-worker/common/litentry/primitives/src/lib.rs +++ b/tee-worker/common/litentry/primitives/src/lib.rs @@ -45,6 +45,7 @@ use bitcoin::sign_message::{signed_msg_hash, MessageSignature}; use codec::{Decode, Encode, MaxEncodedLen}; use itp_sgx_crypto::ShieldingCryptoDecrypt; use log::error; +pub use pallet_parachain_staking::Delegator; pub use pallet_teebag::{ decl_rsa_request, extract_tcb_info_from_raw_dcap_quote, AttestationType, DcapProvider, Enclave, EnclaveFingerprint, MrEnclave, ShardIdentifier, SidechainBlockNumber, WorkerMode, WorkerType, diff --git a/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml b/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml index 3718f96eb0..a34e16af47 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml +++ b/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml @@ -14,7 +14,10 @@ itp-api-client-types = { workspace = true } itp-enclave-metrics = { workspace = true } itp-node-api = { workspace = true } itp-ocall-api = { workspace = true } +itp-sgx-externalities = { workspace = true } itp-stf-primitives = { workspace = true } +itp-stf-state-handler = { workspace = true } +itp-storage = { workspace = true } itp-types = { workspace = true } codec = { package = "parity-scale-codec", workspace = true } @@ -27,8 +30,14 @@ substrate-api-client = { workspace = true, optional = true } lc-dynamic-assertion = { workspace = true } lc-evm-dynamic-assertions = { workspace = true } +lc-parachain-extrinsic-task-sender = { workspace = true } + +litentry-hex-utils = { workspace = true } litentry-primitives = { workspace = true } +frame-support = { workspace = true } +pallet-identity-management-tee = { workspace = true } + [dev-dependencies] env_logger = { workspace = true } itp-node-api = { workspace = true, features = ["std", "mocks"] } @@ -52,6 +61,7 @@ std = [ "itp-stf-executor/std", "itp-stf-primitives/std", "itp-top-pool-author/std", + "itp-sgx-externalities/std", "itp-types/std", "log/std", "sp-core/std", @@ -60,6 +70,7 @@ std = [ "litentry-primitives/std", "lc-dynamic-assertion/std", "lc-evm-dynamic-assertions/std", + "lc-parachain-extrinsic-task-sender/std", "sp-std/std", ] sgx = [ @@ -69,8 +80,10 @@ sgx = [ "itp-node-api/sgx", "itp-sgx-crypto/sgx", "itp-stf-executor/sgx", + "itp-sgx-externalities/sgx", "itp-top-pool-author/sgx", "litentry-primitives/sgx", "lc-dynamic-assertion/sgx", "lc-evm-dynamic-assertions/sgx", + "lc-parachain-extrinsic-task-sender/sgx", ] diff --git a/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_filter.rs b/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_filter.rs index c27e871c70..ad061edc70 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_filter.rs +++ b/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_filter.rs @@ -98,6 +98,11 @@ impl FilterEvents for FilterableEvents { self.filter() } + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + self.filter() + } fn get_relayer_added_events(&self) -> Result, Self::Error> { self.filter() } diff --git a/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_handler.rs b/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_handler.rs index a46eba6cc0..3c9500d3d4 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_handler.rs +++ b/tee-worker/identity/app-libs/parentchain-interface/src/integritee/event_handler.rs @@ -16,39 +16,53 @@ */ use codec::{Decode, Encode}; -pub use ita_sgx_runtime::{Balance, Index}; +use frame_support::storage::storage_prefix; +pub use ita_sgx_runtime::{Balance, Index, Runtime}; use ita_stf::{Getter, TrustedCall, TrustedCallSigned}; use itc_parentchain_indirect_calls_executor::error::Error; use itp_api_client_types::StaticEvent; use itp_enclave_metrics::EnclaveMetric; -use itp_ocall_api::EnclaveMetricsOCallApi; +use itp_node_api::metadata::{ + pallet_score_staking::ScoreStakingCallIndexes, provider::AccessNodeMetadata, NodeMetadataTrait, +}; +use itp_ocall_api::{EnclaveMetricsOCallApi, EnclaveOnChainOCallApi}; +use itp_sgx_externalities::{SgxExternalities, SgxExternalitiesTrait}; use itp_stf_primitives::{traits::IndirectExecutor, types::TrustedOperation}; +use itp_stf_state_handler::handle_state::HandleState; +use itp_storage::{key_to_account_id, storage_map_key, StorageHasher}; use itp_types::{ parentchain::{ - events::ParentchainBlockProcessed, AccountId, FilterEvents, HandleParentchainEvents, - ParentchainEventProcessingError, ProcessedEventsArtifacts, + events::{ParentchainBlockProcessed, RewardDistributionStarted}, + AccountId, FilterEvents, HandleParentchainEvents, ParentchainEventProcessingError, + ParentchainId, ProcessedEventsArtifacts, }, - RsaRequest, H256, + Delegator, OpaqueCall, RsaRequest, H256, }; use lc_dynamic_assertion::AssertionLogicRepository; use lc_evm_dynamic_assertions::repository::EvmAssertionRepository; +use lc_parachain_extrinsic_task_sender::{ParachainExtrinsicSender, SendParachainExtrinsic}; +use litentry_hex_utils::decode_hex; use litentry_primitives::{Assertion, Identity, ValidationData, Web3Network}; use log::*; +use pallet_identity_management_tee::IdentityContext; use sp_core::{blake2_256, H160}; +use sp_runtime::traits::Header; use sp_std::vec::Vec; -use std::{format, string::String, sync::Arc, time::Instant}; +use std::{collections::BTreeMap, format, println, string::String, sync::Arc, time::Instant}; -pub struct ParentchainEventHandler -where - MetricsApi: EnclaveMetricsOCallApi, -{ +pub struct ParentchainEventHandler { pub assertion_repository: Arc, - pub metrics_api: Arc, + pub ocall_api: Arc, + pub state_handler: Arc, + pub node_metadata_repository: Arc, } -impl ParentchainEventHandler +impl ParentchainEventHandler where - MetricsApi: EnclaveMetricsOCallApi, + OCallApi: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi, + HS: HandleState, + NMR: AccessNodeMetadata, + NMR::MetadataType: NodeMetadataTrait, { fn link_identity>( executor: &Executor, @@ -210,28 +224,176 @@ where .save(id, (byte_code, decrypted_secrets)) .map_err(Error::AssertionCreatedHandling)?; let duration = start_time.elapsed(); - if let Err(e) = self - .metrics_api - .update_metric(EnclaveMetric::DynamicAssertionSaveTime(duration)) + if let Err(e) = + self.ocall_api.update_metric(EnclaveMetric::DynamicAssertionSaveTime(duration)) { warn!("Failed to update DynamicAssertionSaveTime metric with error: {:?}", e); } Ok(()) } + + fn distribute_staking_rewards< + Executor: IndirectExecutor, + >( + &self, + executor: &Executor, + block_header: impl Header, + event: &RewardDistributionStarted, + ) -> Result<(), Error> { + let scores_key_prefix = storage_prefix(b"ScoreStaking", b"Scores"); + let scores_storage_keys_response = self + .ocall_api + .get_storage_keys(scores_key_prefix.into()) + .map_err(|_| Error::Other("Failed to get storage keys".into()))?; + let scores_storage_keys: Vec> = scores_storage_keys_response + .into_iter() + .filter_map(decode_storage_key) + .collect(); + let account_ids: Vec = + scores_storage_keys.iter().filter_map(key_to_account_id).collect(); + + let delegator_state_storage_keys: Vec> = account_ids + .iter() + .map(|account_id| { + storage_map_key( + "ParachainStaking", + "DelegatorState", + account_id, + &StorageHasher::Blake2_128Concat, + ) + }) + .collect(); + let delegator_states: BTreeMap> = self + .ocall_api + .get_multiple_storages_verified( + delegator_state_storage_keys, + &block_header, + &ParentchainId::Litentry, + ) + .map_err(|_| Error::Other("Failed to get multiple storages".into()))? + .into_iter() + .filter_map(|entry| { + let storage_key = decode_storage_key(entry.key)?; + let account_id = key_to_account_id(&storage_key)?; + let delegator = entry.value?; + Some((account_id, delegator)) + }) + .collect(); + + let id_graphs_storage_keys: Vec> = account_ids + .iter() + .map(|account_id| { + storage_map_key( + "IdentityManagement", + "IDGraphs", + &Identity::from(account_id.clone()), + &StorageHasher::Blake2_128Concat, + ) + }) + .collect(); + + let shard = executor.get_default_shard(); + + let id_graphs = self + .state_handler + .execute_on_current(&shard, |state, _| { + let mut id_graphs_accounts: BTreeMap> = BTreeMap::new(); + for id_graph_storage_key in id_graphs_storage_keys.iter() { + let id_graph: Vec<(Identity, IdentityContext)> = state + .iter_prefix::>(id_graph_storage_key) + .unwrap_or_default(); + let graph_accounts: Vec = id_graph + .iter() + .filter_map(|(identity, _)| identity.to_account_id()) + .collect(); + if let Some(account_id) = key_to_account_id(id_graph_storage_key) { + id_graphs_accounts.insert(account_id, graph_accounts); + } + } + + id_graphs_accounts + }) + .map_err(|_| Error::Other("Failed to get id graphs".into()))?; + + let extrinsic_sender = ParachainExtrinsicSender::new(); + + let distribute_rewards_call_index = self + .node_metadata_repository + .get_from_metadata(|m| m.distribute_rewards_call_indexes()) + .map_err(|_| { + Error::Other("Metadata retrieval for distribute_rewards_call_indexes failed".into()) + })? + .map_err(|_| Error::Other("Invalid metadata".into()))?; + + for account_id in account_ids.iter() { + let staking_amount: Balance = match id_graphs.get(account_id) { + Some(id_graph) => id_graph + .iter() + .filter_map(|identity| { + let delegator = delegator_states.get(identity)?; + Some(delegator.total) + }) + .sum(), + None => match delegator_states.get(account_id) { + Some(delegator) => delegator.total, + None => 0, + }, + }; + let call = OpaqueCall::from_tuple(&( + distribute_rewards_call_index, + account_id, + staking_amount, + event.round_index, + event.total_stake, + event.total_score, + )); + extrinsic_sender + .send(call) + .map_err(|_| Error::Other("Failed to send extrinsic".into()))?; + } + + let complete_rewards_distribution_call_index = self + .node_metadata_repository + .get_from_metadata(|m| m.complete_rewards_distribution_call_indexes()) + .map_err(|_| { + Error::Other( + "Metadata retrieval for complete_rewards_distribution_call_indexes failed" + .into(), + ) + })? + .map_err(|_| Error::Other("Invalid metadata".into()))?; + let call = + OpaqueCall::from_tuple(&(complete_rewards_distribution_call_index, event.round_index)); + extrinsic_sender + .send(call) + .map_err(|_| Error::Other("Failed to send extrinsic".into()))?; + + Ok(()) + } +} + +fn decode_storage_key(raw_key: Vec) -> Option> { + let hex_key = String::decode(&mut raw_key.as_slice()).unwrap_or_default(); + decode_hex(hex_key).ok() } -impl HandleParentchainEvents - for ParentchainEventHandler +impl + HandleParentchainEvents + for ParentchainEventHandler where Executor: IndirectExecutor, - MetricsApi: EnclaveMetricsOCallApi, + OCallApi: EnclaveOnChainOCallApi + EnclaveMetricsOCallApi, + HS: HandleState, + NMR: AccessNodeMetadata, + NMR::MetadataType: NodeMetadataTrait, { type Output = ProcessedEventsArtifacts; fn handle_events( &self, executor: &Executor, events: impl FilterEvents, + block_header: impl Header, ) -> Result { let mut handled_events: Vec = Vec::new(); let mut successful_assertion_ids: Vec = Vec::new(); @@ -350,6 +512,21 @@ where }); } + if let Ok(events) = events.get_reward_distribution_started_events() { + println!("Handling RewardDistributionStarted events"); + events + .iter() + .try_for_each(|event| { + let event_hash = hash_of(&event); + let result = + self.distribute_staking_rewards(executor, block_header.clone(), event); + handled_events.push(event_hash); + + result + }) + .map_err(|_| ParentchainEventProcessingError::RewardDistributionStartedFailure)?; + } + Ok((handled_events, successful_assertion_ids, failed_assertion_ids)) } } diff --git a/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_filter.rs b/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_filter.rs index c3b102a895..84da9c2ba2 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_filter.rs +++ b/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_filter.rs @@ -106,6 +106,12 @@ impl FilterEvents for FilterableEvents { Ok(Vec::new()) } + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + Ok(Vec::new()) + } + fn get_relayer_added_events(&self) -> Result, Self::Error> { self.filter() } diff --git a/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_handler.rs b/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_handler.rs index 47d1db3382..b7f149ef29 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_handler.rs +++ b/tee-worker/identity/app-libs/parentchain-interface/src/target_a/event_handler.rs @@ -22,6 +22,7 @@ use itc_parentchain_indirect_calls_executor::error::Error; use itp_stf_primitives::traits::IndirectExecutor; use itp_types::parentchain::{FilterEvents, HandleParentchainEvents, ProcessedEventsArtifacts}; use log::*; +use sp_runtime::traits::Header; use sp_std::vec::Vec; pub struct ParentchainEventHandler {} @@ -36,6 +37,7 @@ where &self, _executor: &Executor, _events: impl FilterEvents, + _block_header: impl Header, ) -> Result { debug!("not handling any events for target a"); Ok((Vec::new(), Vec::new(), Vec::new())) diff --git a/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_filter.rs b/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_filter.rs index c3b102a895..84da9c2ba2 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_filter.rs +++ b/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_filter.rs @@ -106,6 +106,12 @@ impl FilterEvents for FilterableEvents { Ok(Vec::new()) } + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + Ok(Vec::new()) + } + fn get_relayer_added_events(&self) -> Result, Self::Error> { self.filter() } diff --git a/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_handler.rs b/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_handler.rs index 5e79be6a99..c71eafaeb7 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_handler.rs +++ b/tee-worker/identity/app-libs/parentchain-interface/src/target_b/event_handler.rs @@ -22,6 +22,7 @@ use itc_parentchain_indirect_calls_executor::error::Error; use itp_stf_primitives::traits::IndirectExecutor; use itp_types::parentchain::{FilterEvents, HandleParentchainEvents, ProcessedEventsArtifacts}; use log::*; +use sp_runtime::traits::Header; use sp_std::vec::Vec; pub struct ParentchainEventHandler {} @@ -36,6 +37,7 @@ where &self, _executor: &Executor, _events: impl FilterEvents, + _block_header: impl Header, ) -> Result { debug!("not handling any events for target B"); Ok((Vec::new(), Vec::new(), Vec::new())) diff --git a/tee-worker/identity/core/parentchain/indirect-calls-executor/src/executor.rs b/tee-worker/identity/core/parentchain/indirect-calls-executor/src/executor.rs index d5b6c0a221..fe5cd33e13 100644 --- a/tee-worker/identity/core/parentchain/indirect-calls-executor/src/executor.rs +++ b/tee-worker/identity/core/parentchain/indirect-calls-executor/src/executor.rs @@ -171,8 +171,9 @@ impl< })? .ok_or_else(|| Error::Other("Could not create events from metadata".into()))?; - let (processed_events, successful_assertion_ids, failed_assertion_ids) = - self.parentchain_event_handler.handle_events(self, events)?; + let (processed_events, successful_assertion_ids, failed_assertion_ids) = self + .parentchain_event_handler + .handle_events(self, events, block.header().clone())?; let mut calls: Vec = Vec::new(); if !successful_assertion_ids.is_empty() { calls.extend(self.create_assertion_stored_call(successful_assertion_ids)?); diff --git a/tee-worker/identity/core/parentchain/indirect-calls-executor/src/mock.rs b/tee-worker/identity/core/parentchain/indirect-calls-executor/src/mock.rs index c24ebfc863..ef574cfd97 100644 --- a/tee-worker/identity/core/parentchain/indirect-calls-executor/src/mock.rs +++ b/tee-worker/identity/core/parentchain/indirect-calls-executor/src/mock.rs @@ -6,6 +6,7 @@ use itp_types::{ RsaRequest, H256, }; use sp_core::H160; +use sp_runtime::traits::Header; use std::vec::Vec; pub struct TestEventCreator; @@ -84,6 +85,12 @@ impl FilterEvents for MockEvents { fn get_relayers_removed_events(&self) -> Result, Self::Error> { Ok(Vec::new()) } + + fn get_reward_distribution_started_events( + &self, + ) -> Result, Self::Error> { + Ok(Vec::new()) + } } pub struct MockParentchainEventHandler {} @@ -98,6 +105,7 @@ where &self, _: &Executor, _: impl FilterEvents, + _: impl Header, ) -> Result { Ok(( Vec::from([H256::default()]), diff --git a/tee-worker/identity/enclave-runtime/Cargo.lock b/tee-worker/identity/enclave-runtime/Cargo.lock index 34b8f1631d..8dbde8ae0f 100644 --- a/tee-worker/identity/enclave-runtime/Cargo.lock +++ b/tee-worker/identity/enclave-runtime/Cargo.lock @@ -1867,6 +1867,7 @@ dependencies = [ name = "id-ita-parentchain-interface" version = "0.1.0" dependencies = [ + "frame-support", "id-ita-sgx-runtime", "id-ita-stf", "id-itc-parentchain-indirect-calls-executor", @@ -1874,12 +1875,18 @@ dependencies = [ "itp-enclave-metrics", "itp-node-api", "itp-ocall-api", + "itp-sgx-externalities", "itp-stf-primitives", + "itp-stf-state-handler", + "itp-storage", "itp-types", "lc-dynamic-assertion", "lc-evm-dynamic-assertions", + "lc-parachain-extrinsic-task-sender", + "litentry-hex-utils 0.1.0", "litentry-primitives", "log", + "pallet-identity-management-tee", "parity-scale-codec", "sgx_tstd", "sp-core", @@ -3403,6 +3410,7 @@ dependencies = [ "itp-sgx-crypto", "itp-sgx-runtime-primitives", "log", + "pallet-parachain-staking", "pallet-teebag", "parity-scale-codec", "rand 0.7.3", diff --git a/tee-worker/identity/enclave-runtime/src/initialization/global_components.rs b/tee-worker/identity/enclave-runtime/src/initialization/global_components.rs index 5255d5303e..939d69fe18 100644 --- a/tee-worker/identity/enclave-runtime/src/initialization/global_components.rs +++ b/tee-worker/identity/enclave-runtime/src/initialization/global_components.rs @@ -177,7 +177,11 @@ pub type IntegriteeParentchainIndirectCallsExecutor = IndirectCallsExecutor< EnclaveTopPoolAuthor, EnclaveNodeMetadataRepository, EventCreator, - integritee::ParentchainEventHandler, + integritee::ParentchainEventHandler< + EnclaveOCallApi, + EnclaveStateHandler, + EnclaveNodeMetadataRepository, + >, EnclaveTrustedCallSigned, EnclaveGetter, >; diff --git a/tee-worker/identity/enclave-runtime/src/initialization/parentchain/common.rs b/tee-worker/identity/enclave-runtime/src/initialization/parentchain/common.rs index 52b345d75a..40fa90d6c7 100644 --- a/tee-worker/identity/enclave-runtime/src/initialization/parentchain/common.rs +++ b/tee-worker/identity/enclave-runtime/src/initialization/parentchain/common.rs @@ -69,10 +69,13 @@ pub(crate) fn create_integritee_parentchain_block_importer( let shielding_key_repository = GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT.get()?; let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; let repository = GLOBAL_ASSERTION_REPOSITORY.get()?; + let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; let parentchain_event_handler = LitentryParentchainEventHandler { assertion_repository: repository, - metrics_api: ocall_api.clone(), + ocall_api: ocall_api.clone(), + state_handler, + node_metadata_repository: node_metadata_repository.clone(), }; let stf_enclave_signer = Arc::new(EnclaveStfEnclaveSigner::new(