From cc87102cbb19294a3b49100e9da324c07e585f89 Mon Sep 17 00:00:00 2001 From: Francisco Silva Date: Fri, 25 Oct 2024 20:53:06 +0200 Subject: [PATCH] AccountStore in-memory state initialization and synchronization (#3133) --- parachain/pallets/omni-account/src/lib.rs | 34 ++++++--- parachain/pallets/omni-account/src/tests.rs | 67 ++++++++++++----- tee-worker/Cargo.lock | 2 +- .../src/integritee/event_filter.rs | 4 ++ .../src/integritee/event_handler.rs | 9 ++- .../src/target_a/event_filter.rs | 4 ++ .../src/target_a/event_handler.rs | 9 ++- .../src/target_b/event_filter.rs | 4 ++ .../src/target_b/event_handler.rs | 9 ++- .../indirect-calls-executor/src/executor.rs | 6 +- .../indirect-calls-executor/src/mock.rs | 13 +++- .../src/ocall/on_chain_ocall.rs | 42 ++++++++++- .../src/ocall_bridge/worker_on_chain_ocall.rs | 22 +++++- .../core-primitives/ocall-api/src/lib.rs | 11 +++ .../common/core-primitives/storage/Cargo.toml | 2 - .../core-primitives/storage/src/keys.rs | 8 +-- .../test/src/mock/onchain_mock.rs | 25 ++++++- .../common/core-primitives/types/src/lib.rs | 8 +++ .../types/src/parentchain/events.rs | 27 ++++++- .../types/src/parentchain/mod.rs | 18 ++++- .../app-libs/parentchain-interface/Cargo.toml | 3 + .../src/integritee/event_filter.rs | 4 ++ .../src/integritee/event_handler.rs | 55 ++++++++++++-- .../src/target_a/event_filter.rs | 28 +++----- .../src/target_a/event_handler.rs | 9 ++- .../src/target_b/event_filter.rs | 28 +++----- .../src/target_b/event_handler.rs | 9 ++- .../enclave-api/ffi/src/lib.rs | 2 + .../enclave-api/src/enclave_base.rs | 13 ++++ .../indirect-calls-executor/src/error.rs | 2 + .../indirect-calls-executor/src/executor.rs | 5 +- .../indirect-calls-executor/src/mock.rs | 13 +++- .../identity/enclave-runtime/Cargo.lock | 2 +- .../identity/enclave-runtime/Enclave.edl | 2 + .../enclave-runtime/src/initialization/mod.rs | 7 ++ .../identity/enclave-runtime/src/lib.rs | 9 +++ .../src/ocall/on_chain_ocall.rs | 42 ++++++++++- .../test/mocks/propose_to_import_call_mock.rs | 17 +++++ .../core/omni-account/src/in_memory_store.rs | 40 +++++++---- .../litentry/core/omni-account/src/lib.rs | 32 +++++++-- .../core/omni-account/src/repository.rs | 71 +++++++++++-------- tee-worker/identity/service/src/main_impl.rs | 5 ++ .../src/ocall_bridge/worker_on_chain_ocall.rs | 22 +++++- .../src/tests/mocks/enclave_api_mock.rs | 4 ++ 44 files changed, 596 insertions(+), 152 deletions(-) diff --git a/parachain/pallets/omni-account/src/lib.rs b/parachain/pallets/omni-account/src/lib.rs index 30d7a35fc3..a83d5a3204 100644 --- a/parachain/pallets/omni-account/src/lib.rs +++ b/parachain/pallets/omni-account/src/lib.rs @@ -140,7 +140,7 @@ pub mod pallet { /// Some member account is made public AccountMadePublic { who: T::AccountId, member_account_hash: H256 }, /// An account store is updated - AccountStoreUpdated { who: T::AccountId }, + AccountStoreUpdated { who: T::AccountId, account_store: MemberAccounts }, /// Some call is dispatched as omni-account origin DispatchedAsOmniAccount { who: T::AccountId, result: DispatchResult }, /// Some call is dispatched as signed origin @@ -245,7 +245,11 @@ pub mod pallet { MemberAccountHash::::insert(hash, who.clone()); AccountStore::::insert(who.clone(), member_accounts.clone()); - Self::deposit_event(Event::AccountAdded { who, member_account_hash: hash }); + Self::deposit_event(Event::AccountAdded { + who: who.clone(), + member_account_hash: hash, + }); + Self::deposit_event(Event::AccountStoreUpdated { who, account_store: member_accounts }); Ok(()) } @@ -276,10 +280,11 @@ pub mod pallet { if member_accounts.is_empty() { AccountStore::::remove(&who); } else { - AccountStore::::insert(who.clone(), member_accounts); + AccountStore::::insert(who.clone(), member_accounts.clone()); } - Self::deposit_event(Event::AccountRemoved { who, member_account_hashes }); + Self::deposit_event(Event::AccountRemoved { who: who.clone(), member_account_hashes }); + Self::deposit_event(Event::AccountStoreUpdated { who, account_store: member_accounts }); Ok(()) } @@ -300,9 +305,13 @@ pub mod pallet { .ok_or(Error::::AccountNotFound)?; *m = member_account.into(); - AccountStore::::insert(who.clone(), member_accounts); + AccountStore::::insert(who.clone(), member_accounts.clone()); - Self::deposit_event(Event::AccountMadePublic { who, member_account_hash: hash }); + Self::deposit_event(Event::AccountMadePublic { + who: who.clone(), + member_account_hash: hash, + }); + Self::deposit_event(Event::AccountStoreUpdated { who, account_store: member_accounts }); Ok(()) } @@ -339,8 +348,11 @@ pub mod pallet { } MemberAccountHash::::insert(member_account.hash(), who_account.clone()); - AccountStore::::insert(who_account.clone(), member_accounts); - Self::deposit_event(Event::AccountStoreUpdated { who: who_account }); + AccountStore::::insert(who_account.clone(), member_accounts.clone()); + Self::deposit_event(Event::AccountStoreUpdated { + who: who_account, + account_store: member_accounts, + }); Ok(Pays::No.into()) } @@ -386,7 +398,11 @@ pub mod pallet { MemberAccountHash::::insert(hash, omni_account.clone()); AccountStore::::insert(omni_account.clone(), member_accounts.clone()); - Self::deposit_event(Event::AccountStoreCreated { who: omni_account }); + Self::deposit_event(Event::AccountStoreCreated { who: omni_account.clone() }); + Self::deposit_event(Event::AccountStoreUpdated { + who: omni_account, + account_store: member_accounts.clone(), + }); Ok(member_accounts) } diff --git a/parachain/pallets/omni-account/src/tests.rs b/parachain/pallets/omni-account/src/tests.rs index 4cce2aa707..1a7a53076f 100644 --- a/parachain/pallets/omni-account/src/tests.rs +++ b/parachain/pallets/omni-account/src/tests.rs @@ -57,7 +57,17 @@ fn create_account_store_works() { alice().identity, )); - System::assert_last_event(Event::AccountStoreCreated { who: alice().omni_account }.into()); + let member_accounts: MemberAccounts = + vec![public_member_account(alice())].try_into().unwrap(); + + System::assert_has_event(Event::AccountStoreCreated { who: alice().omni_account }.into()); + System::assert_last_event( + Event::AccountStoreUpdated { + who: alice().omni_account, + account_store: member_accounts, + } + .into(), + ); // create it the second time will fail assert_noop!( @@ -114,6 +124,13 @@ fn add_account_works() { } .into(), ); + System::assert_has_event( + Event::AccountStoreUpdated { + who: alice().omni_account.clone(), + account_store: expected_member_accounts.clone(), + } + .into(), + ); assert_eq!( AccountStore::::get(alice().omni_account).unwrap(), @@ -126,20 +143,23 @@ fn add_account_works() { alice().identity.hash(), call, )); + let expected_member_accounts: MemberAccounts = + BoundedVec::truncate_from(vec![ + public_member_account(alice()), + bob.clone(), + charlie.clone(), + ]); System::assert_has_event( Event::AccountAdded { who: alice().omni_account, member_account_hash: charlie.hash() } .into(), ); - - let expected_member_accounts: MemberAccounts = - vec![public_member_account(alice()), bob.clone(), charlie.clone()] - .try_into() - .unwrap(); - - assert_eq!( - AccountStore::::get(alice().omni_account).unwrap(), - expected_member_accounts + System::assert_has_event( + Event::AccountStoreUpdated { + who: alice().omni_account, + account_store: expected_member_accounts.clone(), + } + .into(), ); assert!(MemberAccountHash::::contains_key(bob.hash())); @@ -324,6 +344,9 @@ fn remove_account_works() { .into(), ); + let expected_member_accounts: MemberAccounts = + BoundedVec::truncate_from(vec![public_member_account(alice())]); + System::assert_has_event( Event::AccountRemoved { who: alice().omni_account, @@ -331,9 +354,13 @@ fn remove_account_works() { } .into(), ); - - let expected_member_accounts: MemberAccounts = - vec![public_member_account(alice())].try_into().unwrap(); + System::assert_has_event( + Event::AccountStoreUpdated { + who: alice().omni_account, + account_store: expected_member_accounts.clone(), + } + .into(), + ); assert_eq!( AccountStore::::get(alice().omni_account).unwrap(), @@ -432,16 +459,24 @@ fn publicize_account_works() { .into(), ); + let expected_member_accounts: MemberAccounts = + BoundedVec::truncate_from(vec![public_member_account(alice()), public_bob]); + System::assert_has_event( Event::AccountMadePublic { who: alice().omni_account, - member_account_hash: public_bob.hash(), + member_account_hash: bob().identity.hash(), + } + .into(), + ); + System::assert_has_event( + Event::AccountStoreUpdated { + who: alice().omni_account, + account_store: expected_member_accounts.clone(), } .into(), ); - let expected_member_accounts: MemberAccounts = - vec![public_member_account(alice()), public_bob].try_into().unwrap(); assert_eq!( AccountStore::::get(alice().omni_account).unwrap(), expected_member_accounts diff --git a/tee-worker/Cargo.lock b/tee-worker/Cargo.lock index fe5f008fd2..c7d79df281 100644 --- a/tee-worker/Cargo.lock +++ b/tee-worker/Cargo.lock @@ -3273,6 +3273,7 @@ dependencies = [ "itp-types", "lc-dynamic-assertion", "lc-evm-dynamic-assertions", + "lc-omni-account", "litentry-primitives", "log 0.4.20", "parity-scale-codec", @@ -4319,7 +4320,6 @@ dependencies = [ "frame-support", "hash-db 0.15.2", "itp-types", - "litentry-hex-utils", "parity-scale-codec", "sgx_tstd", "sp-core", 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..b7ceeb561a 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,8 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_account_store_updated_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..e26c697c32 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::{Block as ParentchainBlock, Header as ParentchainHeader}; use sp_std::vec::Vec; use std::string::ToString; @@ -129,11 +130,15 @@ where { type Output = Vec; - fn handle_events( + fn handle_events( &self, executor: &Executor, events: impl FilterEvents, - ) -> Result, Error> { + _block_number: <::Header as ParentchainHeader>::Number, + ) -> Result, Error> + where + Block: ParentchainBlock, + { let mut handled_events: Vec = Vec::new(); if let Ok(events) = events.get_relayer_added_events() { 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..33c0278536 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,8 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_account_store_updated_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..12b6eb40a7 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::{Block as ParentchainBlock, Header as ParentchainHeader}; use std::vec::Vec; pub struct ParentchainEventHandler {} @@ -52,11 +53,15 @@ where { type Output = Vec; - fn handle_events( + fn handle_events( &self, _executor: &Executor, _events: impl FilterEvents, - ) -> Result, Error> { + _block_number: <::Header as ParentchainHeader>::Number, + ) -> Result, Error> + where + Block: ParentchainBlock, + { 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..33c0278536 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,8 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_account_store_updated_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..f3ab23f2a1 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::{Block as ParentchainBlock, Header as ParentchainHeader}; use std::vec::Vec; pub struct ParentchainEventHandler {} @@ -52,11 +53,15 @@ where { type Output = Vec; - fn handle_events( + fn handle_events( &self, _executor: &Executor, _events: impl FilterEvents, - ) -> Result, Error> { + _block_number: <::Header as ParentchainHeader>::Number, + ) -> Result, Error> + where + Block: ParentchainBlock, + { 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..216391bda8 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,11 @@ 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_number, + )?; 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..7b17d920fb 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 @@ -19,6 +19,7 @@ use itp_types::{ Address, RsaRequest, ShardIdentifier, H256, }; use log::*; +use sp_runtime::traits::{Block as ParentchainBlock, Header as ParentchainHeader}; use std::vec::Vec; pub struct ExtrinsicParser { @@ -196,6 +197,10 @@ impl FilterEvents for MockEvents { ) -> Result, Self::Error> { Ok(Vec::new()) } + + fn get_account_store_updated_events(&self) -> Result, Self::Error> { + Ok(Vec::new()) + } } pub struct MockParentchainEventHandler {} @@ -220,11 +225,15 @@ where { type Output = Vec; - fn handle_events( + fn handle_events( &self, _: &Executor, _: impl itp_types::parentchain::FilterEvents, - ) -> core::result::Result, Error> { + _block_number: <::Header as ParentchainHeader>::Number, + ) -> core::result::Result, Error> + where + Block: ParentchainBlock, + { Ok(Vec::from([H256::default()])) } } diff --git a/tee-worker/bitacross/enclave-runtime/src/ocall/on_chain_ocall.rs b/tee-worker/bitacross/enclave-runtime/src/ocall/on_chain_ocall.rs index 124f7fabd9..98ba9e9e33 100644 --- a/tee-worker/bitacross/enclave-runtime/src/ocall/on_chain_ocall.rs +++ b/tee-worker/bitacross/enclave-runtime/src/ocall/on_chain_ocall.rs @@ -19,7 +19,7 @@ use crate::ocall::{ffi, OcallApi}; use codec::{Decode, Encode}; use frame_support::ensure; -use itp_ocall_api::{EnclaveOnChainOCallApi, Result}; +use itp_ocall_api::{EnclaveOnChainOCallApi, Error, Result}; use itp_storage::{verify_storage_entries, Error as StorageError}; use itp_types::{ parentchain::ParentchainId, storage::StorageEntryVerified, WorkerRequest, WorkerResponse, H256, @@ -146,4 +146,44 @@ impl EnclaveOnChainOCallApi for OcallApi { let first_response = responses.get(0).ok_or(StorageError::WrongValue)?; Ok(first_response.clone()) } + + fn get_storage_keys_paged>( + &self, + key_prefix: Vec, + count: u32, + start_key: Option>, + header: Option<&H>, + ) -> Result>> { + let header_hash = header.map(|h| h.hash()); + let requests = + vec![WorkerRequest::ChainStorageKeysPaged(key_prefix, count, start_key, header_hash)]; + + let responses: Vec>> = self + .worker_request::>(requests, &ParentchainId::Litentry)? + .iter() + .filter_map(|r| match r { + WorkerResponse::ChainStorageKeys(k) => Some(k.clone()), + _ => None, + }) + .collect(); + + // we should only have one response as we only sent one request + let first_response = responses.get(0).ok_or(StorageError::WrongValue)?; + Ok(first_response.clone()) + } + + fn get_header>(&self, parentchain_id: &ParentchainId) -> Result { + let request = vec![WorkerRequest::ChainHeader(None)]; + let responses: Vec = self + .worker_request::>(request, parentchain_id)? + .iter() + .filter_map(|r| match r { + WorkerResponse::ChainHeader(Some(h)) => + Some(Decode::decode(&mut h.as_slice()).ok()?), + _ => None, + }) + .collect(); + + responses.first().cloned().ok_or(Error::ChainCallFailed) + } } diff --git a/tee-worker/bitacross/service/src/ocall_bridge/worker_on_chain_ocall.rs b/tee-worker/bitacross/service/src/ocall_bridge/worker_on_chain_ocall.rs index 3e1b181b78..e5c1134c27 100644 --- a/tee-worker/bitacross/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/tee-worker/bitacross/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -26,7 +26,8 @@ use log::*; use sp_runtime::OpaqueExtrinsic; use std::{sync::Arc, thread, vec::Vec}; use substrate_api_client::{ - ac_primitives::serde_impls::StorageKey, GetStorage, SubmitAndWatch, SubmitExtrinsic, XtStatus, + ac_primitives::serde_impls::StorageKey, GetChainInfo, GetStorage, SubmitAndWatch, + SubmitExtrinsic, XtStatus, }; #[cfg(feature = "link-binary")] @@ -112,6 +113,25 @@ where }; WorkerResponse::ChainStorageKeys(keys) }, + WorkerRequest::ChainStorageKeysPaged(prefix, count, start_key, hash) => { + let keys: Vec> = match api.get_storage_keys_paged( + Some(StorageKey(prefix)), + count, + start_key.map(StorageKey), + hash, + ) { + Ok(keys) => keys.iter().map(|k| k.0.to_vec()).collect(), + _ => Default::default(), + }; + WorkerResponse::ChainStorageKeys(keys) + }, + WorkerRequest::ChainHeader(block_hash) => { + let header = match api.get_header(block_hash) { + Ok(Some(header)) => Some(header.encode()), + _ => None, + }; + WorkerResponse::ChainHeader(header) + }, }) .collect(); diff --git a/tee-worker/common/core-primitives/ocall-api/src/lib.rs b/tee-worker/common/core-primitives/ocall-api/src/lib.rs index ca5090e88c..4c54ffc130 100644 --- a/tee-worker/common/core-primitives/ocall-api/src/lib.rs +++ b/tee-worker/common/core-primitives/ocall-api/src/lib.rs @@ -38,6 +38,7 @@ pub enum Error { Storage(StorageError), Codec(codec::Error), Sgx(sgx_types::sgx_status_t), + ChainCallFailed, } pub type Result = StdResult; @@ -123,6 +124,16 @@ pub trait EnclaveOnChainOCallApi: Clone + Send + Sync { key_prefix: Vec, header: Option<&H>, ) -> Result>>; + + fn get_storage_keys_paged>( + &self, + key_prefix: Vec, + count: u32, + start_key: Option>, + header: Option<&H>, + ) -> Result>>; + + fn get_header>(&self, parentchain_id: &ParentchainId) -> Result; } /// Trait for sending metric updates. diff --git a/tee-worker/common/core-primitives/storage/Cargo.toml b/tee-worker/common/core-primitives/storage/Cargo.toml index 72659e1b52..d3c48d6e05 100644 --- a/tee-worker/common/core-primitives/storage/Cargo.toml +++ b/tee-worker/common/core-primitives/storage/Cargo.toml @@ -23,8 +23,6 @@ sp-trie = { workspace = true } itp-types = { workspace = true } -litentry-hex-utils = { workspace = true } - [dev-dependencies] sp-state-machine = { workspace = true, features = ["std"] } diff --git a/tee-worker/common/core-primitives/storage/src/keys.rs b/tee-worker/common/core-primitives/storage/src/keys.rs index 5771bd8c03..84387d0c64 100644 --- a/tee-worker/common/core-primitives/storage/src/keys.rs +++ b/tee-worker/common/core-primitives/storage/src/keys.rs @@ -15,11 +15,10 @@ */ -use alloc::{string::String, vec::Vec}; +use alloc::vec::Vec; use codec::{Decode, Encode}; use frame_metadata::v14::StorageHasher; use frame_support::{Blake2_128Concat, ReversibleStorageHasher}; -use litentry_hex_utils::decode_hex; pub fn storage_value_key(module_prefix: &str, storage_prefix: &str) -> Vec { let mut bytes = sp_core::twox_128(module_prefix.as_bytes()).to_vec(); @@ -44,11 +43,6 @@ pub fn extract_blake2_128concat_key(raw_storage_key: &[u8]) -> Option K::decode(&mut raw_key).ok() } -pub 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() -} - pub fn storage_double_map_key( module_prefix: &str, storage_prefix: &str, diff --git a/tee-worker/common/core-primitives/test/src/mock/onchain_mock.rs b/tee-worker/common/core-primitives/test/src/mock/onchain_mock.rs index 021875620e..0e9b212e6d 100644 --- a/tee-worker/common/core-primitives/test/src/mock/onchain_mock.rs +++ b/tee-worker/common/core-primitives/test/src/mock/onchain_mock.rs @@ -30,10 +30,16 @@ use itp_types::{ use lc_teebag_storage::{TeebagStorage, TeebagStorageKeys}; use sgx_types::*; use sp_core::H256; -use sp_runtime::{traits::Header as HeaderTrait, OpaqueExtrinsic}; +use sp_runtime::{ + traits::{BlakeTwo256, Header as HeaderTrait}, + OpaqueExtrinsic, +}; use sp_std::prelude::*; use std::{collections::HashMap, string::String}; +type BlockNumber = u32; +pub type GenericHeader = sp_runtime::generic::Header; + #[derive(Default, Clone, Debug)] pub struct OnchainMock { inner: HashMap, Vec>, @@ -230,6 +236,23 @@ impl EnclaveOnChainOCallApi for OnchainMock { ) -> Result>, itp_ocall_api::Error> { Ok(Default::default()) } + + fn get_storage_keys_paged>( + &self, + _key_prefix: Vec, + _count: u32, + _start_key: Option>, + _header: Option<&H>, + ) -> itp_ocall_api::Result>> { + Ok(Default::default()) + } + + fn get_header>( + &self, + _: &ParentchainId, + ) -> itp_ocall_api::Result { + todo!() + } } pub fn validateer_set() -> Vec { diff --git a/tee-worker/common/core-primitives/types/src/lib.rs b/tee-worker/common/core-primitives/types/src/lib.rs index d60fa6f08a..da2b66d6da 100644 --- a/tee-worker/common/core-primitives/types/src/lib.rs +++ b/tee-worker/common/core-primitives/types/src/lib.rs @@ -18,6 +18,8 @@ #![cfg_attr(all(not(target_env = "sgx"), not(feature = "std")), no_std)] #![cfg_attr(target_env = "sgx", feature(rustc_private))] +extern crate alloc; + use crate::storage::StorageEntry; use codec::{Decode, Encode}; use itp_sgx_crypto::ShieldingCryptoDecrypt; @@ -146,6 +148,10 @@ pub enum WorkerRequest { ChainStorage(Vec, Option), // (storage_key, at_block) #[codec(index = 1)] ChainStorageKeys(Vec, Option), // (storage_key_prefix, at_block) + #[codec(index = 2)] + ChainStorageKeysPaged(Vec, u32, Option>, Option), // (storage_key_prefix, count, start_key, at_block) + #[codec(index = 3)] + ChainHeader(Option), // (at_block) } #[derive(Encode, Decode, Clone, Debug, PartialEq)] @@ -154,6 +160,8 @@ pub enum WorkerResponse { ChainStorage(Vec, Option, Option>>), // (storage_key, storage_value, storage_proof) #[codec(index = 1)] ChainStorageKeys(Vec>), // (storage_keys) + #[codec(index = 2)] + ChainHeader(Option), // (header) } impl From>> for StorageEntry> { 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 e013f159b1..57205832ed 100644 --- a/tee-worker/common/core-primitives/types/src/parentchain/events.rs +++ b/tee-worker/common/core-primitives/types/src/parentchain/events.rs @@ -1,12 +1,12 @@ -use super::alloc::{format, vec::Vec}; use crate::{ AccountId, Assertion, Balance, BlockNumber, Hash, MrEnclave, RsaRequest, ShardIdentifier, WorkerType, }; +use alloc::{format, vec::Vec}; use codec::{Decode, Encode}; use core::fmt::Debug; use itp_utils::{hex::ToHexPrefixed, stringify::account_id_to_string}; -use litentry_primitives::{Address32, Identity}; +use litentry_primitives::{Address32, Identity, MemberAccount}; use sp_core::H160; use substrate_api_client::ac_node_api::StaticEvent; @@ -139,6 +139,29 @@ impl StaticEvent for EnclaveRemoved { const EVENT: &'static str = "EnclaveRemoved"; } +// omni-account pallet events +#[derive(Encode, Decode, Debug)] +pub struct AccountStoreUpdated { + pub who: AccountId, + pub account_store: Vec, +} + +impl core::fmt::Display for AccountStoreUpdated { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + let message = format!( + "AccountStoreCreated :: who: {}, account_store: {:?}", + account_id_to_string::(&self.who), + self.account_store + ); + write!(f, "{}", message) + } +} + +impl StaticEvent for AccountStoreUpdated { + const PALLET: &'static str = "OmniAccount"; + const EVENT: &'static str = "AccountStoreUpdated"; +} + // Identity-worker events #[derive(Encode, Decode, Debug)] 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..05172aabd5 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, Block as ParentchainBlock, Header as ParentchainHeader}, + MultiAddress, MultiSignature, +}; use self::events::ParentchainBlockProcessed; @@ -123,6 +127,8 @@ pub trait FilterEvents { fn get_enclave_removed_events(&self) -> Result, Self::Error>; fn get_btc_wallet_generated_events(&self) -> Result, Self::Error>; + + fn get_account_store_updated_events(&self) -> Result, Self::Error>; } #[derive(Debug)] @@ -140,11 +146,14 @@ where { type Output; - fn handle_events( + fn handle_events( &self, executor: &Executor, events: impl FilterEvents, - ) -> Result; + block_number: <::Header as ParentchainHeader>::Number, + ) -> Result + where + Block: ParentchainBlock; } #[derive(Debug)] @@ -163,6 +172,7 @@ pub enum ParentchainEventProcessingError { EnclaveAddFailure, EnclaveRemoveFailure, BtcWalletGeneratedFailure, + AccountStoreUpdatedFailure, } impl core::fmt::Display for ParentchainEventProcessingError { @@ -196,6 +206,8 @@ impl core::fmt::Display for ParentchainEventProcessingError { "Parentchain Event Processing Error: EnclaveRemoveFailure", ParentchainEventProcessingError::BtcWalletGeneratedFailure => "Parentchain Event Processing Error: BtcWalletGeneratedFailure", + ParentchainEventProcessingError::AccountStoreUpdatedFailure => + "Parentchain Event Processing Error: AccountStoreUpdatedFailure", }; write!(f, "{}", message) } diff --git a/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml b/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml index 3718f96eb0..065d23ae7c 100644 --- a/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml +++ b/tee-worker/identity/app-libs/parentchain-interface/Cargo.toml @@ -27,6 +27,7 @@ substrate-api-client = { workspace = true, optional = true } lc-dynamic-assertion = { workspace = true } lc-evm-dynamic-assertions = { workspace = true } +lc-omni-account = { workspace = true } litentry-primitives = { workspace = true } [dev-dependencies] @@ -61,6 +62,7 @@ std = [ "lc-dynamic-assertion/std", "lc-evm-dynamic-assertions/std", "sp-std/std", + "lc-omni-account/std", ] sgx = [ "sgx_tstd", @@ -73,4 +75,5 @@ sgx = [ "litentry-primitives/sgx", "lc-dynamic-assertion/sgx", "lc-evm-dynamic-assertions/sgx", + "lc-omni-account/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..f0ae6078dc 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 @@ -117,4 +117,8 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_account_store_updated_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..39569551cd 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 @@ -19,22 +19,23 @@ use codec::{Decode, Encode}; pub use ita_sgx_runtime::{Balance, Index}; 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_stf_primitives::{traits::IndirectExecutor, types::TrustedOperation}; use itp_types::{ parentchain::{ - events::ParentchainBlockProcessed, AccountId, FilterEvents, HandleParentchainEvents, + AccountId, BlockNumber, FilterEvents, HandleParentchainEvents, ParentchainEventProcessingError, ProcessedEventsArtifacts, }, RsaRequest, H256, }; use lc_dynamic_assertion::AssertionLogicRepository; use lc_evm_dynamic_assertions::repository::EvmAssertionRepository; -use litentry_primitives::{Assertion, Identity, ValidationData, Web3Network}; +use lc_omni_account::InMemoryStore as OmniAccountStore; +use litentry_primitives::{Assertion, Identity, MemberAccount, ValidationData, Web3Network}; use log::*; use sp_core::{blake2_256, H160}; +use sp_runtime::traits::{Block as ParentchainBlockTrait, Header as ParentchainHeader}; use sp_std::vec::Vec; use std::{format, string::String, sync::Arc, time::Instant}; @@ -219,6 +220,28 @@ where Ok(()) } + + fn update_account_store( + account_id: AccountId, + members: Vec, + block_number: BlockNumber, + ) -> Result<(), Error> { + let last_block_number = OmniAccountStore::get_block_height().map_err(|e| { + Error::AccountStoreError(format!( + "Could not get last block number from account store, reason: {:?}", + e + )) + })?; + if block_number <= last_block_number { + return Ok(()) + } + OmniAccountStore::insert_account_store(account_id.clone(), members).map_err(|e| { + Error::AccountStoreError(format!( + "Could not update account store for account_id: {:?}, reason: {:?}", + account_id, e + )) + }) + } } impl HandleParentchainEvents @@ -228,11 +251,19 @@ where MetricsApi: EnclaveMetricsOCallApi, { type Output = ProcessedEventsArtifacts; - fn handle_events( + + fn handle_events( &self, executor: &Executor, events: impl FilterEvents, - ) -> Result { + block_number: <::Header as ParentchainHeader>::Number, + ) -> Result + where + Block: ParentchainBlockTrait, + { + let block_number: BlockNumber = block_number + .try_into() + .map_err(|_| ParentchainEventProcessingError::ParentchainBlockProcessedFailure)?; let mut handled_events: Vec = Vec::new(); let mut successful_assertion_ids: Vec = Vec::new(); let mut failed_assertion_ids: Vec = Vec::new(); @@ -346,10 +377,22 @@ where events.iter().for_each(|event| { debug!("found ParentchainBlockProcessed event: {:?}", event); // This is for monitoring purposes - handled_events.push(hash_of(ParentchainBlockProcessed::EVENT)); + handled_events.push(hash_of(&event)); }); } + if let Ok(events) = events.get_account_store_updated_events() { + debug!("Handling AccountStoreUpdated events"); + events + .into_iter() + .try_for_each(|event| { + debug!("found AccountStoreUpdated event: {:?}", event); + handled_events.push(hash_of(&event)); + Self::update_account_store(event.who, event.account_store, block_number) + }) + .map_err(|_| ParentchainEventProcessingError::AccountStoreUpdatedFailure)?; + } + 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..4b86a285e8 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 @@ -60,39 +60,29 @@ impl From> for FilterableEvents { impl FilterEvents for FilterableEvents { type Error = itc_parentchain_indirect_calls_executor::Error; - fn get_link_identity_events( - &self, - ) -> Result, Self::Error> { + fn get_link_identity_events(&self) -> Result, Self::Error> { self.filter() } - fn get_vc_requested_events( - &self, - ) -> Result, Self::Error> { + fn get_vc_requested_events(&self) -> Result, Self::Error> { self.filter() } fn get_deactivate_identity_events( &self, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { self.filter() } - fn get_activate_identity_events( - &self, - ) -> Result, Self::Error> { + fn get_activate_identity_events(&self) -> Result, Self::Error> { self.filter() } - fn get_enclave_unauthorized_events( - &self, - ) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { self.filter() } - fn get_opaque_task_posted_events( - &self, - ) -> Result, Self::Error> { + fn get_opaque_task_posted_events(&self) -> Result, Self::Error> { self.filter() } @@ -102,7 +92,7 @@ impl FilterEvents for FilterableEvents { fn get_parentchain_block_proccessed_events( &self, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { Ok(Vec::new()) } @@ -125,4 +115,8 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_account_store_updated_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..e288b5a0bb 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::{Block as ParentchainBlock, Header as ParentchainHeader}; use sp_std::vec::Vec; pub struct ParentchainEventHandler {} @@ -32,11 +33,15 @@ where Executor: IndirectExecutor, { type Output = ProcessedEventsArtifacts; - fn handle_events( + fn handle_events( &self, _executor: &Executor, _events: impl FilterEvents, - ) -> Result { + _block_number: <::Header as ParentchainHeader>::Number, + ) -> Result + where + Block: ParentchainBlock, + { 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..4b86a285e8 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 @@ -60,39 +60,29 @@ impl From> for FilterableEvents { impl FilterEvents for FilterableEvents { type Error = itc_parentchain_indirect_calls_executor::Error; - fn get_link_identity_events( - &self, - ) -> Result, Self::Error> { + fn get_link_identity_events(&self) -> Result, Self::Error> { self.filter() } - fn get_vc_requested_events( - &self, - ) -> Result, Self::Error> { + fn get_vc_requested_events(&self) -> Result, Self::Error> { self.filter() } fn get_deactivate_identity_events( &self, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { self.filter() } - fn get_activate_identity_events( - &self, - ) -> Result, Self::Error> { + fn get_activate_identity_events(&self) -> Result, Self::Error> { self.filter() } - fn get_enclave_unauthorized_events( - &self, - ) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { self.filter() } - fn get_opaque_task_posted_events( - &self, - ) -> Result, Self::Error> { + fn get_opaque_task_posted_events(&self) -> Result, Self::Error> { self.filter() } @@ -102,7 +92,7 @@ impl FilterEvents for FilterableEvents { fn get_parentchain_block_proccessed_events( &self, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { Ok(Vec::new()) } @@ -125,4 +115,8 @@ impl FilterEvents for FilterableEvents { fn get_btc_wallet_generated_events(&self) -> Result, Self::Error> { self.filter() } + + fn get_account_store_updated_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..be64ba5b1b 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::{Block as ParentchainBlock, Header as ParentchainHeader}; use sp_std::vec::Vec; pub struct ParentchainEventHandler {} @@ -32,11 +33,15 @@ where Executor: IndirectExecutor, { type Output = ProcessedEventsArtifacts; - fn handle_events( + fn handle_events( &self, _executor: &Executor, _events: impl FilterEvents, - ) -> Result { + _block_number: <::Header as ParentchainHeader>::Number, + ) -> Result + where + Block: ParentchainBlock, + { debug!("not handling any events for target B"); Ok((Vec::new(), Vec::new(), Vec::new())) } diff --git a/tee-worker/identity/core-primitives/enclave-api/ffi/src/lib.rs b/tee-worker/identity/core-primitives/enclave-api/ffi/src/lib.rs index cf755efcc1..bfe689de8f 100644 --- a/tee-worker/identity/core-primitives/enclave-api/ffi/src/lib.rs +++ b/tee-worker/identity/core-primitives/enclave-api/ffi/src/lib.rs @@ -238,6 +238,8 @@ extern "C" { shard_size: u32, ) -> sgx_status_t; + pub fn init_in_memory_state(eid: sgx_enclave_id_t, retval: *mut sgx_status_t) -> sgx_status_t; + pub fn upload_id_graph(eid: sgx_enclave_id_t, retval: *mut sgx_status_t) -> sgx_status_t; pub fn ignore_parentchain_block_import_validation_until( diff --git a/tee-worker/identity/core-primitives/enclave-api/src/enclave_base.rs b/tee-worker/identity/core-primitives/enclave-api/src/enclave_base.rs index 69e8a0c9eb..f7a8c8e53e 100644 --- a/tee-worker/identity/core-primitives/enclave-api/src/enclave_base.rs +++ b/tee-worker/identity/core-primitives/enclave-api/src/enclave_base.rs @@ -83,6 +83,8 @@ pub trait EnclaveBase: Send + Sync + 'static { // litentry fn migrate_shard(&self, new_shard: Vec) -> EnclaveResult<()>; + fn init_in_memory_state(&self) -> EnclaveResult<()>; + fn upload_id_graph(&self) -> EnclaveResult<()>; } @@ -391,6 +393,17 @@ mod impl_ffi { Ok(()) } + fn init_in_memory_state(&self) -> EnclaveResult<()> { + let mut retval = sgx_status_t::SGX_SUCCESS; + + let result = unsafe { ffi::init_in_memory_state(self.eid, &mut retval) }; + + ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result)); + ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval)); + + Ok(()) + } + fn upload_id_graph(&self) -> EnclaveResult<()> { let mut retval = sgx_status_t::SGX_SUCCESS; diff --git a/tee-worker/identity/core/parentchain/indirect-calls-executor/src/error.rs b/tee-worker/identity/core/parentchain/indirect-calls-executor/src/error.rs index e5e51eae13..ef745e930f 100644 --- a/tee-worker/identity/core/parentchain/indirect-calls-executor/src/error.rs +++ b/tee-worker/identity/core/parentchain/indirect-calls-executor/src/error.rs @@ -53,6 +53,8 @@ pub enum Error { BatchAllHandlingError, #[error("AssertionCreated handling error: {0:?}")] AssertionCreatedHandling(String), + #[error("AccountStore error: {0:?}")] + AccountStoreError(String), } impl From for Error { 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..e8a24a10e4 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_number)?; 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..25cab5b0e6 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::{Block as ParentchainBlock, Header as ParentchainHeader}; use std::vec::Vec; pub struct TestEventCreator; @@ -84,6 +85,10 @@ impl FilterEvents for MockEvents { fn get_relayers_removed_events(&self) -> Result, Self::Error> { Ok(Vec::new()) } + + fn get_account_store_updated_events(&self) -> Result, Self::Error> { + Ok(Vec::new()) + } } pub struct MockParentchainEventHandler {} @@ -94,11 +99,15 @@ where Executor: IndirectExecutor, { type Output = ProcessedEventsArtifacts; - fn handle_events( + fn handle_events( &self, _: &Executor, _: impl FilterEvents, - ) -> Result { + _block_number: <::Header as ParentchainHeader>::Number, + ) -> Result + where + Block: ParentchainBlock, + { Ok(( Vec::from([H256::default()]), Vec::from([H160::default()]), diff --git a/tee-worker/identity/enclave-runtime/Cargo.lock b/tee-worker/identity/enclave-runtime/Cargo.lock index 0a028e44d7..d70370871b 100644 --- a/tee-worker/identity/enclave-runtime/Cargo.lock +++ b/tee-worker/identity/enclave-runtime/Cargo.lock @@ -1811,6 +1811,7 @@ dependencies = [ "itp-types", "lc-dynamic-assertion", "lc-evm-dynamic-assertions", + "lc-omni-account", "litentry-primitives", "log", "parity-scale-codec", @@ -2604,7 +2605,6 @@ dependencies = [ "frame-support", "hash-db 0.15.2", "itp-types", - "litentry-hex-utils", "parity-scale-codec", "sgx_tstd", "sp-core", diff --git a/tee-worker/identity/enclave-runtime/Enclave.edl b/tee-worker/identity/enclave-runtime/Enclave.edl index 94c1be5f1c..59a995aed3 100644 --- a/tee-worker/identity/enclave-runtime/Enclave.edl +++ b/tee-worker/identity/enclave-runtime/Enclave.edl @@ -61,6 +61,8 @@ enclave { [in, size=shard_size] uint8_t* shard, uint32_t shard_size ); + public sgx_status_t init_in_memory_state(); + public sgx_status_t init_shard_creation_parentchain_header( [in, size=shard_size] uint8_t* shard, uint32_t shard_size, [in, size=parentchain_id_size] uint8_t* parentchain_id, uint32_t parentchain_id_size, diff --git a/tee-worker/identity/enclave-runtime/src/initialization/mod.rs b/tee-worker/identity/enclave-runtime/src/initialization/mod.rs index 263ae6b0b3..b14d42c6c9 100644 --- a/tee-worker/identity/enclave-runtime/src/initialization/mod.rs +++ b/tee-worker/identity/enclave-runtime/src/initialization/mod.rs @@ -96,6 +96,7 @@ use jsonrpc_core::IoHandler; use lc_data_providers::DataProviderConfig; use lc_evm_dynamic_assertions::repository::EvmAssertionRepository; use lc_native_task_receiver::{run_native_task_receiver, NativeTaskContext}; +use lc_omni_account::init_in_memory_omni_account_store; use lc_parachain_extrinsic_task_receiver::run_parachain_extrinsic_task_receiver; use lc_stf_task_receiver::{run_stf_task_receiver, StfTaskContext}; use lc_vc_task_receiver::run_vc_handler_runner; @@ -517,6 +518,12 @@ pub(crate) fn init_shard(shard: ShardIdentifier) -> EnclaveResult<()> { Ok(()) } +pub(crate) fn init_in_memory_state() -> EnclaveResult<()> { + let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; + init_in_memory_omni_account_store(ocall_api).map_err(|e| Error::Other(e.into()))?; + Ok(()) +} + pub(crate) fn migrate_shard(new_shard: ShardIdentifier) -> EnclaveResult<()> { let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; let _ = state_handler.migrate_shard(new_shard)?; diff --git a/tee-worker/identity/enclave-runtime/src/lib.rs b/tee-worker/identity/enclave-runtime/src/lib.rs index d1486b62cf..ba0670d6c7 100644 --- a/tee-worker/identity/enclave-runtime/src/lib.rs +++ b/tee-worker/identity/enclave-runtime/src/lib.rs @@ -445,6 +445,15 @@ pub unsafe extern "C" fn migrate_shard(new_shard: *const u8, shard_size: u32) -> sgx_status_t::SGX_SUCCESS } +#[no_mangle] +pub unsafe extern "C" fn init_in_memory_state() -> sgx_status_t { + if let Err(e) = initialization::init_in_memory_state() { + error!("Failed to initialize in-memory state: {:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + } + sgx_status_t::SGX_SUCCESS +} + #[no_mangle] pub unsafe extern "C" fn upload_id_graph() -> sgx_status_t { if let Err(e) = initialization::upload_id_graph() { diff --git a/tee-worker/identity/enclave-runtime/src/ocall/on_chain_ocall.rs b/tee-worker/identity/enclave-runtime/src/ocall/on_chain_ocall.rs index 124f7fabd9..98ba9e9e33 100644 --- a/tee-worker/identity/enclave-runtime/src/ocall/on_chain_ocall.rs +++ b/tee-worker/identity/enclave-runtime/src/ocall/on_chain_ocall.rs @@ -19,7 +19,7 @@ use crate::ocall::{ffi, OcallApi}; use codec::{Decode, Encode}; use frame_support::ensure; -use itp_ocall_api::{EnclaveOnChainOCallApi, Result}; +use itp_ocall_api::{EnclaveOnChainOCallApi, Error, Result}; use itp_storage::{verify_storage_entries, Error as StorageError}; use itp_types::{ parentchain::ParentchainId, storage::StorageEntryVerified, WorkerRequest, WorkerResponse, H256, @@ -146,4 +146,44 @@ impl EnclaveOnChainOCallApi for OcallApi { let first_response = responses.get(0).ok_or(StorageError::WrongValue)?; Ok(first_response.clone()) } + + fn get_storage_keys_paged>( + &self, + key_prefix: Vec, + count: u32, + start_key: Option>, + header: Option<&H>, + ) -> Result>> { + let header_hash = header.map(|h| h.hash()); + let requests = + vec![WorkerRequest::ChainStorageKeysPaged(key_prefix, count, start_key, header_hash)]; + + let responses: Vec>> = self + .worker_request::>(requests, &ParentchainId::Litentry)? + .iter() + .filter_map(|r| match r { + WorkerResponse::ChainStorageKeys(k) => Some(k.clone()), + _ => None, + }) + .collect(); + + // we should only have one response as we only sent one request + let first_response = responses.get(0).ok_or(StorageError::WrongValue)?; + Ok(first_response.clone()) + } + + fn get_header>(&self, parentchain_id: &ParentchainId) -> Result { + let request = vec![WorkerRequest::ChainHeader(None)]; + let responses: Vec = self + .worker_request::>(request, parentchain_id)? + .iter() + .filter_map(|r| match r { + WorkerResponse::ChainHeader(Some(h)) => + Some(Decode::decode(&mut h.as_slice()).ok()?), + _ => None, + }) + .collect(); + + responses.first().cloned().ok_or(Error::ChainCallFailed) + } } diff --git a/tee-worker/identity/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs b/tee-worker/identity/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs index 67a1b4ea64..a9f7ff9806 100644 --- a/tee-worker/identity/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs +++ b/tee-worker/identity/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs @@ -91,6 +91,23 @@ impl EnclaveOnChainOCallApi for ProposeToImportOCallApi { ) -> Result>> { todo!() } + + fn get_header>( + &self, + _parentchain_id: &ParentchainId, + ) -> Result { + todo!() + } + + fn get_storage_keys_paged>( + &self, + _key_prefix: Vec, + _count: u32, + _start_key: Option>, + _header: Option<&H>, + ) -> Result>> { + todo!() + } } impl EnclaveSidechainOCallApi for ProposeToImportOCallApi { diff --git a/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs b/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs index a8ec1e4e1f..ed5460c64c 100644 --- a/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs +++ b/tee-worker/identity/litentry/core/omni-account/src/in_memory_store.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . -use crate::{AccountId, BTreeMap, Error, MemberAccount, OmniAccounts, Vec}; +use crate::{AccountId, BTreeMap, BlockNumber, Error, MemberAccount, OmniAccounts, Vec}; use lazy_static::lazy_static; use sp_core::H256; @@ -27,6 +27,7 @@ lazy_static! { static ref ACCCOUNT_STORE: RwLock = RwLock::new(BTreeMap::new()); static ref MEMBER_ACCOUNT_HASH: RwLock> = RwLock::new(BTreeMap::new()); + static ref STORE_BLOCK_HEIGHT: RwLock = RwLock::new(0); } pub struct InMemoryStore; @@ -60,7 +61,10 @@ impl InMemoryStore { Ok(account_id) } - pub fn insert(account_id: AccountId, members: Vec) -> Result<(), Error> { + pub fn insert_account_store( + account_id: AccountId, + members: Vec, + ) -> Result<(), Error> { let mut member_account_hash = MEMBER_ACCOUNT_HASH.write().map_err(|_| { log::error!("[InMemoryStore] Lock poisoning"); Error::LockPoisoning @@ -79,19 +83,7 @@ impl InMemoryStore { Ok(()) } - pub fn remove(account_id: AccountId) -> Result<(), Error> { - ACCCOUNT_STORE - .write() - .map_err(|_| { - log::error!("[InMemoryStore] Lock poisoning"); - Error::LockPoisoning - })? - .remove(&account_id); - - Ok(()) - } - - pub fn load(accounts: OmniAccounts) -> Result<(), Error> { + pub fn load_account_stores(accounts: OmniAccounts) -> Result<(), Error> { for (account_id, members) in &accounts { let mut member_account_hash = MEMBER_ACCOUNT_HASH.write().map_err(|_| { log::error!("[InMemoryStore] Lock poisoning"); @@ -108,4 +100,22 @@ impl InMemoryStore { Ok(()) } + + pub fn set_block_height(block_number: BlockNumber) -> Result<(), Error> { + *STORE_BLOCK_HEIGHT.write().map_err(|_| { + log::error!("[InMemoryStore] Lock poisoning"); + Error::LockPoisoning + })? = block_number; + + Ok(()) + } + + pub fn get_block_height() -> Result { + let block_number = *STORE_BLOCK_HEIGHT.read().map_err(|_| { + log::error!("[InMemoryStore] Lock poisoning"); + Error::LockPoisoning + })?; + + Ok(block_number) + } } diff --git a/tee-worker/identity/litentry/core/omni-account/src/lib.rs b/tee-worker/identity/litentry/core/omni-account/src/lib.rs index 506ff11c41..9c2e81c813 100644 --- a/tee-worker/identity/litentry/core/omni-account/src/lib.rs +++ b/tee-worker/identity/litentry/core/omni-account/src/lib.rs @@ -16,22 +16,23 @@ #![cfg_attr(not(feature = "std"), no_std)] -pub extern crate alloc; +#[cfg(all(feature = "std", feature = "sgx"))] +compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); #[cfg(all(not(feature = "std"), feature = "sgx"))] extern crate sgx_tstd as std; -#[cfg(all(feature = "std", feature = "sgx"))] -compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); +extern crate alloc; mod repository; +use itp_ocall_api::EnclaveOnChainOCallApi; pub use repository::*; mod in_memory_store; pub use in_memory_store::InMemoryStore; -use alloc::{collections::btree_map::BTreeMap, vec::Vec}; -use itp_types::parentchain::{AccountId, Header, ParentchainId}; +use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; +use itp_types::parentchain::{AccountId, BlockNumber, Header, ParentchainId}; use litentry_primitives::MemberAccount; pub type OmniAccounts = BTreeMap>; @@ -41,3 +42,24 @@ pub enum Error { LockPoisoning, OCallApiError(&'static str), } + +pub fn init_in_memory_omni_account_store( + ocall_api: Arc, +) -> Result<(), &'static str> +where + OCallApi: EnclaveOnChainOCallApi, +{ + let header: Header = ocall_api.get_header(&ParentchainId::Litentry).map_err(|e| { + log::error!("Failed to get header: {:?}", e); + "Failed to get header" + })?; + let block_number: BlockNumber = header.number; + let repository = OmniAccountRepository::new(ocall_api, header); + let account_stores = repository.get_all().map_err(|_| "Failed to get all account stores")?; + InMemoryStore::load_account_stores(account_stores) + .map_err(|_| "Failed to load account stores")?; + InMemoryStore::set_block_height(block_number).map_err(|_| "Failed to set block number")?; + log::info!("In-memory store initialized successfully"); + + Ok(()) +} diff --git a/tee-worker/identity/litentry/core/omni-account/src/repository.rs b/tee-worker/identity/litentry/core/omni-account/src/repository.rs index eba762c1e1..fd0cf76e43 100644 --- a/tee-worker/identity/litentry/core/omni-account/src/repository.rs +++ b/tee-worker/identity/litentry/core/omni-account/src/repository.rs @@ -15,22 +15,22 @@ // along with Litentry. If not, see . use crate::{AccountId, Error, Header, MemberAccount, OmniAccounts, ParentchainId}; -use alloc::vec::Vec; +use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use frame_support::storage::storage_prefix; use itp_ocall_api::EnclaveOnChainOCallApi; -use itp_storage::{decode_storage_key, extract_blake2_128concat_key}; +use itp_storage::extract_blake2_128concat_key; pub trait GetAccountStoresRepository { fn get_all(&self) -> Result; } pub struct OmniAccountRepository { - ocall_api: OCallApi, + ocall_api: Arc, header: Header, } impl OmniAccountRepository { - pub fn new(ocall_api: OCallApi, header: Header) -> Self { + pub fn new(ocall_api: Arc, header: Header) -> Self { Self { ocall_api, header } } @@ -44,31 +44,44 @@ impl GetAccountStoresRepository { fn get_all(&self) -> Result { let account_store_key_prefix = storage_prefix(b"OmniAccount", b"AccountStore"); - let account_store_storage_keys_response = self - .ocall_api - .get_storage_keys(account_store_key_prefix.into(), Some(&self.header)) - .map_err(|_| Error::OCallApiError("Failed to get storage keys"))?; - let account_store_storage_keys = account_store_storage_keys_response - .into_iter() - .filter_map(decode_storage_key) - .collect::>>(); - let omni_accounts: OmniAccounts = self - .ocall_api - .get_multiple_storages_verified( - account_store_storage_keys, - &self.header, - &ParentchainId::Litentry, - ) - .map_err(|_| Error::OCallApiError("Failed to get multiple storages"))? - .into_iter() - .filter_map(|entry| { - // TODO: double check this - let storage_key = decode_storage_key(entry.key)?; - let account_id: AccountId = extract_blake2_128concat_key(&storage_key)?; - let member_accounts: Vec = entry.value?; - Some((account_id, member_accounts)) - }) - .collect(); + let page_size = 300; + let mut start_key: Option> = None; + let mut omni_accounts: OmniAccounts = BTreeMap::new(); + + loop { + let storage_keys_paged = self + .ocall_api + .get_storage_keys_paged( + account_store_key_prefix.into(), + page_size, + start_key.clone(), + Some(&self.header), + ) + .map_err(|_| Error::OCallApiError("Failed to get storage keys"))?; + + if storage_keys_paged.is_empty() || storage_keys_paged.last().cloned() == start_key { + break + } + + start_key = storage_keys_paged.last().cloned(); + + self.ocall_api + .get_multiple_storages_verified( + storage_keys_paged, + &self.header, + &ParentchainId::Litentry, + ) + .map_err(|_| Error::OCallApiError("Failed to get multiple storages"))? + .into_iter() + .filter_map(|entry| { + let account_id: AccountId = extract_blake2_128concat_key(entry.key.as_slice())?; + let member_accounts: Vec = entry.value?; + Some((account_id, member_accounts)) + }) + .for_each(|(account_id, member_accounts)| { + omni_accounts.insert(account_id, member_accounts); + }); + } Ok(omni_accounts) } diff --git a/tee-worker/identity/service/src/main_impl.rs b/tee-worker/identity/service/src/main_impl.rs index e5f9c0dcc4..ed91d151ee 100644 --- a/tee-worker/identity/service/src/main_impl.rs +++ b/tee-worker/identity/service/src/main_impl.rs @@ -162,6 +162,11 @@ pub(crate) fn main() { enclave_metrics_receiver, ))); + // init in-memory store, it should be done after the o-call bridge is initialized + if let Err(e) = enclave.init_in_memory_state() { + error!("Failed to initialize in-memory state: {:?}", e); + } + #[cfg(feature = "dcap")] let quoting_enclave_target_info = match enclave.qe_get_target_info() { Ok(target_info) => Some(target_info), diff --git a/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs b/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs index 1d309a3ea1..93005c902e 100644 --- a/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/tee-worker/identity/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -26,7 +26,8 @@ use log::*; use sp_runtime::OpaqueExtrinsic; use std::{sync::Arc, thread, vec::Vec}; use substrate_api_client::{ - ac_primitives::serde_impls::StorageKey, GetStorage, SubmitAndWatch, SubmitExtrinsic, XtStatus, + ac_primitives::serde_impls::StorageKey, GetChainInfo, GetStorage, SubmitAndWatch, + SubmitExtrinsic, XtStatus, }; #[cfg(feature = "link-binary")] @@ -112,6 +113,25 @@ where }; WorkerResponse::ChainStorageKeys(keys) }, + WorkerRequest::ChainStorageKeysPaged(prefix, count, start_key, hash) => { + let keys: Vec> = match api.get_storage_keys_paged( + Some(StorageKey(prefix)), + count, + start_key.map(StorageKey), + hash, + ) { + Ok(keys) => keys.iter().map(|k| k.0.to_vec()).collect(), + _ => Default::default(), + }; + WorkerResponse::ChainStorageKeys(keys) + }, + WorkerRequest::ChainHeader(block_hash) => { + let header = match api.get_header(block_hash) { + Ok(Some(header)) => Some(header.encode()), + _ => None, + }; + WorkerResponse::ChainHeader(header) + }, }) .collect(); diff --git a/tee-worker/identity/service/src/tests/mocks/enclave_api_mock.rs b/tee-worker/identity/service/src/tests/mocks/enclave_api_mock.rs index ef500df115..18633c4f59 100644 --- a/tee-worker/identity/service/src/tests/mocks/enclave_api_mock.rs +++ b/tee-worker/identity/service/src/tests/mocks/enclave_api_mock.rs @@ -104,6 +104,10 @@ impl EnclaveBase for EnclaveMock { unimplemented!() } + fn init_in_memory_state(&self) -> EnclaveResult<()> { + unimplemented!() + } + fn upload_id_graph(&self) -> EnclaveResult<()> { unimplemented!() }