From 8550d7dc428aec1fb044cfdb9c178f461ee5a7bf Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 15:17:57 +0200 Subject: [PATCH 01/49] [itp-sgx-crypto] add `ToPubkey` and `AccessPubkey` traits --- .../sgx/crypto/src/key_repository.rs | 25 ++++++++++++++++++- core-primitives/sgx/crypto/src/traits.rs | 7 ++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/core-primitives/sgx/crypto/src/key_repository.rs b/core-primitives/sgx/crypto/src/key_repository.rs index 626321d0f8..5a9106dae7 100644 --- a/core-primitives/sgx/crypto/src/key_repository.rs +++ b/core-primitives/sgx/crypto/src/key_repository.rs @@ -21,7 +21,10 @@ use std::sync::SgxRwLock as RwLock; #[cfg(feature = "std")] use std::sync::RwLock; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + ToPubkey, +}; use itp_sgx_io::SealedIO; use std::sync::Arc; @@ -32,6 +35,13 @@ pub trait AccessKey { fn retrieve_key(&self) -> Result; } +/// Access a cryptographic public key. +pub trait AccessPubkey { + type KeyType; + + fn retrieve_pubkey(&self) -> Result; +} + /// Mutate a cryptographic key. pub trait MutateKey { fn update_key(&self, key: KeyType) -> Result<()>; @@ -62,6 +72,19 @@ where } } +impl AccessPubkey for KeyRepository +where + Pair: ToPubkey + Clone, + SealedIo: SealedIO, +{ + type KeyType = ::Pubkey; + + fn retrieve_pubkey(&self) -> Result { + let pair = self.key_lock.read().map_err(|_| Error::LockPoisoning).map(|l| l.clone())?; + pair.pubkey() + } +} + impl MutateKey for KeyRepository where KeyType: Clone, diff --git a/core-primitives/sgx/crypto/src/traits.rs b/core-primitives/sgx/crypto/src/traits.rs index fde231ff33..1d0aef5798 100644 --- a/core-primitives/sgx/crypto/src/traits.rs +++ b/core-primitives/sgx/crypto/src/traits.rs @@ -33,3 +33,10 @@ pub trait ShieldingCryptoDecrypt { type Error: Debug; fn decrypt(&self, data: &[u8]) -> Result, Self::Error>; } + +pub trait ToPubkey { + type Error: Debug; + type Pubkey; + + fn pubkey(&self) -> Result; +} From 560c7870599a27b053e8c3344d789fa778b958ee Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 15:19:13 +0200 Subject: [PATCH 02/49] [itp-sgx-crypto] refactor the Rsa3072 stuff to no longer use static file IO. --- core-primitives/sgx/crypto/src/rsa3072.rs | 108 ++++++++++++------- enclave-runtime/Cargo.lock | 1 + enclave-runtime/Cargo.toml | 5 + enclave-runtime/src/initialization/mod.rs | 14 +-- enclave-runtime/src/lib.rs | 15 ++- enclave-runtime/src/rpc/worker_api_direct.rs | 16 ++- enclave-runtime/src/test/direct_rpc_tests.rs | 9 +- local-setup/py/worker.py | 2 +- 8 files changed, 115 insertions(+), 55 deletions(-) diff --git a/core-primitives/sgx/crypto/src/rsa3072.rs b/core-primitives/sgx/crypto/src/rsa3072.rs index feb6d7204c..b4ce7c2a3e 100644 --- a/core-primitives/sgx/crypto/src/rsa3072.rs +++ b/core-primitives/sgx/crypto/src/rsa3072.rs @@ -20,6 +20,7 @@ use crate::sgx_reexport_prelude::*; use crate::{ error::{Error, Result}, traits::{ShieldingCryptoDecrypt, ShieldingCryptoEncrypt}, + ToPubkey, }; use sgx_crypto_helper::{ rsa3072::{Rsa3072KeyPair, Rsa3072PubKey}, @@ -64,56 +65,86 @@ impl ShieldingCryptoEncrypt for Rsa3072PubKey { } } +impl ToPubkey for Rsa3072KeyPair { + type Error = Error; + type Pubkey = Rsa3072PubKey; + + fn pubkey(&self) -> Result { + self.export_pubkey().map_err(|e| Error::Other(format!("{:?}", e).into())) + } +} + +pub trait RsaSealing { + fn unseal_pubkey(&self) -> Result; + + fn unseal_pair(&self) -> Result; + + fn exists(&self) -> bool; + + fn create_sealed_if_absent(&self) -> Result<()>; + + fn create_sealed(&self) -> Result<()>; +} + #[cfg(feature = "sgx")] pub mod sgx { use super::*; - use derive_more::Display; + use crate::key_repository::KeyRepository; use itp_settings::files::RSA3072_SEALED_KEY_FILE; - use itp_sgx_io::{seal, unseal, SealedIO, StaticSealedIO}; + use itp_sgx_io::{seal, unseal, SealedIO}; use log::*; - use std::sgxfs::SgxFile; + use std::{path::PathBuf, sgxfs::SgxFile}; + + pub fn get_rsa3072_repository( + path: PathBuf, + ) -> Result> { + let rsa_seal = Rsa3072Seal::new(path); + rsa_seal.create_sealed_if_absent()?; + let shielding_key = rsa_seal.unseal_pair()?; + Ok(KeyRepository::new(shielding_key, rsa_seal.into())) + } + + #[derive(Clone, Debug)] + pub struct Rsa3072Seal { + base_path: PathBuf, + } impl Rsa3072Seal { - pub fn unseal_pubkey() -> Result { - let pair = Self::unseal_from_static_file()?; - let pubkey = - pair.export_pubkey().map_err(|e| Error::Other(format!("{:?}", e).into()))?; - Ok(pubkey) + pub fn new(base_path: PathBuf) -> Self { + Self { base_path } } - } - pub fn create_sealed_if_absent() -> Result<()> { - if SgxFile::open(RSA3072_SEALED_KEY_FILE).is_err() { - info!("[Enclave] Keyfile not found, creating new! {}", RSA3072_SEALED_KEY_FILE); - return create_sealed() + pub fn path(&self) -> PathBuf { + self.base_path.join(RSA3072_SEALED_KEY_FILE) } - Ok(()) } - pub fn create_sealed() -> Result<()> { - let rsa_keypair = - Rsa3072KeyPair::new().map_err(|e| Error::Other(format!("{:?}", e).into()))?; - // println!("[Enclave] generated RSA3072 key pair. Cleartext: {}", rsa_key_json); - Rsa3072Seal::seal_to_static_file(&rsa_keypair) - } + impl RsaSealing for Rsa3072Seal { + fn unseal_pubkey(&self) -> Result { + self.unseal()?.pubkey() + } - #[derive(Copy, Clone, Debug, Display)] - pub struct Rsa3072Seal; + fn unseal_pair(&self) -> Result { + self.unseal() + } - impl StaticSealedIO for Rsa3072Seal { - type Error = Error; - type Unsealed = Rsa3072KeyPair; - fn unseal_from_static_file() -> Result { - let raw = unseal(RSA3072_SEALED_KEY_FILE)?; - let key: Rsa3072KeyPair = serde_json::from_slice(&raw) - .map_err(|e| Error::Other(format!("{:?}", e).into()))?; - Ok(key.into()) + fn exists(&self) -> bool { + SgxFile::open(self.path()).is_ok() } - fn seal_to_static_file(unsealed: &Self::Unsealed) -> Result<()> { - let key_json = serde_json::to_vec(&unsealed) - .map_err(|e| Error::Other(format!("{:?}", e).into()))?; - Ok(seal(&key_json, RSA3072_SEALED_KEY_FILE)?) + fn create_sealed_if_absent(&self) -> Result<()> { + if !self.exists() { + info!("Keyfile not found, creating new! {}", RSA3072_SEALED_KEY_FILE); + return self.create_sealed() + } + Ok(()) + } + + fn create_sealed(&self) -> Result<()> { + let rsa_keypair = + Rsa3072KeyPair::new().map_err(|e| Error::Other(format!("{:?}", e).into()))?; + // println!("[Enclave] generated RSA3072 key pair. Cleartext: {}", rsa_key_json); + self.seal(&rsa_keypair) } } @@ -122,11 +153,16 @@ pub mod sgx { type Unsealed = Rsa3072KeyPair; fn unseal(&self) -> Result { - Self::unseal_from_static_file() + let raw = unseal(self.path())?; + let key: Rsa3072KeyPair = serde_json::from_slice(&raw) + .map_err(|e| Error::Other(format!("{:?}", e).into()))?; + Ok(key.into()) } fn seal(&self, unsealed: &Self::Unsealed) -> Result<()> { - Self::seal_to_static_file(unsealed) + let key_json = serde_json::to_vec(&unsealed) + .map_err(|e| Error::Other(format!("{:?}", e).into()))?; + Ok(seal(&key_json, self.path())?) } } } diff --git a/enclave-runtime/Cargo.lock b/enclave-runtime/Cargo.lock index e0b665f47f..53ec4d4b40 100644 --- a/enclave-runtime/Cargo.lock +++ b/enclave-runtime/Cargo.lock @@ -701,6 +701,7 @@ dependencies = [ "itp-sgx-crypto", "itp-sgx-externalities", "itp-sgx-io", + "itp-sgx-temp-dir", "itp-stf-executor", "itp-stf-interface", "itp-stf-primitives", diff --git a/enclave-runtime/Cargo.toml b/enclave-runtime/Cargo.toml index f0e229c0e4..3faaa81fa0 100644 --- a/enclave-runtime/Cargo.toml +++ b/enclave-runtime/Cargo.toml @@ -34,6 +34,7 @@ test = [ "itp-attestation-handler/test", "itp-extrinsics-factory/mocks", "itp-sgx-crypto/mocks", + "itp-sgx-temp-dir", "itp-stf-executor/test", "itp-stf-executor/mocks", "itp-stf-state-handler/test", @@ -134,6 +135,10 @@ sp-core = { default-features = false, features = ["full_crypto"], git = "https:/ sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.39" } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.39" } +# test-deps +itp-sgx-temp-dir = { version = "0.1", default-features = false, optional = true, path = "../core-primitives/sgx/temp-dir" } + + [patch.crates-io] env_logger = { git = "https://github.com/integritee-network/env_logger-sgx" } getrandom = { git = "https://github.com/integritee-network/getrandom-sgx", branch = "update-v2.3" } diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index aea45fcd23..8b4b049810 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -60,7 +60,7 @@ use itp_attestation_handler::IntelAttestationHandler; use itp_component_container::{ComponentGetter, ComponentInitializer}; use itp_primitives_cache::GLOBAL_PRIMITIVES_CACHE; use itp_settings::files::STATE_SNAPSHOTS_CACHE_SIZE; -use itp_sgx_crypto::{aes, ed25519, rsa3072, AesSeal, Ed25519Seal, Rsa3072Seal}; +use itp_sgx_crypto::{aes, ed25519, get_rsa3072_repository, AesSeal, Ed25519Seal}; use itp_sgx_io::StaticSealedIO; use itp_stf_state_handler::{ handle_state::HandleState, query_shard_state::QueryShardState, @@ -83,12 +83,7 @@ pub(crate) fn init_enclave(mu_ra_url: String, untrusted_worker_url: String) -> E let signer = Ed25519Seal::unseal_from_static_file().map_err(Error::Crypto)?; info!("[Enclave initialized] Ed25519 prim raw : {:?}", signer.public().0); - rsa3072::create_sealed_if_absent()?; - - let shielding_key = Rsa3072Seal::unseal_from_static_file()?; - - let shielding_key_repository = - Arc::new(EnclaveShieldingKeyRepository::new(shielding_key, Arc::new(Rsa3072Seal))); + let shielding_key_repository = Arc::new(get_rsa3072_repository(base_path.clone())?); GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT.initialize(shielding_key_repository.clone()); // Create the aes key that is used for state encryption such that a key is always present in tests. @@ -153,12 +148,13 @@ pub(crate) fn init_enclave(mu_ra_url: String, untrusted_worker_url: String) -> E connection_registry.clone(), state_handler, ocall_api.clone(), - shielding_key_repository, + shielding_key_repository.clone(), ); GLOBAL_TOP_POOL_AUTHOR_COMPONENT.initialize(top_pool_author.clone()); let getter_executor = Arc::new(EnclaveGetterExecutor::new(state_observer)); - let io_handler = public_api_rpc_handler(top_pool_author, getter_executor); + let io_handler = + public_api_rpc_handler(top_pool_author, getter_executor, shielding_key_repository); let rpc_handler = Arc::new(RpcWsHandler::new(io_handler, watch_extractor, connection_registry)); GLOBAL_RPC_WS_HANDLER_COMPONENT.initialize(rpc_handler); diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index dbb83f5adb..c44e5d8550 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -33,7 +33,8 @@ use crate::{ error::{Error, Result}, initialization::global_components::{ GLOBAL_FULL_PARACHAIN_HANDLER_COMPONENT, GLOBAL_FULL_SOLOCHAIN_HANDLER_COMPONENT, - GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT, + GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT, + GLOBAL_STATE_HANDLER_COMPONENT, }, rpc::worker_api_direct::sidechain_io_handler, utils::{ @@ -50,7 +51,7 @@ use itp_component_container::ComponentGetter; use itp_node_api::metadata::NodeMetadata; use itp_nonce_cache::{MutateNonce, Nonce, GLOBAL_NONCE_CACHE}; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode, WorkerModeProvider}; -use itp_sgx_crypto::{ed25519, Ed25519Seal, Rsa3072Seal}; +use itp_sgx_crypto::{ed25519, key_repository::AccessPubkey, Ed25519Seal}; use itp_sgx_io::StaticSealedIO; use itp_storage::StorageProof; use itp_types::{ShardIdentifier, SignedBlock}; @@ -119,7 +120,15 @@ pub unsafe extern "C" fn get_rsa_encryption_pubkey( pubkey: *mut u8, pubkey_size: u32, ) -> sgx_status_t { - let rsa_pubkey = match Rsa3072Seal::unseal_pubkey() { + let shielding_key_repository = match GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT.get() { + Ok(s) => s, + Err(e) => { + error!("{:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + }, + }; + + let rsa_pubkey = match shielding_key_repository.retrieve_pubkey() { Ok(key) => key, Err(e) => return e.into(), }; diff --git a/enclave-runtime/src/rpc/worker_api_direct.rs b/enclave-runtime/src/rpc/worker_api_direct.rs index 9a1624ba89..0a674e48ce 100644 --- a/enclave-runtime/src/rpc/worker_api_direct.rs +++ b/enclave-runtime/src/rpc/worker_api_direct.rs @@ -28,7 +28,7 @@ use ita_sgx_runtime::Runtime; use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, ExtrinsicSender}; use itp_primitives_cache::{GetPrimitives, GLOBAL_PRIMITIVES_CACHE}; use itp_rpc::RpcReturnValue; -use itp_sgx_crypto::Rsa3072Seal; +use itp_sgx_crypto::key_repository::AccessPubkey; use itp_stf_executor::getter_executor::ExecuteGetter; use itp_top_pool_author::traits::AuthorApi; use itp_types::{DirectRequestStatus, Request, ShardIdentifier, H256}; @@ -36,6 +36,7 @@ use itp_utils::{FromHexPrefixed, ToHexPrefixed}; use its_primitives::types::block::SignedBlock; use its_sidechain::rpc_handler::{direct_top_pool_api, import_block_api}; use jsonrpc_core::{serde_json::json, IoHandler, Params, Value}; +use sgx_crypto_helper::rsa3072::Rsa3072PubKey; use sp_runtime::OpaqueExtrinsic; use std::{borrow::ToOwned, format, str, string::String, sync::Arc, vec::Vec}; @@ -53,10 +54,15 @@ fn get_all_rpc_methods_string(io_handler: &IoHandler) -> String { format!("methods: [{}]", method_string) } -pub fn public_api_rpc_handler(top_pool_author: Arc, getter_executor: Arc) -> IoHandler +pub fn public_api_rpc_handler( + top_pool_author: Arc, + getter_executor: Arc, + shielding_key: Arc, +) -> IoHandler where - R: AuthorApi + Send + Sync + 'static, - G: ExecuteGetter + Send + Sync + 'static, + Author: AuthorApi + Send + Sync + 'static, + GetterExecutor: ExecuteGetter + Send + Sync + 'static, + AccessShieldingKey: AccessPubkey + Send + Sync + 'static, { let io = IoHandler::new(); @@ -66,7 +72,7 @@ where // author_getShieldingKey let rsa_pubkey_name: &str = "author_getShieldingKey"; io.add_sync_method(rsa_pubkey_name, move |_: Params| { - let rsa_pubkey = match Rsa3072Seal::unseal_pubkey() { + let rsa_pubkey = match shielding_key.retrieve_pubkey() { Ok(key) => key, Err(status) => { let error_msg: String = format!("Could not get rsa pubkey due to: {}", status); diff --git a/enclave-runtime/src/test/direct_rpc_tests.rs b/enclave-runtime/src/test/direct_rpc_tests.rs index 2f2d8c54b4..a4d79eca8e 100644 --- a/enclave-runtime/src/test/direct_rpc_tests.rs +++ b/enclave-runtime/src/test/direct_rpc_tests.rs @@ -25,6 +25,8 @@ use itc_direct_rpc_server::{ }; use itc_tls_websocket_server::{ConnectionToken, WebSocketMessageHandler}; use itp_rpc::{RpcRequest, RpcReturnValue}; +use itp_sgx_crypto::get_rsa3072_repository; +use itp_sgx_temp_dir::TempDir; use itp_stf_executor::{getter_executor::GetterExecutor, mocks::GetStateMock}; use itp_stf_state_observer::mock::ObserveStateMock; use itp_top_pool_author::mocks::AuthorApiMock; @@ -37,15 +39,20 @@ use std::{string::ToString, sync::Arc, vec::Vec}; pub fn get_state_request_works() { type TestState = u64; + let temp_dir = TempDir::with_prefix("get_state_request_works").unwrap(); + let connection_registry = Arc::new(ConnectionRegistry::::new()); let watch_extractor = Arc::new(create_determine_watch::()); + let rsa_repository = get_rsa3072_repository(temp_dir.path().to_path_buf()).unwrap(); let state: TestState = 78234u64; let state_observer = Arc::new(ObserveStateMock::::new(state)); let getter_executor = Arc::new(GetterExecutor::<_, GetStateMock>::new(state_observer)); let top_pool_author = Arc::new(AuthorApiMock::default()); - let io_handler = public_api_rpc_handler(top_pool_author, getter_executor); + + let io_handler = + public_api_rpc_handler(top_pool_author, getter_executor, Arc::new(rsa_repository)); let rpc_handler = Arc::new(RpcWsHandler::new(io_handler, watch_extractor, connection_registry)); let getter = Getter::trusted(TrustedGetterSigned::new( diff --git a/local-setup/py/worker.py b/local-setup/py/worker.py index 132b3df9b0..3986f8a343 100644 --- a/local-setup/py/worker.py +++ b/local-setup/py/worker.py @@ -164,7 +164,7 @@ def run_in_background(self, log_file: TextIO, flags: [str] = None, subcommand_fl 'substrate_api_client=warn,' 'jsonrpsee_ws_client=warn,' 'jsonrpsee_ws_server=warn,' - 'enclave_runtime=warn,' + 'enclave_runtime=info,' 'integritee_service=warn,' 'ita_stf=debug') From 2906f8fd77f6d8eccc359f892b0e93e8532b94ef Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 15:43:10 +0200 Subject: [PATCH 03/49] [itp-sgx-crypto] set-base-path to the PWD --- enclave-runtime/Cargo.lock | 1 + enclave-runtime/Cargo.toml | 1 + enclave-runtime/src/initialization/mod.rs | 13 +++++++------ enclave-runtime/src/lib.rs | 16 ++++++++++++++-- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/enclave-runtime/Cargo.lock b/enclave-runtime/Cargo.lock index 53ec4d4b40..cbb5c81d2f 100644 --- a/enclave-runtime/Cargo.lock +++ b/enclave-runtime/Cargo.lock @@ -722,6 +722,7 @@ dependencies = [ "lazy_static", "log", "multibase", + "once_cell 1.4.0", "parity-scale-codec", "primitive-types", "rust-base58", diff --git a/enclave-runtime/Cargo.toml b/enclave-runtime/Cargo.toml index 3faaa81fa0..acf682e215 100644 --- a/enclave-runtime/Cargo.toml +++ b/enclave-runtime/Cargo.toml @@ -75,6 +75,7 @@ jsonrpc-core = { default-features = false, git = "https://github.com/scs/jsonrpc # mesalock env_logger = { git = "https://github.com/integritee-network/env_logger-sgx" } log = { git = "https://github.com/integritee-network/log-sgx" } +once_cell = { git = "https://github.com/mesalock-linux/once_cell-sgx" } rustls = { rev = "sgx_1.1.3", features = ["dangerous_configuration"], git = "https://github.com/mesalock-linux/rustls" } serde = { tag = "sgx_1.1.3", git = "https://github.com/mesalock-linux/serde-sgx", features = ["alloc", "mesalock_sgx"] } serde_derive = { git = "https://github.com/mesalock-linux/serde-sgx" } diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index 8b4b049810..29ba4440ff 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -73,17 +73,18 @@ use itp_types::ShardIdentifier; use its_sidechain::block_composer::BlockComposer; use log::*; use sp_core::crypto::Pair; -use std::{collections::HashMap, string::String, sync::Arc}; - -pub(crate) fn init_enclave(mu_ra_url: String, untrusted_worker_url: String) -> EnclaveResult<()> { - // Initialize the logging environment in the enclave. - env_logger::init(); +use std::{collections::HashMap, path::PathBuf, string::String, sync::Arc}; +pub(crate) fn init_enclave( + mu_ra_url: String, + untrusted_worker_url: String, + base_dir: PathBuf, +) -> EnclaveResult<()> { ed25519::create_sealed_if_absent().map_err(Error::Crypto)?; let signer = Ed25519Seal::unseal_from_static_file().map_err(Error::Crypto)?; info!("[Enclave initialized] Ed25519 prim raw : {:?}", signer.public().0); - let shielding_key_repository = Arc::new(get_rsa3072_repository(base_path.clone())?); + let shielding_key_repository = Arc::new(get_rsa3072_repository(base_dir.clone())?); GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT.initialize(shielding_key_repository.clone()); // Create the aes key that is used for state encryption such that a key is always present in tests. diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index c44e5d8550..a9fefa935c 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -57,9 +57,10 @@ use itp_storage::StorageProof; use itp_types::{ShardIdentifier, SignedBlock}; use itp_utils::write_slice_and_whitespace_pad; use log::*; +use once_cell::sync::OnceCell; use sgx_types::sgx_status_t; use sp_core::crypto::Pair; -use std::{boxed::Box, slice, vec::Vec}; +use std::{boxed::Box, path::PathBuf, slice, vec::Vec}; mod attestation; mod empty_impls; @@ -83,6 +84,8 @@ pub mod test; pub type Hash = sp_core::H256; pub type AuthorityPair = sp_core::ed25519::Pair; +static BASE_PATH: OnceCell = OnceCell::new(); + /// Initialize the enclave. #[no_mangle] pub unsafe extern "C" fn init( @@ -91,6 +94,15 @@ pub unsafe extern "C" fn init( untrusted_worker_addr: *const u8, untrusted_worker_addr_size: u32, ) -> sgx_status_t { + // Initialize the logging environment in the enclave. + env_logger::init(); + + // Todo: This will be changed to be a param of the `init` ecall: + // https://github.com/integritee-network/worker/issues/1292 + let pwd = std::env::current_dir().expect("Works on all supported platforms; qed"); + info!("Setting base_dir to pwd: {}", pwd.display()); + BASE_PATH.set(pwd.clone()).expect("We only init this once here; qed."); + let mu_ra_url = match String::decode(&mut slice::from_raw_parts(mu_ra_addr, mu_ra_addr_size as usize)) .map_err(Error::Codec) @@ -109,7 +121,7 @@ pub unsafe extern "C" fn init( Err(e) => return e.into(), }; - match initialization::init_enclave(mu_ra_url, untrusted_worker_url) { + match initialization::init_enclave(mu_ra_url, untrusted_worker_url, pwd) { Err(e) => e.into(), Ok(()) => sgx_status_t::SGX_SUCCESS, } From e9dbe6ee0ae9dffa647e53a5ad708c91748e56e5 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 15:49:01 +0200 Subject: [PATCH 04/49] [enclave-runtime] more explanation about using the PWD --- enclave-runtime/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index a9fefa935c..bef40a5289 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -99,6 +99,9 @@ pub unsafe extern "C" fn init( // Todo: This will be changed to be a param of the `init` ecall: // https://github.com/integritee-network/worker/issues/1292 + // + // Until the above task is finished, we just fall back to the + // static behaviour, which uses the PWD already. let pwd = std::env::current_dir().expect("Works on all supported platforms; qed"); info!("Setting base_dir to pwd: {}", pwd.display()); BASE_PATH.set(pwd.clone()).expect("We only init this once here; qed."); From 177503d793c46f9643960fabe2bca320039a457f Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 15:51:24 +0200 Subject: [PATCH 05/49] [enclave-runtime] add todo for replacing the once-cell. --- enclave-runtime/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/enclave-runtime/Cargo.toml b/enclave-runtime/Cargo.toml index acf682e215..1ace0938ea 100644 --- a/enclave-runtime/Cargo.toml +++ b/enclave-runtime/Cargo.toml @@ -75,6 +75,7 @@ jsonrpc-core = { default-features = false, git = "https://github.com/scs/jsonrpc # mesalock env_logger = { git = "https://github.com/integritee-network/env_logger-sgx" } log = { git = "https://github.com/integritee-network/log-sgx" } +# Todo: use the `once_cell` included in rusts core library once we use rust v1.70.0 once_cell = { git = "https://github.com/mesalock-linux/once_cell-sgx" } rustls = { rev = "sgx_1.1.3", features = ["dangerous_configuration"], git = "https://github.com/mesalock-linux/rustls" } serde = { tag = "sgx_1.1.3", git = "https://github.com/mesalock-linux/serde-sgx", features = ["alloc", "mesalock_sgx"] } From 564542021cafd5bd6bb36dfdefc08e9ccef14056 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 15:52:04 +0200 Subject: [PATCH 06/49] taplo fmt --- enclave-runtime/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/enclave-runtime/Cargo.toml b/enclave-runtime/Cargo.toml index 1ace0938ea..2824f0d4c8 100644 --- a/enclave-runtime/Cargo.toml +++ b/enclave-runtime/Cargo.toml @@ -140,7 +140,6 @@ sp-std = { default-features = false, git = "https://github.com/paritytech/substr # test-deps itp-sgx-temp-dir = { version = "0.1", default-features = false, optional = true, path = "../core-primitives/sgx/temp-dir" } - [patch.crates-io] env_logger = { git = "https://github.com/integritee-network/env_logger-sgx" } getrandom = { git = "https://github.com/integritee-network/getrandom-sgx", branch = "update-v2.3" } From 0c1d6b9b1b0736c415e4388f5cbc7d667bca73bc Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 16:33:37 +0200 Subject: [PATCH 07/49] add some doc --- core-primitives/sgx/crypto/src/rsa3072.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core-primitives/sgx/crypto/src/rsa3072.rs b/core-primitives/sgx/crypto/src/rsa3072.rs index b4ce7c2a3e..26aacac001 100644 --- a/core-primitives/sgx/crypto/src/rsa3072.rs +++ b/core-primitives/sgx/crypto/src/rsa3072.rs @@ -95,6 +95,8 @@ pub mod sgx { use log::*; use std::{path::PathBuf, sgxfs::SgxFile}; + /// Gets an key repository for an Rsa3072 keypair and initializes + /// a fresh key pair if it doesn't exist at `path`. pub fn get_rsa3072_repository( path: PathBuf, ) -> Result> { From 8ea4fff5315e73b30c4bdd2903fb52cbe093e30a Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Tue, 23 May 2023 16:38:13 +0200 Subject: [PATCH 08/49] typo --- core-primitives/sgx/crypto/src/rsa3072.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-primitives/sgx/crypto/src/rsa3072.rs b/core-primitives/sgx/crypto/src/rsa3072.rs index 26aacac001..b5392e4839 100644 --- a/core-primitives/sgx/crypto/src/rsa3072.rs +++ b/core-primitives/sgx/crypto/src/rsa3072.rs @@ -95,7 +95,7 @@ pub mod sgx { use log::*; use std::{path::PathBuf, sgxfs::SgxFile}; - /// Gets an key repository for an Rsa3072 keypair and initializes + /// Gets a repository for an Rsa3072 keypair and initializes /// a fresh key pair if it doesn't exist at `path`. pub fn get_rsa3072_repository( path: PathBuf, From 7a381e452ee8d45ae141b9f3c8c01d5abd2b0b41 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 08:16:47 +0200 Subject: [PATCH 09/49] [sgx-crypto] log full path instead of just filename. --- core-primitives/sgx/crypto/src/rsa3072.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-primitives/sgx/crypto/src/rsa3072.rs b/core-primitives/sgx/crypto/src/rsa3072.rs index b5392e4839..9e9ffa8f5f 100644 --- a/core-primitives/sgx/crypto/src/rsa3072.rs +++ b/core-primitives/sgx/crypto/src/rsa3072.rs @@ -136,7 +136,7 @@ pub mod sgx { fn create_sealed_if_absent(&self) -> Result<()> { if !self.exists() { - info!("Keyfile not found, creating new! {}", RSA3072_SEALED_KEY_FILE); + info!("Keyfile not found, creating new! {}", self.path().display()); return self.create_sealed() } Ok(()) From 33faf7d5795bcc23d22b6dab5bf9179f241d5ea9 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 08:25:30 +0200 Subject: [PATCH 10/49] [itp-sgx-io] fix standalone compilation --- core-primitives/sgx/io/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-primitives/sgx/io/Cargo.toml b/core-primitives/sgx/io/Cargo.toml index 57f64ec054..2f18915854 100644 --- a/core-primitives/sgx/io/Cargo.toml +++ b/core-primitives/sgx/io/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] # sgx deps -sgx_tstd = { branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true } +sgx_tstd = { optional = true, features = ["untrusted_fs"], branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git" } [features] default = ["std"] From 19b873e4119e13a5ed37932a2dda85a6b8646f60 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 08:32:38 +0200 Subject: [PATCH 11/49] [itp-sgx-crypto] put some functions behind a trait. --- core-primitives/sgx/crypto/src/ed25519.rs | 114 ++++++++++++++-------- 1 file changed, 74 insertions(+), 40 deletions(-) diff --git a/core-primitives/sgx/crypto/src/ed25519.rs b/core-primitives/sgx/crypto/src/ed25519.rs index 07082d38ce..6df5101897 100644 --- a/core-primitives/sgx/crypto/src/ed25519.rs +++ b/core-primitives/sgx/crypto/src/ed25519.rs @@ -15,42 +15,92 @@ */ -use derive_more::Display; - -#[derive(Copy, Clone, Debug, Display)] -pub struct Ed25519Seal; +use crate::error::Result; +use sp_core::ed25519; #[cfg(feature = "sgx")] pub use sgx::*; +pub trait Ed25519Sealing { + fn unseal_pubkey(&self) -> Result; + + fn unseal_pair(&self) -> Result; + + fn exists(&self) -> bool; + + fn create_sealed_if_absent(&self) -> Result<()>; + + fn create_sealed(&self) -> Result<()>; +} + #[cfg(feature = "sgx")] pub mod sgx { - - use super::*; - use crate::error::{Error, Result}; + use crate::{ + error::{Error, Result}, + key_repository::KeyRepository, + Ed25519Sealing, + }; use codec::Encode; use itp_settings::files::SEALED_SIGNER_SEED_FILE; - use itp_sgx_io::{seal, unseal, SealedIO, StaticSealedIO}; + use itp_sgx_io::{seal, unseal, SealedIO}; use log::*; use sgx_rand::{Rng, StdRng}; use sp_core::{crypto::Pair, ed25519}; - use std::{path::Path, sgxfs::SgxFile}; + use std::{path::PathBuf, sgxfs::SgxFile}; + + /// Gets a repository for an Ed25519 keypair and initializes + /// a fresh key pair if it doesn't exist at `path`. + pub fn get_ed25519_repository( + path: PathBuf, + ) -> Result> { + let ed25519_seal = Ed25519Seal::new(path); + ed25519_seal.create_sealed_if_absent()?; + let signing_pair = ed25519_seal.unseal_pair()?; + Ok(KeyRepository::new(signing_pair, ed25519_seal.into())) + } - impl StaticSealedIO for Ed25519Seal { - type Error = Error; - type Unsealed = ed25519::Pair; + #[derive(Clone, Debug)] + pub struct Ed25519Seal { + base_path: PathBuf, + } - fn unseal_from_static_file() -> Result { - let raw = unseal(SEALED_SIGNER_SEED_FILE)?; + impl Ed25519Seal { + pub fn new(base_path: PathBuf) -> Self { + Self { base_path } + } - let key = ed25519::Pair::from_seed_slice(&raw) - .map_err(|e| Error::Other(format!("{:?}", e).into()))?; + pub fn path(&self) -> PathBuf { + self.base_path.join(SEALED_SIGNER_SEED_FILE) + } + } - Ok(key.into()) + impl Ed25519Sealing for Ed25519Seal { + fn unseal_pubkey(&self) -> Result { + self.unseal().map(Into::into) } - fn seal_to_static_file(unsealed: &Self::Unsealed) -> Result<()> { - Ok(unsealed.seed().using_encoded(|bytes| seal(bytes, SEALED_SIGNER_SEED_FILE))?) + fn unseal_pair(&self) -> Result { + self.unseal() + } + + fn exists(&self) -> bool { + SgxFile::open(self.path()).is_ok() + } + + fn create_sealed_if_absent(&self) -> Result<()> { + if !self.exists() { + info!("Keyfile not found, creating new! {}", self.path().display()); + return self.create_sealed() + } + Ok(()) + } + + fn create_sealed(&self) -> Result<()> { + let mut seed = [0u8; 32]; + let mut rand = StdRng::new()?; + rand.fill_bytes(&mut seed); + + Ok(seal(&seed, self.path())?) } } @@ -59,30 +109,14 @@ pub mod sgx { type Unsealed = ed25519::Pair; fn unseal(&self) -> Result { - Self::unseal_from_static_file() - } + let raw = unseal(self.path())?; - fn seal(&self, unsealed: &Self::Unsealed) -> Result<()> { - Self::seal_to_static_file(unsealed) + ed25519::Pair::from_seed_slice(&raw) + .map_err(|e| Error::Other(format!("{:?}", e).into())) } - } - pub fn create_sealed_if_absent() -> Result<()> { - if SgxFile::open(SEALED_SIGNER_SEED_FILE).is_err() { - if Path::new(SEALED_SIGNER_SEED_FILE).exists() { - panic!("[Enclave] Keyfile {} exists but can't be opened. has it been written by the same enclave?", SEALED_SIGNER_SEED_FILE); - } - info!("[Enclave] Keyfile not found, creating new! {}", SEALED_SIGNER_SEED_FILE); - return create_sealed_seed() + fn seal(&self, unsealed: &Self::Unsealed) -> Result<()> { + Ok(unsealed.seed().using_encoded(|bytes| seal(bytes, self.path()))?) } - Ok(()) - } - - pub fn create_sealed_seed() -> Result<()> { - let mut seed = [0u8; 32]; - let mut rand = StdRng::new()?; - rand.fill_bytes(&mut seed); - - Ok(seal(&seed, SEALED_SIGNER_SEED_FILE)?) } } From b5c5284770f619bce61940990d4f6ec405c5a865 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 09:05:06 +0200 Subject: [PATCH 12/49] [enclave-runtime/attestation_handler] add signing key repo to struct --- .../src/attestation_handler.rs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/core-primitives/attestation-handler/src/attestation_handler.rs b/core-primitives/attestation-handler/src/attestation_handler.rs index 9e5cde04d3..8b8401951d 100644 --- a/core-primitives/attestation-handler/src/attestation_handler.rs +++ b/core-primitives/attestation-handler/src/attestation_handler.rs @@ -39,9 +39,8 @@ use itp_settings::{ files::{RA_API_KEY_FILE, RA_DUMP_CERT_DER_FILE, RA_SPID_FILE}, worker::MR_ENCLAVE_SIZE, }; -use itp_sgx_crypto::Ed25519Seal; +use itp_sgx_crypto::key_repository::AccessKey; use itp_sgx_io as io; -use itp_sgx_io::StaticSealedIO; use itp_time_utils::now_as_secs; use log::*; use sgx_rand::{os, Rng}; @@ -51,7 +50,7 @@ use sgx_types::{ c_int, sgx_epid_group_id_t, sgx_quote_nonce_t, sgx_quote_sign_type_t, sgx_report_data_t, sgx_spid_t, sgx_status_t, sgx_target_info_t, SgxResult, *, }; -use sp_core::Pair; +use sp_core::{ed25519, Pair}; use std::{ borrow::ToOwned, env, format, @@ -115,13 +114,16 @@ pub trait AttestationHandler { ) -> EnclaveResult<(Vec, Vec)>; } -pub struct IntelAttestationHandler { +pub struct IntelAttestationHandler { pub(crate) ocall_api: Arc, + pub(crate) signing_key_repo: Arc, } -impl AttestationHandler for IntelAttestationHandler +impl AttestationHandler + for IntelAttestationHandler where OCallApi: EnclaveAttestationOCallApi, + AccessSigningKey: AccessKey, { fn generate_ias_ra_cert(&self, skip_ra: bool) -> EnclaveResult> { // Our certificate is unlinkable. @@ -195,7 +197,7 @@ where sign_type: sgx_quote_sign_type_t, skip_ra: bool, ) -> EnclaveResult<(Vec, Vec)> { - let chain_signer = Ed25519Seal::unseal_from_static_file()?; + let chain_signer = self.signing_key_repo.retrieve_key()?; info!("[Enclave Attestation] Ed25519 pub raw : {:?}", chain_signer.public().0); info!(" [Enclave] Generate keypair"); @@ -249,7 +251,7 @@ where quote_size: u32, skip_ra: bool, ) -> EnclaveResult<(Vec, Vec)> { - let chain_signer = Ed25519Seal::unseal_from_static_file()?; + let chain_signer = self.signing_key_repo.retrieve_key()?; info!("[Enclave Attestation] Ed25519 signer pub key: {:?}", chain_signer.public().0); let ecc_handle = SgxEccHandle::new(); @@ -291,14 +293,17 @@ where } } -impl IntelAttestationHandler +impl IntelAttestationHandler { + pub fn new(ocall_api: Arc, signing_key_repo: Arc) -> Self { + Self { ocall_api, signing_key_repo } + } +} + +impl IntelAttestationHandler where OCallApi: EnclaveAttestationOCallApi, + AccessSigningKey: AccessKey, { - pub fn new(ocall_api: Arc) -> Self { - Self { ocall_api } - } - fn parse_response_attn_report(&self, resp: &[u8]) -> EnclaveResult<(String, String, String)> { debug!(" [Enclave] Entering parse_response_attn_report"); let mut headers = [httparse::EMPTY_HEADER; 16]; From 6a716198d436c36ad49269b5942f557ae1812bfd Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 09:05:38 +0200 Subject: [PATCH 13/49] [itp-sgx-crypto] impl `ToPubkey` for `ed25511::Pair` --- core-primitives/sgx/crypto/src/ed25519.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core-primitives/sgx/crypto/src/ed25519.rs b/core-primitives/sgx/crypto/src/ed25519.rs index 6df5101897..ac172b1cc8 100644 --- a/core-primitives/sgx/crypto/src/ed25519.rs +++ b/core-primitives/sgx/crypto/src/ed25519.rs @@ -15,7 +15,10 @@ */ -use crate::error::Result; +use crate::{ + error::{Error, Result}, + ToPubkey, +}; use sp_core::ed25519; #[cfg(feature = "sgx")] @@ -33,6 +36,15 @@ pub trait Ed25519Sealing { fn create_sealed(&self) -> Result<()>; } +impl ToPubkey for ed25519::Pair { + type Error = Error; + type Pubkey = ed25519::Public; + + fn pubkey(&self) -> Result { + Ok(self.clone().into()) + } +} + #[cfg(feature = "sgx")] pub mod sgx { use crate::{ From cc0be6ee30018e48e4672312b2cb780b117eb094 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 09:26:58 +0200 Subject: [PATCH 14/49] introduce `SigningKeyRepository` and remove all instances of `StaticFile` IO. --- .../src/initialization/global_components.rs | 13 ++++++--- enclave-runtime/src/initialization/mod.rs | 27 ++++++++++--------- .../src/initialization/parentchain/common.rs | 9 +++---- enclave-runtime/src/lib.rs | 25 +++++++++-------- enclave-runtime/src/top_pool_execution.rs | 9 +++---- 5 files changed, 47 insertions(+), 36 deletions(-) diff --git a/enclave-runtime/src/initialization/global_components.rs b/enclave-runtime/src/initialization/global_components.rs index 544aee95a6..e4197a43ba 100644 --- a/enclave-runtime/src/initialization/global_components.rs +++ b/enclave-runtime/src/initialization/global_components.rs @@ -62,7 +62,7 @@ use itp_node_api::{ metadata::{provider::NodeMetadataRepository, NodeMetadata}, }; use itp_nonce_cache::NonceCache; -use itp_sgx_crypto::{key_repository::KeyRepository, Aes, AesSeal, Rsa3072Seal}; +use itp_sgx_crypto::{key_repository::KeyRepository, Aes, AesSeal, Ed25519Seal, Rsa3072Seal}; use itp_stf_executor::{ enclave_signer::StfEnclaveSigner, executor::StfExecutor, getter_executor::GetterExecutor, state_getter::StfStateGetter, @@ -90,7 +90,7 @@ use its_sidechain::{ }; use sgx_crypto_helper::rsa3072::Rsa3072KeyPair; use sgx_tstd::vec::Vec; -use sp_core::ed25519::Pair; +use sp_core::{ed25519, ed25519::Pair}; pub type EnclaveParentchainSigner = itp_node_api::api_client::StaticExtrinsicSigner; @@ -100,6 +100,7 @@ pub type EnclaveTrustedCallSigned = TrustedCallSigned; pub type EnclaveStf = Stf; pub type EnclaveStateKeyRepository = KeyRepository; pub type EnclaveShieldingKeyRepository = KeyRepository; +pub type EnclaveSigningKeyRepository = KeyRepository; pub type EnclaveStateFileIo = SgxStateFileIo; pub type EnclaveStateSnapshotRepository = StateSnapshotRepository; pub type EnclaveStateObserver = StateObserver; @@ -119,7 +120,8 @@ pub type EnclaveStfEnclaveSigner = StfEnclaveSigner< EnclaveStf, EnclaveTopPoolAuthor, >; -pub type EnclaveAttestationHandler = IntelAttestationHandler; +pub type EnclaveAttestationHandler = + IntelAttestationHandler; pub type EnclaveRpcConnectionRegistry = ConnectionRegistry; pub type EnclaveRpcWsHandler = @@ -237,6 +239,11 @@ pub static GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT: ComponentContainer< EnclaveShieldingKeyRepository, > = ComponentContainer::new("Shielding key repository"); +/// Signing key repository +pub static GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT: ComponentContainer< + EnclaveSigningKeyRepository, +> = ComponentContainer::new("Signing key repository"); + /// O-Call API pub static GLOBAL_OCALL_API_COMPONENT: ComponentContainer = ComponentContainer::new("O-call API"); diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index 29ba4440ff..239d78a982 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -32,9 +32,9 @@ use crate::{ GLOBAL_RPC_WS_HANDLER_COMPONENT, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_SIDECHAIN_BLOCK_COMPOSER_COMPONENT, GLOBAL_SIDECHAIN_BLOCK_SYNCER_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_WORKER_COMPONENT, - GLOBAL_STATE_HANDLER_COMPONENT, GLOBAL_STATE_KEY_REPOSITORY_COMPONENT, - GLOBAL_STATE_OBSERVER_COMPONENT, GLOBAL_TOP_POOL_AUTHOR_COMPONENT, - GLOBAL_WEB_SOCKET_SERVER_COMPONENT, + GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT, + GLOBAL_STATE_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_OBSERVER_COMPONENT, + GLOBAL_TOP_POOL_AUTHOR_COMPONENT, GLOBAL_WEB_SOCKET_SERVER_COMPONENT, }, ocall::OcallApi, rpc::{rpc_response_channel::RpcResponseChannel, worker_api_direct::public_api_rpc_handler}, @@ -60,7 +60,9 @@ use itp_attestation_handler::IntelAttestationHandler; use itp_component_container::{ComponentGetter, ComponentInitializer}; use itp_primitives_cache::GLOBAL_PRIMITIVES_CACHE; use itp_settings::files::STATE_SNAPSHOTS_CACHE_SIZE; -use itp_sgx_crypto::{aes, ed25519, get_rsa3072_repository, AesSeal, Ed25519Seal}; +use itp_sgx_crypto::{ + aes, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey, AesSeal, +}; use itp_sgx_io::StaticSealedIO; use itp_stf_state_handler::{ handle_state::HandleState, query_shard_state::QueryShardState, @@ -80,8 +82,9 @@ pub(crate) fn init_enclave( untrusted_worker_url: String, base_dir: PathBuf, ) -> EnclaveResult<()> { - ed25519::create_sealed_if_absent().map_err(Error::Crypto)?; - let signer = Ed25519Seal::unseal_from_static_file().map_err(Error::Crypto)?; + let signing_key_repository = Arc::new(get_ed25519_repository(base_dir.clone())?); + GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.initialize(signing_key_repository.clone()); + let signer = signing_key_repository.retrieve_key()?; info!("[Enclave initialized] Ed25519 prim raw : {:?}", signer.public().0); let shielding_key_repository = Arc::new(get_rsa3072_repository(base_dir.clone())?); @@ -162,7 +165,8 @@ pub(crate) fn init_enclave( let sidechain_block_import_queue = Arc::new(EnclaveSidechainBlockImportQueue::default()); GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT.initialize(sidechain_block_import_queue); - let attestation_handler = Arc::new(IntelAttestationHandler::new(ocall_api)); + let attestation_handler = + Arc::new(IntelAttestationHandler::new(ocall_api, signing_key_repository)); GLOBAL_ATTESTATION_HANDLER_COMPONENT.initialize(attestation_handler); Ok(()) @@ -187,12 +191,11 @@ pub(crate) fn init_enclave_sidechain_components() -> EnclaveResult<()> { let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; let top_pool_author = GLOBAL_TOP_POOL_AUTHOR_COMPONENT.get()?; + let state_key_repository = GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.get()?; let parentchain_block_import_dispatcher = get_triggered_dispatcher_from_solo_or_parachain()?; - let state_key_repository = GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.get()?; - - let signer = Ed25519Seal::unseal_from_static_file()?; + let signer = GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?; let sidechain_block_importer = Arc::new(EnclaveSidechainBlockImporter::new( state_handler, @@ -236,10 +239,10 @@ pub(crate) fn init_enclave_sidechain_components() -> EnclaveResult<()> { pub(crate) fn init_direct_invocation_server(server_addr: String) -> EnclaveResult<()> { let rpc_handler = GLOBAL_RPC_WS_HANDLER_COMPONENT.get()?; - let signing = Ed25519Seal::unseal_from_static_file()?; + let signer = GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?; let cert = - ed25519_self_signed_certificate(signing, "Enclave").map_err(|e| Error::Other(e.into()))?; + ed25519_self_signed_certificate(signer, "Enclave").map_err(|e| Error::Other(e.into()))?; // Serialize certificate(s) and private key to PEM. // PEM format is needed as a certificate chain can only be serialized into PEM. diff --git a/enclave-runtime/src/initialization/parentchain/common.rs b/enclave-runtime/src/initialization/parentchain/common.rs index d3c0c20182..91ce1a12b4 100644 --- a/enclave-runtime/src/initialization/parentchain/common.rs +++ b/enclave-runtime/src/initialization/parentchain/common.rs @@ -26,16 +26,15 @@ use crate::{ EnclaveParentchainEventImportQueue, EnclaveParentchainSigner, EnclaveStfExecutor, EnclaveTriggeredParentchainBlockImportDispatcher, EnclaveValidatorAccessor, GLOBAL_OCALL_API_COMPONENT, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, - GLOBAL_STATE_HANDLER_COMPONENT, GLOBAL_STATE_OBSERVER_COMPONENT, - GLOBAL_TOP_POOL_AUTHOR_COMPONENT, + GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT, + GLOBAL_STATE_OBSERVER_COMPONENT, GLOBAL_TOP_POOL_AUTHOR_COMPONENT, }, EnclaveStfEnclaveSigner, }, }; use itp_component_container::ComponentGetter; use itp_nonce_cache::GLOBAL_NONCE_CACHE; -use itp_sgx_crypto::Ed25519Seal; -use itp_sgx_io::StaticSealedIO; +use itp_sgx_crypto::key_repository::AccessKey; use log::*; use sp_core::H256; use std::sync::Arc; @@ -75,7 +74,7 @@ pub(crate) fn create_extrinsics_factory( genesis_hash: H256, node_metadata_repository: Arc, ) -> Result> { - let signer = Ed25519Seal::unseal_from_static_file()?; + let signer = GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?; Ok(Arc::new(EnclaveExtrinsicsFactory::new( genesis_hash, diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index 236e632ddb..bdd3ecee96 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -34,7 +34,7 @@ use crate::{ initialization::global_components::{ GLOBAL_FULL_PARACHAIN_HANDLER_COMPONENT, GLOBAL_FULL_SOLOCHAIN_HANDLER_COMPONENT, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT, - GLOBAL_STATE_HANDLER_COMPONENT, + GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT, }, rpc::worker_api_direct::sidechain_io_handler, utils::{ @@ -51,15 +51,13 @@ use itp_import_queue::PushToQueue; use itp_node_api::metadata::NodeMetadata; use itp_nonce_cache::{MutateNonce, Nonce, GLOBAL_NONCE_CACHE}; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode, WorkerModeProvider}; -use itp_sgx_crypto::{ed25519, key_repository::AccessPubkey, Ed25519Seal}; -use itp_sgx_io::StaticSealedIO; +use itp_sgx_crypto::key_repository::AccessPubkey; use itp_storage::{StorageProof, StorageProofChecker}; use itp_types::{ShardIdentifier, SignedBlock}; use itp_utils::write_slice_and_whitespace_pad; use log::*; use once_cell::sync::OnceCell; use sgx_types::sgx_status_t; -use sp_core::crypto::Pair; use sp_runtime::traits::BlakeTwo256; use std::{boxed::Box, path::PathBuf, slice, vec::Vec}; @@ -170,18 +168,23 @@ pub unsafe extern "C" fn get_rsa_encryption_pubkey( #[no_mangle] pub unsafe extern "C" fn get_ecc_signing_pubkey(pubkey: *mut u8, pubkey_size: u32) -> sgx_status_t { - if let Err(e) = ed25519::create_sealed_if_absent().map_err(Error::Crypto) { - return e.into() - } + let signing_key_repository = match GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get() { + Ok(s) => s, + Err(e) => { + error!("{:?}", e); + return sgx_status_t::SGX_ERROR_UNEXPECTED + }, + }; - let signer = match Ed25519Seal::unseal_from_static_file().map_err(Error::Crypto) { - Ok(pair) => pair, + let signer_public = match signing_key_repository.retrieve_pubkey() { + Ok(s) => s, Err(e) => return e.into(), }; - debug!("Restored ECC pubkey: {:?}", signer.public()); + + debug!("Restored ECC pubkey: {:?}", signer_public); let pubkey_slice = slice::from_raw_parts_mut(pubkey, pubkey_size as usize); - pubkey_slice.clone_from_slice(&signer.public()); + pubkey_slice.clone_from_slice(&signer_public); sgx_status_t::SGX_SUCCESS } diff --git a/enclave-runtime/src/top_pool_execution.rs b/enclave-runtime/src/top_pool_execution.rs index 1dec62ad5b..b276513ff9 100644 --- a/enclave-runtime/src/top_pool_execution.rs +++ b/enclave-runtime/src/top_pool_execution.rs @@ -19,8 +19,8 @@ use crate::{ error::Result, initialization::global_components::{ GLOBAL_OCALL_API_COMPONENT, GLOBAL_SIDECHAIN_BLOCK_COMPOSER_COMPONENT, - GLOBAL_SIDECHAIN_IMPORT_QUEUE_WORKER_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT, - GLOBAL_TOP_POOL_AUTHOR_COMPONENT, + GLOBAL_SIDECHAIN_IMPORT_QUEUE_WORKER_COMPONENT, GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT, + GLOBAL_STATE_HANDLER_COMPONENT, GLOBAL_TOP_POOL_AUTHOR_COMPONENT, }, sync::{EnclaveLock, EnclaveStateRWLock}, utils::{ @@ -41,8 +41,7 @@ use itp_component_container::ComponentGetter; use itp_extrinsics_factory::CreateExtrinsics; use itp_ocall_api::{EnclaveOnChainOCallApi, EnclaveSidechainOCallApi}; use itp_settings::sidechain::SLOT_DURATION; -use itp_sgx_crypto::Ed25519Seal; -use itp_sgx_io::StaticSealedIO; +use itp_sgx_crypto::key_repository::AccessKey; use itp_stf_state_handler::query_shard_state::QueryShardState; use itp_time_utils::duration_now; use itp_types::{Block, OpaqueCall, H256}; @@ -130,7 +129,7 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; - let authority = Ed25519Seal::unseal_from_static_file()?; + let authority = GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT.get()?.retrieve_key()?; match yield_next_slot( slot_beginning_timestamp, From f73b880cc979d8f86d9abe847a63f31321f344f1 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 11:50:44 +0200 Subject: [PATCH 15/49] [itp-sgx-crypto] add base path to AESSeal --- core-primitives/sgx/crypto/src/aes.rs | 100 ++++++++++++++-------- enclave-runtime/src/initialization/mod.rs | 15 ++-- 2 files changed, 70 insertions(+), 45 deletions(-) diff --git a/core-primitives/sgx/crypto/src/aes.rs b/core-primitives/sgx/crypto/src/aes.rs index d63bed35a2..d2bf3ceeb8 100644 --- a/core-primitives/sgx/crypto/src/aes.rs +++ b/core-primitives/sgx/crypto/src/aes.rs @@ -21,12 +21,15 @@ use crate::{ }; use aes::Aes128; use codec::{Decode, Encode}; -use derive_more::Display; +use itp_settings::files::AES_KEY_FILE_AND_INIT_V; use ofb::{ cipher::{NewStreamCipher, SyncStreamCipher}, Ofb, }; -use std::convert::{TryFrom, TryInto}; +use std::{ + convert::{TryFrom, TryInto}, + path::PathBuf, +}; type AesOfb = Ofb; @@ -42,8 +45,20 @@ impl Aes { } } -#[derive(Copy, Clone, Debug, Display)] -pub struct AesSeal; +#[derive(Clone, Debug)] +pub struct AesSeal { + base_path: PathBuf, +} + +impl AesSeal { + pub fn new(base_path: PathBuf) -> Self { + Self { base_path } + } + + pub fn path(&self) -> PathBuf { + self.base_path.join(AES_KEY_FILE_AND_INIT_V) + } +} impl StateCrypto for Aes { type Error = Error; @@ -70,29 +85,63 @@ pub fn de_or_encrypt(aes: &Aes, data: &mut [u8]) -> Result<()> { aes.try_into().map(|mut ofb: AesOfb| ofb.apply_keystream(data)) } +pub trait AesSealing { + fn unseal_key(&self) -> Result; + + fn exists(&self) -> bool; + + fn create_sealed_if_absent(&self) -> Result<()>; + + fn create_sealed(&self) -> Result<()>; +} + #[cfg(feature = "sgx")] pub use sgx::*; #[cfg(feature = "sgx")] pub mod sgx { - use super::*; - use itp_settings::files::AES_KEY_FILE_AND_INIT_V; - use itp_sgx_io::{seal, unseal, SealedIO, StaticSealedIO}; + use crate::key_repository::KeyRepository; + use itp_sgx_io::{seal, unseal, SealedIO}; use log::info; use sgx_rand::{Rng, StdRng}; use std::sgxfs::SgxFile; - impl StaticSealedIO for AesSeal { - type Error = Error; - type Unsealed = Aes; + /// Gets a repository for an AES key and initializes + /// a fresh key if it doesn't exist at `path`. + pub fn get_aes_repository(path: PathBuf) -> Result> { + let aes_seal = AesSeal::new(path); + aes_seal.create_sealed_if_absent()?; + let aes_key = aes_seal.unseal_key()?; + Ok(KeyRepository::new(aes_key, aes_seal.into())) + } + + impl AesSealing for AesSeal { + fn unseal_key(&self) -> Result { + self.unseal() + } - fn unseal_from_static_file() -> Result { - Ok(unseal(AES_KEY_FILE_AND_INIT_V).map(|b| Decode::decode(&mut b.as_slice()))??) + fn exists(&self) -> bool { + SgxFile::open(self.path()).is_ok() } - fn seal_to_static_file(unsealed: &Self::Unsealed) -> Result<()> { - Ok(unsealed.using_encoded(|bytes| seal(bytes, AES_KEY_FILE_AND_INIT_V))?) + fn create_sealed_if_absent(&self) -> Result<()> { + if !self.exists() { + info!("Keyfile not found, creating new! {}", self.path().display()); + return self.create_sealed() + } + Ok(()) + } + + fn create_sealed(&self) -> Result<()> { + let mut key = [0u8; 16]; + let mut iv = [0u8; 16]; + let mut rand = StdRng::new()?; + + rand.fill_bytes(&mut key); + rand.fill_bytes(&mut iv); + + Ok(self.seal(&Aes::new(key, iv))?) } } @@ -101,30 +150,11 @@ pub mod sgx { type Unsealed = Aes; fn unseal(&self) -> Result { - Self::unseal_from_static_file() + Ok(unseal(self.path()).map(|b| Decode::decode(&mut b.as_slice()))??) } fn seal(&self, unsealed: &Self::Unsealed) -> Result<()> { - Self::seal_to_static_file(&unsealed) + Ok(unsealed.using_encoded(|bytes| seal(bytes, self.path()))?) } } - - pub fn create_sealed_if_absent() -> Result<()> { - if SgxFile::open(AES_KEY_FILE_AND_INIT_V).is_err() { - info!("[Enclave] Keyfile not found, creating new! {}", AES_KEY_FILE_AND_INIT_V); - return create_sealed() - } - Ok(()) - } - - pub fn create_sealed() -> Result<()> { - let mut key = [0u8; 16]; - let mut iv = [0u8; 16]; - - let mut rand = StdRng::new()?; - - rand.fill_bytes(&mut key); - rand.fill_bytes(&mut iv); - AesSeal::seal_to_static_file(&Aes::new(key, iv)) - } } diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index 239d78a982..aa10dbabd2 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -26,9 +26,9 @@ use crate::{ EnclaveSidechainApi, EnclaveSidechainBlockImportQueue, EnclaveSidechainBlockImportQueueWorker, EnclaveSidechainBlockImporter, EnclaveSidechainBlockSyncer, EnclaveStateFileIo, EnclaveStateHandler, - EnclaveStateInitializer, EnclaveStateKeyRepository, EnclaveStateObserver, - EnclaveStateSnapshotRepository, EnclaveStfEnclaveSigner, EnclaveTopPool, - EnclaveTopPoolAuthor, GLOBAL_ATTESTATION_HANDLER_COMPONENT, GLOBAL_OCALL_API_COMPONENT, + EnclaveStateInitializer, EnclaveStateObserver, EnclaveStateSnapshotRepository, + EnclaveStfEnclaveSigner, EnclaveTopPool, EnclaveTopPoolAuthor, + GLOBAL_ATTESTATION_HANDLER_COMPONENT, GLOBAL_OCALL_API_COMPONENT, GLOBAL_RPC_WS_HANDLER_COMPONENT, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT, GLOBAL_SIDECHAIN_BLOCK_COMPOSER_COMPONENT, GLOBAL_SIDECHAIN_BLOCK_SYNCER_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_WORKER_COMPONENT, @@ -61,9 +61,8 @@ use itp_component_container::{ComponentGetter, ComponentInitializer}; use itp_primitives_cache::GLOBAL_PRIMITIVES_CACHE; use itp_settings::files::STATE_SNAPSHOTS_CACHE_SIZE; use itp_sgx_crypto::{ - aes, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey, AesSeal, + get_aes_repository, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey, }; -use itp_sgx_io::StaticSealedIO; use itp_stf_state_handler::{ handle_state::HandleState, query_shard_state::QueryShardState, state_snapshot_repository::VersionedStateAccess, @@ -92,11 +91,7 @@ pub(crate) fn init_enclave( // Create the aes key that is used for state encryption such that a key is always present in tests. // It will be overwritten anyway if mutual remote attestation is performed with the primary worker. - aes::create_sealed_if_absent().map_err(Error::Crypto)?; - - let state_key = AesSeal::unseal_from_static_file()?; - let state_key_repository = - Arc::new(EnclaveStateKeyRepository::new(state_key, Arc::new(AesSeal))); + let state_key_repository = Arc::new(get_aes_repository(base_dir.clone())?); GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.initialize(state_key_repository.clone()); let state_file_io = Arc::new(EnclaveStateFileIo::new(state_key_repository)); From d0e5c3eb030ac50353895cd88ad462759d404fa4 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 11:53:23 +0200 Subject: [PATCH 16/49] [itp-state-handler] wip update tests --- Cargo.lock | 1 + core-primitives/stf-state-handler/Cargo.toml | 4 +++ .../stf-state-handler/src/test/sgx_tests.rs | 32 +++++++++++++------ enclave-runtime/Cargo.lock | 1 + 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4919006bb..cfb3e2cb62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3627,6 +3627,7 @@ dependencies = [ "itp-sgx-crypto", "itp-sgx-externalities", "itp-sgx-io", + "itp-sgx-temp-dir", "itp-stf-interface", "itp-stf-state-observer", "itp-time-utils", diff --git a/core-primitives/stf-state-handler/Cargo.toml b/core-primitives/stf-state-handler/Cargo.toml index 7b8d31b2b0..73f0f63e59 100644 --- a/core-primitives/stf-state-handler/Cargo.toml +++ b/core-primitives/stf-state-handler/Cargo.toml @@ -22,6 +22,9 @@ itp-stf-state-observer = { path = "../stf-state-observer", default-features = fa itp-time-utils = { path = "../../core-primitives/time-utils", default-features = false } itp-types = { path = "../types", default-features = false } +# for tests +itp-sgx-temp-dir = { version = "0.1", default-features = false, optional = true, path = "../../core-primitives/sgx/temp-dir" } + # sgx enabled external libraries rust-base58_sgx = { package = "rust-base58", rev = "sgx_1.1.3", git = "https://github.com/mesalock-linux/rust-base58-sgx", optional = true, default-features = false, features = ["mesalock_sgx"] } thiserror_sgx = { package = "thiserror", git = "https://github.com/mesalock-linux/thiserror-sgx", tag = "sgx_1.1.3", optional = true } @@ -71,4 +74,5 @@ sgx = [ test = [ "itp-sgx-crypto/mocks", "itp-stf-interface/mocks", + "itp-sgx-temp-dir" ] diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 4ad8ff1947..b0e2b83166 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -33,16 +33,21 @@ use crate::{ use codec::{Decode, Encode}; use ita_stf::{State as StfState, StateType as StfStateType}; use itp_hashing::Hash; -use itp_sgx_crypto::{mocks::KeyRepositoryMock, Aes, AesSeal, StateCrypto}; +use itp_sgx_crypto::{ + get_aes_repository, + key_repository::{AccessKey, KeyRepository}, + Aes, AesSeal, StateCrypto, +}; use itp_sgx_externalities::{SgxExternalities, SgxExternalitiesTrait}; -use itp_sgx_io::{write, StaticSealedIO}; +use itp_sgx_io::write; +use itp_sgx_temp_dir::TempDir; use itp_stf_state_observer::state_observer::StateObserver; use itp_types::{ShardIdentifier, H256}; use std::{sync::Arc, thread, vec::Vec}; const STATE_SNAPSHOTS_CACHE_SIZE: usize = 3; -type StateKeyRepositoryMock = KeyRepositoryMock; +type StateKeyRepositoryMock = KeyRepository; type TestStateInitializer = InitializeStateMock; type TestStateFileIo = SgxStateFileIo; type TestStateRepository = StateSnapshotRepository; @@ -88,7 +93,12 @@ pub fn test_sgx_state_decode_encode_works() { pub fn test_encrypt_decrypt_state_type_works() { // given let state = given_hello_world_state(); - let state_key = AesSeal::unseal_from_static_file().unwrap(); + + let temp_dir = TempDir::with_prefix("test_encrypt_decrypt_state_type_works").unwrap(); + let state_key = get_aes_repository(temp_dir.path().to_path_buf()) + .unwrap() + .retrieve_key() + .unwrap(); // when let mut state_buffer = state.state.encode(); @@ -234,8 +244,8 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); - let state_key_access = - Arc::new(StateKeyRepositoryMock::new(AesSeal::unseal_from_static_file().unwrap())); + let temp_dir = TempDir::with_prefix("test_file_io_get_state_hash_works").unwrap(); + let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); let file_io = TestStateFileIo::new(state_key_access); @@ -281,8 +291,9 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); - let state_key_access = - Arc::new(StateKeyRepositoryMock::new(AesSeal::unseal_from_static_file().unwrap())); + let temp_dir = + TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); + let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); let file_io = TestStateFileIo::new(state_key_access); @@ -321,8 +332,9 @@ fn initialize_state_handler_with_directory_handle( } fn initialize_state_handler() -> Arc { - let state_key_access = - Arc::new(StateKeyRepositoryMock::new(AesSeal::unseal_from_static_file().unwrap())); + let temp_dir = TempDir::with_prefix("initialize_state_handler").unwrap(); + let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); + let file_io = Arc::new(TestStateFileIo::new(state_key_access)); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = diff --git a/enclave-runtime/Cargo.lock b/enclave-runtime/Cargo.lock index e9367bf0c2..8e26c96c8c 100644 --- a/enclave-runtime/Cargo.lock +++ b/enclave-runtime/Cargo.lock @@ -2090,6 +2090,7 @@ dependencies = [ "itp-sgx-crypto", "itp-sgx-externalities", "itp-sgx-io", + "itp-sgx-temp-dir", "itp-stf-interface", "itp-stf-state-observer", "itp-time-utils", From 11a38525a74a1bbe657e7f1f9ad3d28dd05fb28e Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 11:53:39 +0200 Subject: [PATCH 17/49] [itp-state-handler] add debug log for existing files in shard --- core-primitives/stf-state-handler/src/test/sgx_tests.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index b0e2b83166..f9f31e1c1e 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -380,6 +380,10 @@ fn given_initialized_shard(shard: &ShardIdentifier) -> Result<()> { fn number_of_files_in_shard_dir(shard: &ShardIdentifier) -> Result { let shard_dir_path = shard_path(shard); - let files_in_dir = std::fs::read_dir(shard_dir_path).map_err(|e| Error::Other(e.into()))?; + let files_in_dir = + std::fs::read_dir(shard_dir_path.clone()).map_err(|e| Error::Other(e.into()))?; + + log::info!("File in shard dir: {:?}", files_in_dir); + Ok(files_in_dir.count()) } From a4d0a4197b086c4a5892396b7255c4e9d5367b90 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Wed, 24 May 2023 14:49:31 +0200 Subject: [PATCH 18/49] [itp-state-handler] fix tests by creating a unique key-repo per test --- .../stf-state-handler/src/test/sgx_tests.rs | 63 +++++++++++++------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index f9f31e1c1e..3d6d37c51a 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -75,6 +75,14 @@ impl Drop for ShardDirectoryHandle { } } +/// Gets a temporary key repository. +/// +/// We pass and ID such that it doesn't clash with other temp repositories. +fn temp_state_key_repository(id: &str) -> StateKeyRepositoryMock { + let temp_dir = TempDir::with_prefix(id).unwrap(); + get_aes_repository(temp_dir.path().to_path_buf()).unwrap() +} + // Fixme: Move this test to sgx-runtime: // // https://github.com/integritee-network/sgx-runtime/issues/23 @@ -94,9 +102,7 @@ pub fn test_encrypt_decrypt_state_type_works() { // given let state = given_hello_world_state(); - let temp_dir = TempDir::with_prefix("test_encrypt_decrypt_state_type_works").unwrap(); - let state_key = get_aes_repository(temp_dir.path().to_path_buf()) - .unwrap() + let state_key = temp_state_key_repository("test_encrypt_decrypt_state_type_works") .retrieve_key() .unwrap(); @@ -114,7 +120,9 @@ pub fn test_encrypt_decrypt_state_type_works() { pub fn test_write_and_load_state_works() { // given let shard: ShardIdentifier = [94u8; 32].into(); - let (state_handler, shard_dir_handle) = initialize_state_handler_with_directory_handle(&shard); + let state_key_access = Arc::new(temp_state_key_repository("test_write_and_load_state_works")); + let (state_handler, shard_dir_handle) = + initialize_state_handler_with_directory_handle(&shard, state_key_access); let state = given_hello_world_state(); @@ -134,7 +142,10 @@ pub fn test_write_and_load_state_works() { pub fn test_ensure_subsequent_state_loads_have_same_hash() { // given let shard: ShardIdentifier = [49u8; 32].into(); - let (state_handler, shard_dir_handle) = initialize_state_handler_with_directory_handle(&shard); + let state_key_access = + Arc::new(temp_state_key_repository("test_ensure_subsequent_state_loads_have_same_hash")); + let (state_handler, shard_dir_handle) = + initialize_state_handler_with_directory_handle(&shard, state_key_access); let (lock, initial_state) = state_handler.load_for_mutation(&shard).unwrap(); state_handler.write_after_mutation(initial_state.clone(), lock, &shard).unwrap(); @@ -153,7 +164,10 @@ pub fn test_write_access_locks_read_until_finished() { // given let shard: ShardIdentifier = [47u8; 32].into(); - let (state_handler, shard_dir_handle) = initialize_state_handler_with_directory_handle(&shard); + let state_key_access = + Arc::new(temp_state_key_repository("test_write_access_locks_read_until_finished")); + let (state_handler, shard_dir_handle) = + initialize_state_handler_with_directory_handle(&shard, state_key_access); let new_state_key = "my_new_state".encode(); let (lock, mut state_to_mutate) = state_handler.load_for_mutation(&shard).unwrap(); @@ -183,7 +197,10 @@ pub fn test_write_access_locks_read_until_finished() { pub fn test_state_handler_file_backend_is_initialized() { let shard: ShardIdentifier = [11u8; 32].into(); - let (state_handler, shard_dir_handle) = initialize_state_handler_with_directory_handle(&shard); + let state_key_access = + Arc::new(temp_state_key_repository("test_state_handler_file_backend_is_initialized")); + let (state_handler, shard_dir_handle) = + initialize_state_handler_with_directory_handle(&shard, state_key_access); assert!(state_handler.shard_exists(&shard).unwrap()); assert!(1 <= state_handler.list_shards().unwrap().len()); // only greater equal, because there might be other (non-test) shards present @@ -199,7 +216,11 @@ pub fn test_state_handler_file_backend_is_initialized() { pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let shard: ShardIdentifier = [17u8; 32].into(); - let (state_handler, _shard_dir_handle) = initialize_state_handler_with_directory_handle(&shard); + let state_key_access = Arc::new(temp_state_key_repository( + "test_multiple_state_updates_create_snapshots_up_to_cache_size", + )); + let (state_handler, _shard_dir_handle) = + initialize_state_handler_with_directory_handle(&shard, state_key_access); assert_eq!(1, number_of_files_in_shard_dir(&shard).unwrap()); @@ -244,8 +265,7 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); - let temp_dir = TempDir::with_prefix("test_file_io_get_state_hash_works").unwrap(); - let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); + let state_key_access = Arc::new(temp_state_key_repository("test_file_io_get_state_hash_works")); let file_io = TestStateFileIo::new(state_key_access); @@ -261,7 +281,10 @@ pub fn test_file_io_get_state_hash_works() { pub fn test_state_files_from_handler_can_be_loaded_again() { let shard: ShardIdentifier = [15u8; 32].into(); - let (state_handler, _shard_dir_handle) = initialize_state_handler_with_directory_handle(&shard); + let state_key_access = + Arc::new(temp_state_key_repository("test_state_files_from_handler_can_be_loaded_again")); + let (state_handler, _shard_dir_handle) = + initialize_state_handler_with_directory_handle(&shard, state_key_access.clone()); update_state(state_handler.as_ref(), &shard, ("test_key_1".encode(), "value1".encode())); update_state(state_handler.as_ref(), &shard, ("test_key_2".encode(), "value2".encode())); @@ -273,7 +296,7 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { update_state(state_handler.as_ref(), &shard, ("test_key_3".encode(), "value3".encode())); // We initialize another state handler to load the state from the changes we just made. - let updated_state_handler = initialize_state_handler(); + let updated_state_handler = initialize_state_handler(state_key_access); assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, number_of_files_in_shard_dir(&shard).unwrap()); assert_eq!( @@ -291,9 +314,9 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); - let temp_dir = - TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); - let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); + let state_key_access = Arc::new(temp_state_key_repository( + "test_list_state_ids_ignores_files_not_matching_the_pattern", + )); let file_io = TestStateFileIo::new(state_key_access); @@ -326,15 +349,15 @@ pub fn test_in_memory_state_initializes_from_shard_directory() { fn initialize_state_handler_with_directory_handle( shard: &ShardIdentifier, + state_key_access: Arc, ) -> (Arc, ShardDirectoryHandle) { let shard_dir_handle = ShardDirectoryHandle::new(*shard).unwrap(); - (initialize_state_handler(), shard_dir_handle) + (initialize_state_handler(state_key_access), shard_dir_handle) } -fn initialize_state_handler() -> Arc { - let temp_dir = TempDir::with_prefix("initialize_state_handler").unwrap(); - let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); - +fn initialize_state_handler( + state_key_access: Arc, +) -> Arc { let file_io = Arc::new(TestStateFileIo::new(state_key_access)); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = From d53ef306c0d5b814f61a1d8bcbefb2df5cba525f Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 09:18:13 +0200 Subject: [PATCH 19/49] fix merge errors --- enclave-runtime/src/initialization/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index b922b83f94..aa10dbabd2 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -62,9 +62,7 @@ use itp_primitives_cache::GLOBAL_PRIMITIVES_CACHE; use itp_settings::files::STATE_SNAPSHOTS_CACHE_SIZE; use itp_sgx_crypto::{ get_aes_repository, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey, - AesSeal, }; -use itp_sgx_io::StaticSealedIO; use itp_stf_state_handler::{ handle_state::HandleState, query_shard_state::QueryShardState, state_snapshot_repository::VersionedStateAccess, @@ -88,7 +86,7 @@ pub(crate) fn init_enclave( let signer = signing_key_repository.retrieve_key()?; info!("[Enclave initialized] Ed25519 prim raw : {:?}", signer.public().0); - let shielding_key_repository = Arc::new(get_rsa3072_repository(base_dir)?); + let shielding_key_repository = Arc::new(get_rsa3072_repository(base_dir.clone())?); GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT.initialize(shielding_key_repository.clone()); // Create the aes key that is used for state encryption such that a key is always present in tests. From df8c61f973683c6781e8712d6e09b7dc971c5e5d Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 09:19:24 +0200 Subject: [PATCH 20/49] [itp-sgx-crypto] add tests for aes --- core-primitives/sgx/crypto/src/aes.rs | 41 ++++++++++++++++++++++++++ core-primitives/sgx/crypto/src/lib.rs | 4 +++ enclave-runtime/src/test/tests_main.rs | 2 ++ 3 files changed, 47 insertions(+) diff --git a/core-primitives/sgx/crypto/src/aes.rs b/core-primitives/sgx/crypto/src/aes.rs index d2bf3ceeb8..208f5d658a 100644 --- a/core-primitives/sgx/crypto/src/aes.rs +++ b/core-primitives/sgx/crypto/src/aes.rs @@ -158,3 +158,44 @@ pub mod sgx { } } } + +#[cfg(feature = "test")] +pub mod sgx_tests { + use super::sgx::*; + use crate::{key_repository::AccessKey, AesSeal, AesSealing}; + use itp_sgx_temp_dir::TempDir; + + pub fn using_get_aes_repository_twice_initializes_key_only_once() { + let temp_dir = + TempDir::with_prefix("using_get_aes_repository_twice_initializes_key_only_once") + .unwrap(); + let temp_path = temp_dir.path().to_path_buf(); + let key1 = get_aes_repository(temp_path.clone()).unwrap().retrieve_key().unwrap(); + let key2 = get_aes_repository(temp_path).unwrap().retrieve_key().unwrap(); + assert_eq!(key1, key2); + } + + pub fn aes_sealing_works() { + let temp_dir = TempDir::with_prefix("aes_sealing_works").unwrap(); + let seal = AesSeal::new(temp_dir.path().to_path_buf()); + + // Create new sealed keys and unseal them + assert!(!seal.exists()); + seal.create_sealed_if_absent().unwrap(); + let key = seal.unseal_key().unwrap(); + + assert!(seal.exists()); + + // Should not change anything because the key is already there. + seal.create_sealed_if_absent().unwrap(); + let key_same = seal.unseal_key().unwrap(); + + assert_eq!(key, key_same); + + // Should overwrite previous keys. + seal.create_sealed().unwrap(); + let key_different = seal.unseal_key().unwrap(); + + assert_ne!(key_different, key); + } +} diff --git a/core-primitives/sgx/crypto/src/lib.rs b/core-primitives/sgx/crypto/src/lib.rs index 2dcd271b31..b876b05203 100644 --- a/core-primitives/sgx/crypto/src/lib.rs +++ b/core-primitives/sgx/crypto/src/lib.rs @@ -57,4 +57,8 @@ pub mod tests { pub use super::rsa3072::sgx_tests::{ rsa3072_sealing_works, using_get_rsa3072_repository_twice_initializes_key_only_once, }; + + pub use super::aes::sgx_tests::{ + aes_sealing_works, using_get_aes_repository_twice_initializes_key_only_once, + }; } diff --git a/enclave-runtime/src/test/tests_main.rs b/enclave-runtime/src/test/tests_main.rs index b6d3874f27..777627c8b0 100644 --- a/enclave-runtime/src/test/tests_main.rs +++ b/enclave-runtime/src/test/tests_main.rs @@ -91,6 +91,8 @@ pub extern "C" fn test_main_entrance() -> size_t { itp_stf_state_handler::test::sgx_tests::test_file_io_get_state_hash_works, itp_stf_state_handler::test::sgx_tests::test_list_state_ids_ignores_files_not_matching_the_pattern, itp_stf_state_handler::test::sgx_tests::test_in_memory_state_initializes_from_shard_directory, + itp_sgx_crypto::tests::aes_sealing_works, + itp_sgx_crypto::tests::using_get_aes_repository_twice_initializes_key_only_once, itp_sgx_crypto::tests::ed25529_sealing_works, itp_sgx_crypto::tests::using_get_ed25519_repository_twice_initializes_key_only_once, itp_sgx_crypto::tests::rsa3072_sealing_works, From 4202a29246970390487a34c6576e4335a74600ec Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 09:22:25 +0200 Subject: [PATCH 21/49] taplo fmt --- core-primitives/sgx/io/Cargo.toml | 2 +- core-primitives/stf-state-handler/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core-primitives/sgx/io/Cargo.toml b/core-primitives/sgx/io/Cargo.toml index 2f18915854..9c358d438b 100644 --- a/core-primitives/sgx/io/Cargo.toml +++ b/core-primitives/sgx/io/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] # sgx deps -sgx_tstd = { optional = true, features = ["untrusted_fs"], branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git" } +sgx_tstd = { optional = true, features = ["untrusted_fs"], branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git" } [features] default = ["std"] diff --git a/core-primitives/stf-state-handler/Cargo.toml b/core-primitives/stf-state-handler/Cargo.toml index 73f0f63e59..739473c96b 100644 --- a/core-primitives/stf-state-handler/Cargo.toml +++ b/core-primitives/stf-state-handler/Cargo.toml @@ -74,5 +74,5 @@ sgx = [ test = [ "itp-sgx-crypto/mocks", "itp-stf-interface/mocks", - "itp-sgx-temp-dir" + "itp-sgx-temp-dir", ] From bace8d61969efdd67ae75927e24efbec5494d89d Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 09:25:26 +0200 Subject: [PATCH 22/49] clippy --- enclave-runtime/src/initialization/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index aa10dbabd2..d7d971fa4d 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -91,7 +91,7 @@ pub(crate) fn init_enclave( // Create the aes key that is used for state encryption such that a key is always present in tests. // It will be overwritten anyway if mutual remote attestation is performed with the primary worker. - let state_key_repository = Arc::new(get_aes_repository(base_dir.clone())?); + let state_key_repository = Arc::new(get_aes_repository(base_dir)?); GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.initialize(state_key_repository.clone()); let state_file_io = Arc::new(EnclaveStateFileIo::new(state_key_repository)); From 61688aa3558810b03218d9801d0991c9e9dd98c1 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 09:26:52 +0200 Subject: [PATCH 23/49] move aes key file name constant to the aes module --- core-primitives/settings/src/lib.rs | 1 - core-primitives/sgx/crypto/src/aes.rs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core-primitives/settings/src/lib.rs b/core-primitives/settings/src/lib.rs index 1d569ac862..536949f983 100644 --- a/core-primitives/settings/src/lib.rs +++ b/core-primitives/settings/src/lib.rs @@ -42,7 +42,6 @@ pub mod files { pub static SIDECHAIN_PURGE_LIMIT: u64 = 100; // keep the last.. sidechainblocks when purging // used by enclave - pub const AES_KEY_FILE_AND_INIT_V: &str = "aes_key_sealed.bin"; pub const LIGHT_CLIENT_DB: &str = "light_client_db.bin"; pub const RA_DUMP_CERT_DER_FILE: &str = "ra_dump_cert.der"; diff --git a/core-primitives/sgx/crypto/src/aes.rs b/core-primitives/sgx/crypto/src/aes.rs index 208f5d658a..17f43c7ac2 100644 --- a/core-primitives/sgx/crypto/src/aes.rs +++ b/core-primitives/sgx/crypto/src/aes.rs @@ -21,7 +21,6 @@ use crate::{ }; use aes::Aes128; use codec::{Decode, Encode}; -use itp_settings::files::AES_KEY_FILE_AND_INIT_V; use ofb::{ cipher::{NewStreamCipher, SyncStreamCipher}, Ofb, @@ -33,6 +32,9 @@ use std::{ type AesOfb = Ofb; +/// File name of the sealed AES key data. +pub const AES_KEY_FILE_AND_INIT_V: &str = "aes_key_sealed.bin"; + #[derive(Debug, Default, Encode, Decode, Clone, Copy, PartialEq, Eq)] pub struct Aes { pub key: [u8; 16], From df29524b4a8fc74678fcf6256fa7c8111732c44a Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 09:29:47 +0200 Subject: [PATCH 24/49] [stf-state-handle] rename `TestKeyRepositoryMock` to `TestKeyRepositoryMock` to reflect that it is no longer the mock --- .../stf-state-handler/src/test/sgx_tests.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 3d6d37c51a..da659e06f9 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -47,9 +47,9 @@ use std::{sync::Arc, thread, vec::Vec}; const STATE_SNAPSHOTS_CACHE_SIZE: usize = 3; -type StateKeyRepositoryMock = KeyRepository; +type StateKeyRepository = KeyRepository; type TestStateInitializer = InitializeStateMock; -type TestStateFileIo = SgxStateFileIo; +type TestStateFileIo = SgxStateFileIo; type TestStateRepository = StateSnapshotRepository; type TestStateRepositoryLoader = StateSnapshotRepositoryLoader; @@ -78,7 +78,7 @@ impl Drop for ShardDirectoryHandle { /// Gets a temporary key repository. /// /// We pass and ID such that it doesn't clash with other temp repositories. -fn temp_state_key_repository(id: &str) -> StateKeyRepositoryMock { +fn temp_state_key_repository(id: &str) -> StateKeyRepository { let temp_dir = TempDir::with_prefix(id).unwrap(); get_aes_repository(temp_dir.path().to_path_buf()).unwrap() } @@ -349,15 +349,13 @@ pub fn test_in_memory_state_initializes_from_shard_directory() { fn initialize_state_handler_with_directory_handle( shard: &ShardIdentifier, - state_key_access: Arc, + state_key_access: Arc, ) -> (Arc, ShardDirectoryHandle) { let shard_dir_handle = ShardDirectoryHandle::new(*shard).unwrap(); (initialize_state_handler(state_key_access), shard_dir_handle) } -fn initialize_state_handler( - state_key_access: Arc, -) -> Arc { +fn initialize_state_handler(state_key_access: Arc) -> Arc { let file_io = Arc::new(TestStateFileIo::new(state_key_access)); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = From f9166849c3e668680bd4f8ab9e767729c13a499c Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 12:15:04 +0200 Subject: [PATCH 25/49] [itp-stf-state-handler] introduce `StatePathProvider` --- core-primitives/settings/src/lib.rs | 1 - .../stf-state-handler/src/file_io.rs | 45 ++++++-- .../stf-state-handler/src/test/sgx_tests.rs | 100 +++++++++++------- enclave-runtime/src/initialization/mod.rs | 7 +- 4 files changed, 103 insertions(+), 50 deletions(-) diff --git a/core-primitives/settings/src/lib.rs b/core-primitives/settings/src/lib.rs index 536949f983..b945a1a955 100644 --- a/core-primitives/settings/src/lib.rs +++ b/core-primitives/settings/src/lib.rs @@ -48,7 +48,6 @@ pub mod files { // used by worker and enclave pub const SHARDS_PATH: &str = "shards"; - pub const ENCRYPTED_STATE_FILE: &str = "state.bin"; pub const LAST_SLOT_BIN: &str = "last_slot.bin"; #[cfg(feature = "production")] diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index e8d522a9f5..ffc1140957 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -24,9 +24,6 @@ use rust_base58::base58::ToBase58; #[cfg(feature = "sgx")] use base58::ToBase58; -#[cfg(any(test, feature = "sgx"))] -use itp_settings::files::ENCRYPTED_STATE_FILE; - #[cfg(any(test, feature = "sgx"))] use std::string::String; @@ -37,6 +34,39 @@ use itp_types::ShardIdentifier; use log::error; use std::{format, path::PathBuf, vec::Vec}; +/// Encrypted state file suffix +pub const ENCRYPTED_STATE_FILE: &str = "state.bin"; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct StatePathProvider { + base_path: PathBuf, +} + +impl StatePathProvider { + pub fn new(base_path: PathBuf) -> Self { + Self { base_path } + } + + pub fn shards_directory(&self) -> PathBuf { + self.base_path.join(SHARDS_PATH) + } + + pub fn shard_path(&self, shard: &ShardIdentifier) -> PathBuf { + self.shards_directory().join(shard.encode().to_base58()) + } + + pub fn state_file_path(&self, shard: &ShardIdentifier, state_id: StateId) -> PathBuf { + self.shard_path(shard).join(to_file_name(state_id)) + } + + pub fn purge_shard_dir(&self, shard: &ShardIdentifier) { + let shard_dir_path = self.shard_path(shard); + if let Err(e) = std::fs::remove_dir_all(&shard_dir_path) { + error!("Failed to remove shard directory {:?}: {:?}", shard_dir_path, e); + } + } +} + /// Trait to abstract file I/O for state. pub trait StateFileIo { type StateType; @@ -108,6 +138,7 @@ pub mod sgx { /// SGX state file I/O. pub struct SgxStateFileIo { state_key_repository: Arc, + path_provider: StatePathProvider, _phantom: PhantomData, } @@ -117,8 +148,11 @@ pub mod sgx { ::KeyType: StateCrypto, State: SgxExternalitiesTrait, { - pub fn new(state_key_repository: Arc) -> Self { - SgxStateFileIo { state_key_repository, _phantom: PhantomData } + pub fn new( + state_key_repository: Arc, + path_provider: StatePathProvider, + ) -> Self { + SgxStateFileIo { state_key_repository, path_provider, _phantom: PhantomData } } fn read(&self, path: &Path) -> Result> { @@ -331,7 +365,6 @@ pub(crate) fn shard_path(shard: &ShardIdentifier) -> PathBuf { PathBuf::from(format!("./{}/{}", SHARDS_PATH, shard.encode().to_base58())) } -#[cfg(any(test, feature = "sgx"))] fn to_file_name(state_id: StateId) -> String { format!("{}_{}", state_id, ENCRYPTED_STATE_FILE) } diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index da659e06f9..34c0aa8693 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -20,7 +20,7 @@ use crate::{ file_io::{ purge_shard_dir, sgx::{init_shard, shard_exists, SgxStateFileIo}, - shard_path, StateFileIo, + shard_path, StateFileIo, StatePathProvider, }, handle_state::HandleState, in_memory_state_file_io::sgx::create_in_memory_state_io_from_shards_directories, @@ -43,7 +43,7 @@ use itp_sgx_io::write; use itp_sgx_temp_dir::TempDir; use itp_stf_state_observer::state_observer::StateObserver; use itp_types::{ShardIdentifier, H256}; -use std::{sync::Arc, thread, vec::Vec}; +use std::{path::PathBuf, sync::Arc, thread, vec::Vec}; const STATE_SNAPSHOTS_CACHE_SIZE: usize = 3; @@ -75,12 +75,9 @@ impl Drop for ShardDirectoryHandle { } } -/// Gets a temporary key repository. -/// -/// We pass and ID such that it doesn't clash with other temp repositories. -fn temp_state_key_repository(id: &str) -> StateKeyRepository { - let temp_dir = TempDir::with_prefix(id).unwrap(); - get_aes_repository(temp_dir.path().to_path_buf()).unwrap() +// For better readability in tests. +fn aes_repo(path: PathBuf) -> StateKeyRepository { + get_aes_repository(path).unwrap() } // Fixme: Move this test to sgx-runtime: @@ -101,10 +98,9 @@ pub fn test_sgx_state_decode_encode_works() { pub fn test_encrypt_decrypt_state_type_works() { // given let state = given_hello_world_state(); + let temp_dir = TempDir::with_prefix("test_encrypt_decrypt_state_type_works").unwrap(); - let state_key = temp_state_key_repository("test_encrypt_decrypt_state_type_works") - .retrieve_key() - .unwrap(); + let state_key = aes_repo(temp_dir.path().to_path_buf()).retrieve_key().unwrap(); // when let mut state_buffer = state.state.encode(); @@ -120,9 +116,12 @@ pub fn test_encrypt_decrypt_state_type_works() { pub fn test_write_and_load_state_works() { // given let shard: ShardIdentifier = [94u8; 32].into(); - let state_key_access = Arc::new(temp_state_key_repository("test_write_and_load_state_works")); + let temp_dir = TempDir::with_prefix("test_write_and_load_state_works").unwrap(); + let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access); + initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); let state = given_hello_world_state(); @@ -142,10 +141,13 @@ pub fn test_write_and_load_state_works() { pub fn test_ensure_subsequent_state_loads_have_same_hash() { // given let shard: ShardIdentifier = [49u8; 32].into(); - let state_key_access = - Arc::new(temp_state_key_repository("test_ensure_subsequent_state_loads_have_same_hash")); + let temp_dir = + TempDir::with_prefix("test_ensure_subsequent_state_loads_have_same_hash").unwrap(); + let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access); + initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); let (lock, initial_state) = state_handler.load_for_mutation(&shard).unwrap(); state_handler.write_after_mutation(initial_state.clone(), lock, &shard).unwrap(); @@ -164,10 +166,12 @@ pub fn test_write_access_locks_read_until_finished() { // given let shard: ShardIdentifier = [47u8; 32].into(); - let state_key_access = - Arc::new(temp_state_key_repository("test_write_access_locks_read_until_finished")); + let temp_dir = TempDir::with_prefix("test_write_access_locks_read_until_finished").unwrap(); + let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access); + initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); let new_state_key = "my_new_state".encode(); let (lock, mut state_to_mutate) = state_handler.load_for_mutation(&shard).unwrap(); @@ -197,10 +201,12 @@ pub fn test_write_access_locks_read_until_finished() { pub fn test_state_handler_file_backend_is_initialized() { let shard: ShardIdentifier = [11u8; 32].into(); - let state_key_access = - Arc::new(temp_state_key_repository("test_state_handler_file_backend_is_initialized")); + let temp_dir = TempDir::with_prefix("test_state_handler_file_backend_is_initialized").unwrap(); + let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access); + initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); assert!(state_handler.shard_exists(&shard).unwrap()); assert!(1 <= state_handler.list_shards().unwrap().len()); // only greater equal, because there might be other (non-test) shards present @@ -216,11 +222,12 @@ pub fn test_state_handler_file_backend_is_initialized() { pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let shard: ShardIdentifier = [17u8; 32].into(); - let state_key_access = Arc::new(temp_state_key_repository( - "test_multiple_state_updates_create_snapshots_up_to_cache_size", - )); + let temp_dir = TempDir::with_prefix("test_state_handler_file_backend_is_initialized").unwrap(); + let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + let (state_handler, _shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access); + initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); assert_eq!(1, number_of_files_in_shard_dir(&shard).unwrap()); @@ -265,9 +272,11 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); - let state_key_access = Arc::new(temp_state_key_repository("test_file_io_get_state_hash_works")); + let temp_dir = TempDir::with_prefix("test_file_io_get_state_hash_works").unwrap(); + let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - let file_io = TestStateFileIo::new(state_key_access); + let file_io = TestStateFileIo::new(state_key_access, path_provider); let state_id = 1234u128; let state_hash = file_io @@ -281,10 +290,16 @@ pub fn test_file_io_get_state_hash_works() { pub fn test_state_files_from_handler_can_be_loaded_again() { let shard: ShardIdentifier = [15u8; 32].into(); - let state_key_access = - Arc::new(temp_state_key_repository("test_state_files_from_handler_can_be_loaded_again")); - let (state_handler, _shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access.clone()); + let temp_dir = + TempDir::with_prefix("test_state_files_from_handler_can_be_loaded_again").unwrap(); + let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + + let (state_handler, _shard_dir_handle) = initialize_state_handler_with_directory_handle( + &shard, + state_key_access.clone(), + path_provider.clone(), + ); update_state(state_handler.as_ref(), &shard, ("test_key_1".encode(), "value1".encode())); update_state(state_handler.as_ref(), &shard, ("test_key_2".encode(), "value2".encode())); @@ -296,7 +311,7 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { update_state(state_handler.as_ref(), &shard, ("test_key_3".encode(), "value3".encode())); // We initialize another state handler to load the state from the changes we just made. - let updated_state_handler = initialize_state_handler(state_key_access); + let updated_state_handler = initialize_state_handler(state_key_access, path_provider); assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, number_of_files_in_shard_dir(&shard).unwrap()); assert_eq!( @@ -314,11 +329,12 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); - let state_key_access = Arc::new(temp_state_key_repository( - "test_list_state_ids_ignores_files_not_matching_the_pattern", - )); + let temp_dir = + TempDir::with_prefix("test_state_files_from_handler_can_be_loaded_again").unwrap(); + let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - let file_io = TestStateFileIo::new(state_key_access); + let file_io = TestStateFileIo::new(state_key_access, path_provider); let mut invalid_state_file_path = shard_path(&shard); invalid_state_file_path.push("invalid-state.bin"); @@ -350,13 +366,17 @@ pub fn test_in_memory_state_initializes_from_shard_directory() { fn initialize_state_handler_with_directory_handle( shard: &ShardIdentifier, state_key_access: Arc, + path_provider: StatePathProvider, ) -> (Arc, ShardDirectoryHandle) { let shard_dir_handle = ShardDirectoryHandle::new(*shard).unwrap(); - (initialize_state_handler(state_key_access), shard_dir_handle) + (initialize_state_handler(state_key_access, path_provider), shard_dir_handle) } -fn initialize_state_handler(state_key_access: Arc) -> Arc { - let file_io = Arc::new(TestStateFileIo::new(state_key_access)); +fn initialize_state_handler( + state_key_access: Arc, + path_provider: StatePathProvider, +) -> Arc { + let file_io = Arc::new(TestStateFileIo::new(state_key_access, path_provider)); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = TestStateRepositoryLoader::new(file_io, state_initializer.clone()); diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index d7d971fa4d..143f30c1ef 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -64,7 +64,7 @@ use itp_sgx_crypto::{ get_aes_repository, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey, }; use itp_stf_state_handler::{ - handle_state::HandleState, query_shard_state::QueryShardState, + file_io::StatePathProvider, handle_state::HandleState, query_shard_state::QueryShardState, state_snapshot_repository::VersionedStateAccess, state_snapshot_repository_loader::StateSnapshotRepositoryLoader, StateHandler, }; @@ -91,10 +91,11 @@ pub(crate) fn init_enclave( // Create the aes key that is used for state encryption such that a key is always present in tests. // It will be overwritten anyway if mutual remote attestation is performed with the primary worker. - let state_key_repository = Arc::new(get_aes_repository(base_dir)?); + let state_key_repository = Arc::new(get_aes_repository(base_dir.clone())?); GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.initialize(state_key_repository.clone()); - let state_file_io = Arc::new(EnclaveStateFileIo::new(state_key_repository)); + let state_file_io = + Arc::new(EnclaveStateFileIo::new(state_key_repository, StatePathProvider::new(base_dir))); let state_initializer = Arc::new(EnclaveStateInitializer::new(shielding_key_repository.clone())); let state_snapshot_repository_loader = StateSnapshotRepositoryLoader::< From a58ef02b81576da911b1b32e06ed2e8d5b7bdf90 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 12:45:35 +0200 Subject: [PATCH 26/49] [itp-stf-state-handler] add more methods to path provider --- .../stf-state-handler/src/file_io.rs | 150 ++++++++++-------- .../src/in_memory_state_file_io.rs | 6 +- .../stf-state-handler/src/test/sgx_tests.rs | 6 +- 3 files changed, 91 insertions(+), 71 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index ffc1140957..6ab3c732bb 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -19,20 +19,24 @@ use crate::sgx_reexport_prelude::*; #[cfg(any(test, feature = "std"))] -use rust_base58::base58::ToBase58; +use rust_base58::base58::{FromBase58, ToBase58}; #[cfg(feature = "sgx")] -use base58::ToBase58; +use base58::{FromBase58, ToBase58}; #[cfg(any(test, feature = "sgx"))] use std::string::String; use crate::{error::Result, state_snapshot_primitives::StateId}; -use codec::Encode; +use codec::{Decode, Encode}; use itp_settings::files::SHARDS_PATH; use itp_types::ShardIdentifier; use log::error; -use std::{format, path::PathBuf, vec::Vec}; +use std::{ + format, + path::{Path, PathBuf}, + vec::Vec, +}; /// Encrypted state file suffix pub const ENCRYPTED_STATE_FILE: &str = "state.bin"; @@ -55,8 +59,29 @@ impl StatePathProvider { self.shards_directory().join(shard.encode().to_base58()) } - pub fn state_file_path(&self, shard: &ShardIdentifier, state_id: StateId) -> PathBuf { - self.shard_path(shard).join(to_file_name(state_id)) + /// List any valid shards that are found in the shard path. + /// Ignore any items (files, directories) that are not valid shard identifiers. + pub fn list_shards(&self) -> Result> { + list_shards(&self.shards_directory()) + } + + pub fn list_state_ids_for_shard( + &self, + shard_identifier: &ShardIdentifier, + ) -> Result> { + let shard_path = self.shard_path(shard_identifier); + let directory_items = list_items_in_directory(&shard_path); + + Ok(directory_items + .iter() + .flat_map(|item| { + let maybe_state_id = extract_state_id_from_file_name(item.as_str()); + if maybe_state_id.is_none() { + log::warn!("Found item ({}) that does not match state snapshot naming pattern, ignoring it", item) + } + maybe_state_id + }) + .collect()) } pub fn purge_shard_dir(&self, shard: &ShardIdentifier) { @@ -65,6 +90,27 @@ impl StatePathProvider { error!("Failed to remove shard directory {:?}: {:?}", shard_dir_path, e); } } + + pub fn shard_exists(&self, shard: &ShardIdentifier) -> bool { + let shard_path = self.shard_path(shard); + if !shard_path.exists() { + return false + } + + shard_path + .read_dir() + // When the iterator over all files in the directory returns none, the directory is empty. + .map(|mut d| d.next().is_some()) + .unwrap_or(false) + } + + pub fn state_file_path(&self, shard: &ShardIdentifier, state_id: StateId) -> PathBuf { + self.shard_path(shard).join(to_file_name(state_id)) + } + + pub fn file_for_state_exists(&self, shard: &ShardIdentifier, state_id: StateId) -> bool { + self.state_file_path(shard, state_id).exists() + } } /// Trait to abstract file I/O for state. @@ -121,10 +167,8 @@ pub trait StateFileIo { #[cfg(feature = "sgx")] pub mod sgx { - use super::*; use crate::error::Error; - use base58::FromBase58; use codec::Decode; use core::fmt::Debug; use itp_hashing::Hash; @@ -197,11 +241,11 @@ pub mod sgx { shard_identifier: &ShardIdentifier, state_id: StateId, ) -> Result { - if !file_for_state_exists(shard_identifier, state_id) { + if !self.path_provider.file_for_state_exists(shard_identifier, state_id) { return Err(Error::InvalidStateId(state_id)) } - let state_path = state_file_path(shard_identifier, state_id); + let state_path = self.path_provider.state_file_path(shard_identifier, state_id); trace!("loading state from: {:?}", state_path); let state_encoded = self.read(&state_path)?; @@ -249,7 +293,7 @@ pub mod sgx { state_id: StateId, state: &Self::StateType, ) -> Result { - let state_path = state_file_path(shard_identifier, state_id); + let state_path = self.path_provider.state_file_path(shard_identifier, state_id); trace!("writing state to: {:?}", state_path); // Only save the state, the state diff is pruned. @@ -263,48 +307,23 @@ pub mod sgx { } fn remove(&self, shard_identifier: &ShardIdentifier, state_id: StateId) -> Result<()> { - fs::remove_file(state_file_path(shard_identifier, state_id)) + fs::remove_file(self.path_provider.state_file_path(shard_identifier, state_id)) .map_err(|e| Error::Other(e.into())) } fn shard_exists(&self, shard_identifier: &ShardIdentifier) -> bool { - shard_exists(shard_identifier) + self.path_provider.shard_exists(shard_identifier) } fn list_shards(&self) -> Result> { - list_shards() + self.path_provider.list_shards() } - fn list_state_ids_for_shard( - &self, - shard_identifier: &ShardIdentifier, - ) -> Result> { - let shard_path = shard_path(shard_identifier); - let directory_items = list_items_in_directory(&shard_path); - - Ok(directory_items - .iter() - .flat_map(|item| { - let maybe_state_id = extract_state_id_from_file_name(item.as_str()); - if maybe_state_id.is_none() { - warn!("Found item ({}) that does not match state snapshot naming pattern, ignoring it", item) - } - maybe_state_id - }) - .collect()) + fn list_state_ids_for_shard(&self, shard: &ShardIdentifier) -> Result> { + self.path_provider.list_state_ids_for_shard(shard) } } - fn state_file_path(shard: &ShardIdentifier, state_id: StateId) -> PathBuf { - let mut shard_file_path = shard_path(shard); - shard_file_path.push(to_file_name(state_id)); - shard_file_path - } - - fn file_for_state_exists(shard: &ShardIdentifier, state_id: StateId) -> bool { - state_file_path(shard, state_id).exists() - } - /// Returns true if a shard directory for a given identifier exists AND contains at least one state file. pub(crate) fn shard_exists(shard: &ShardIdentifier) -> bool { let shard_path = shard_path(shard); @@ -323,34 +342,32 @@ pub mod sgx { let path = shard_path(shard); fs::create_dir_all(path).map_err(|e| Error::Other(e.into())) } +} - /// List any valid shards that are found in the shard path. - /// Ignore any items (files, directories) that are not valid shard identifiers. - pub(crate) fn list_shards() -> Result> { - let directory_items = list_items_in_directory(&PathBuf::from(format!("./{}", SHARDS_PATH))); - Ok(directory_items - .iter() - .flat_map(|item| { - item.from_base58() - .ok() - .map(|encoded_shard_id| { - ShardIdentifier::decode(&mut encoded_shard_id.as_slice()).ok() - }) - .flatten() - }) - .collect()) - } +pub(crate) fn list_shards(path: &Path) -> Result> { + let directory_items = list_items_in_directory(path); + Ok(directory_items + .iter() + .flat_map(|item| { + item.from_base58() + .ok() + .map(|encoded_shard_id| { + ShardIdentifier::decode(&mut encoded_shard_id.as_slice()).ok() + }) + .flatten() + }) + .collect()) +} - fn list_items_in_directory(directory: &Path) -> Vec { - let items = match directory.read_dir() { - Ok(rd) => rd, - Err(_) => return Vec::new(), - }; +fn list_items_in_directory(directory: &Path) -> Vec { + let items = match directory.read_dir() { + Ok(rd) => rd, + Err(_) => return Vec::new(), + }; - items - .flat_map(|fr| fr.map(|de| de.file_name().into_string().ok()).ok().flatten()) - .collect() - } + items + .flat_map(|fr| fr.map(|de| de.file_name().into_string().ok()).ok().flatten()) + .collect() } /// Remove a shard directory with all of its content. @@ -369,7 +386,6 @@ fn to_file_name(state_id: StateId) -> String { format!("{}_{}", state_id, ENCRYPTED_STATE_FILE) } -#[cfg(any(test, feature = "sgx"))] fn extract_state_id_from_file_name(file_name: &str) -> Option { let state_id_str = file_name.strip_suffix(format!("_{}", ENCRYPTED_STATE_FILE).as_str())?; state_id_str.parse::().ok() diff --git a/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs b/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs index c979352db4..449c499552 100644 --- a/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs +++ b/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs @@ -224,11 +224,13 @@ fn sgx_externalities_wrapper() -> ExternalStateGenerator Result>> { - let shards = list_shards()?; + let shards = list_shards(path)?; Ok(create_in_memory_externalities_state_io(&shards)) } } diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 34c0aa8693..a7076dd086 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -330,7 +330,7 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); let temp_dir = - TempDir::with_prefix("test_state_files_from_handler_can_be_loaded_again").unwrap(); + TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); @@ -350,8 +350,10 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { pub fn test_in_memory_state_initializes_from_shard_directory() { let shard: ShardIdentifier = [45u8; 32].into(); let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); + let temp_dir = + TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); - let file_io = create_in_memory_state_io_from_shards_directories().unwrap(); + let file_io = create_in_memory_state_io_from_shards_directories(&temp_dir.path()).unwrap(); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = StateSnapshotRepositoryLoader::new(file_io.clone(), state_initializer); From 0724222ef469ba2ac80d6c1e727d10a4d5afdc3a Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 13:14:21 +0200 Subject: [PATCH 27/49] [itp-stf-state-handler/sgx-tests] remove obsolete `ShardDirectoryHandle` and fix all tests except for `test_in_memory_state_initializes_from_shard_directory` --- .../stf-state-handler/src/file_io.rs | 30 ++-- .../stf-state-handler/src/test/sgx_tests.rs | 133 +++++++----------- 2 files changed, 56 insertions(+), 107 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 6ab3c732bb..fd020c5752 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -27,7 +27,10 @@ use base58::{FromBase58, ToBase58}; #[cfg(any(test, feature = "sgx"))] use std::string::String; -use crate::{error::Result, state_snapshot_primitives::StateId}; +use crate::{ + error::{Error, Result}, + state_snapshot_primitives::StateId, +}; use codec::{Decode, Encode}; use itp_settings::files::SHARDS_PATH; use itp_types::ShardIdentifier; @@ -104,6 +107,10 @@ impl StatePathProvider { .unwrap_or(false) } + pub fn create_shard(&self, shard: &ShardIdentifier) -> Result<()> { + std::fs::create_dir_all(self.shard_path(shard)).map_err(|e| Error::Other(e.into())) + } + pub fn state_file_path(&self, shard: &ShardIdentifier, state_id: StateId) -> PathBuf { self.shard_path(shard).join(to_file_name(state_id)) } @@ -281,7 +288,7 @@ pub mod sgx { state_id: StateId, state: &Self::StateType, ) -> Result { - init_shard(&shard_identifier)?; + self.path_provider.create_shard(&shard_identifier)?; self.write(shard_identifier, state_id, state) } @@ -323,25 +330,6 @@ pub mod sgx { self.path_provider.list_state_ids_for_shard(shard) } } - - /// Returns true if a shard directory for a given identifier exists AND contains at least one state file. - pub(crate) fn shard_exists(shard: &ShardIdentifier) -> bool { - let shard_path = shard_path(shard); - if !shard_path.exists() { - return false - } - - shard_path - .read_dir() - // When the iterator over all files in the directory returns none, the directory is empty. - .map(|mut d| d.next().is_some()) - .unwrap_or(false) - } - - pub(crate) fn init_shard(shard: &ShardIdentifier) -> Result<()> { - let path = shard_path(shard); - fs::create_dir_all(path).map_err(|e| Error::Other(e.into())) - } } pub(crate) fn list_shards(path: &Path) -> Result> { diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index a7076dd086..aab46e9bf4 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -17,11 +17,7 @@ use crate::{ error::{Error, Result}, - file_io::{ - purge_shard_dir, - sgx::{init_shard, shard_exists, SgxStateFileIo}, - shard_path, StateFileIo, StatePathProvider, - }, + file_io::{sgx::SgxStateFileIo, shard_path, StateFileIo, StatePathProvider}, handle_state::HandleState, in_memory_state_file_io::sgx::create_in_memory_state_io_from_shards_directories, query_shard_state::QueryShardState, @@ -56,25 +52,6 @@ type TestStateRepositoryLoader = type TestStateObserver = StateObserver; type TestStateHandler = StateHandler; -/// Directory handle to automatically initialize a directory -/// and upon dropping the reference, removing it again. -struct ShardDirectoryHandle { - shard: ShardIdentifier, -} - -impl ShardDirectoryHandle { - pub fn new(shard: ShardIdentifier) -> Result { - given_initialized_shard(&shard)?; - Ok(ShardDirectoryHandle { shard }) - } -} - -impl Drop for ShardDirectoryHandle { - fn drop(&mut self) { - purge_shard_dir(&self.shard) - } -} - // For better readability in tests. fn aes_repo(path: PathBuf) -> StateKeyRepository { get_aes_repository(path).unwrap() @@ -119,9 +96,9 @@ pub fn test_write_and_load_state_works() { let temp_dir = TempDir::with_prefix("test_write_and_load_state_works").unwrap(); let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); - let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_provider); let state = given_hello_world_state(); @@ -133,9 +110,6 @@ pub fn test_write_and_load_state_works() { // then assert_eq!(state.state, result_state.state); - - // clean up - std::mem::drop(shard_dir_handle); } pub fn test_ensure_subsequent_state_loads_have_same_hash() { @@ -145,9 +119,9 @@ pub fn test_ensure_subsequent_state_loads_have_same_hash() { TempDir::with_prefix("test_ensure_subsequent_state_loads_have_same_hash").unwrap(); let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); - let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_provider); let (lock, initial_state) = state_handler.load_for_mutation(&shard).unwrap(); state_handler.write_after_mutation(initial_state.clone(), lock, &shard).unwrap(); @@ -155,9 +129,6 @@ pub fn test_ensure_subsequent_state_loads_have_same_hash() { let (_, loaded_state_hash) = state_handler.load_cloned(&shard).unwrap(); assert_eq!(initial_state.hash(), loaded_state_hash); - - // clean up - std::mem::drop(shard_dir_handle); } pub fn test_write_access_locks_read_until_finished() { @@ -169,9 +140,9 @@ pub fn test_write_access_locks_read_until_finished() { let temp_dir = TempDir::with_prefix("test_write_access_locks_read_until_finished").unwrap(); let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); - let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_provider); let new_state_key = "my_new_state".encode(); let (lock, mut state_to_mutate) = state_handler.load_for_mutation(&shard).unwrap(); @@ -194,9 +165,6 @@ pub fn test_write_access_locks_read_until_finished() { let _hash = state_handler.write_after_mutation(state_to_mutate, lock, &shard).unwrap(); join_handle.join().unwrap(); - - // clean up - std::mem::drop(shard_dir_handle); } pub fn test_state_handler_file_backend_is_initialized() { @@ -204,20 +172,17 @@ pub fn test_state_handler_file_backend_is_initialized() { let temp_dir = TempDir::with_prefix("test_state_handler_file_backend_is_initialized").unwrap(); let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); - let (state_handler, shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_provider.clone()); assert!(state_handler.shard_exists(&shard).unwrap()); assert!(1 <= state_handler.list_shards().unwrap().len()); // only greater equal, because there might be other (non-test) shards present - assert_eq!(1, number_of_files_in_shard_dir(&shard).unwrap()); // creates a first initialized file + assert_eq!(1, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); // creates a first initialized file let _state = state_handler.load_cloned(&shard).unwrap(); - assert_eq!(1, number_of_files_in_shard_dir(&shard).unwrap()); - - // clean up - std::mem::drop(shard_dir_handle); + assert_eq!(1, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); } pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { @@ -225,39 +190,39 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let temp_dir = TempDir::with_prefix("test_state_handler_file_backend_is_initialized").unwrap(); let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); - let (state_handler, _shard_dir_handle) = - initialize_state_handler_with_directory_handle(&shard, state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_provider.clone()); - assert_eq!(1, number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(1, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); let hash_1 = update_state( state_handler.as_ref(), &shard, ("my_key_1".encode(), "mega_secret_value".encode()), ); - assert_eq!(2, number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(2, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); let hash_2 = update_state( state_handler.as_ref(), &shard, ("my_key_2".encode(), "mega_secret_value222".encode()), ); - assert_eq!(3, number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); let hash_3 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_value3".encode()), ); - assert_eq!(3, number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); let hash_4 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_valuenot3".encode()), ); - assert_eq!(3, number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); assert_ne!(hash_1, hash_2); assert_ne!(hash_1, hash_3); @@ -266,15 +231,18 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { assert_ne!(hash_2, hash_4); assert_ne!(hash_3, hash_4); - assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!( + STATE_SNAPSHOTS_CACHE_SIZE, + path_provider.number_of_files_in_shard_dir(&shard).unwrap() + ); } pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); - let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); let temp_dir = TempDir::with_prefix("test_file_io_get_state_hash_works").unwrap(); let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); let file_io = TestStateFileIo::new(state_key_access, path_provider); @@ -294,12 +262,9 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { TempDir::with_prefix("test_state_files_from_handler_can_be_loaded_again").unwrap(); let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); - let (state_handler, _shard_dir_handle) = initialize_state_handler_with_directory_handle( - &shard, - state_key_access.clone(), - path_provider.clone(), - ); + let state_handler = initialize_state_handler(state_key_access.clone(), path_provider.clone()); update_state(state_handler.as_ref(), &shard, ("test_key_1".encode(), "value1".encode())); update_state(state_handler.as_ref(), &shard, ("test_key_2".encode(), "value2".encode())); @@ -311,9 +276,12 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { update_state(state_handler.as_ref(), &shard, ("test_key_3".encode(), "value3".encode())); // We initialize another state handler to load the state from the changes we just made. - let updated_state_handler = initialize_state_handler(state_key_access, path_provider); + let updated_state_handler = initialize_state_handler(state_key_access, path_provider.clone()); - assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!( + STATE_SNAPSHOTS_CACHE_SIZE, + path_provider.number_of_files_in_shard_dir(&shard).unwrap() + ); assert_eq!( &"value3".encode(), updated_state_handler @@ -328,16 +296,15 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); - let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); let temp_dir = TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); let file_io = TestStateFileIo::new(state_key_access, path_provider); - let mut invalid_state_file_path = shard_path(&shard); - invalid_state_file_path.push("invalid-state.bin"); + let invalid_state_file_path = path_provider.shard_path(&shard).join("invalid-state.bin"); write(&[0, 1, 2, 3, 4, 5], invalid_state_file_path).unwrap(); file_io @@ -349,9 +316,10 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { pub fn test_in_memory_state_initializes_from_shard_directory() { let shard: ShardIdentifier = [45u8; 32].into(); - let _shard_dir_handle = ShardDirectoryHandle::new(shard).unwrap(); let temp_dir = TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(&shard); let file_io = create_in_memory_state_io_from_shards_directories(&temp_dir.path()).unwrap(); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); @@ -365,15 +333,6 @@ pub fn test_in_memory_state_initializes_from_shard_directory() { assert!(state_snapshot_repository.shard_exists(&shard)); } -fn initialize_state_handler_with_directory_handle( - shard: &ShardIdentifier, - state_key_access: Arc, - path_provider: StatePathProvider, -) -> (Arc, ShardDirectoryHandle) { - let shard_dir_handle = ShardDirectoryHandle::new(*shard).unwrap(); - (initialize_state_handler(state_key_access, path_provider), shard_dir_handle) -} - fn initialize_state_handler( state_key_access: Arc, path_provider: StatePathProvider, @@ -414,19 +373,21 @@ fn given_hello_world_state() -> StfState { state } -fn given_initialized_shard(shard: &ShardIdentifier) -> Result<()> { - if shard_exists(&shard) { - purge_shard_dir(shard); +impl StatePathProvider { + fn given_initialized_shard(&self, shard: &ShardIdentifier) { + if self.shard_exists(shard) { + self.purge_shard_dir(shard); + } + self.create_shard(&shard).unwrap() } - init_shard(&shard) -} -fn number_of_files_in_shard_dir(shard: &ShardIdentifier) -> Result { - let shard_dir_path = shard_path(shard); - let files_in_dir = - std::fs::read_dir(shard_dir_path.clone()).map_err(|e| Error::Other(e.into()))?; + fn number_of_files_in_shard_dir(&self, shard: &ShardIdentifier) -> Result { + let shard_dir_path = self.shard_path(shard); + let files_in_dir = + std::fs::read_dir(shard_dir_path.clone()).map_err(|e| Error::Other(e.into()))?; - log::info!("File in shard dir: {:?}", files_in_dir); + log::info!("File in shard dir: {:?}", files_in_dir); - Ok(files_in_dir.count()) + Ok(files_in_dir.count()) + } } From d41d9b3adf32085a60152ca20ff98b77ed0d65e2 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 13:17:24 +0200 Subject: [PATCH 28/49] [itp-sgx-crypto] more accurate name for the AES key file --- core-primitives/sgx/crypto/src/aes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-primitives/sgx/crypto/src/aes.rs b/core-primitives/sgx/crypto/src/aes.rs index 17f43c7ac2..0c1414e84c 100644 --- a/core-primitives/sgx/crypto/src/aes.rs +++ b/core-primitives/sgx/crypto/src/aes.rs @@ -33,7 +33,7 @@ use std::{ type AesOfb = Ofb; /// File name of the sealed AES key data. -pub const AES_KEY_FILE_AND_INIT_V: &str = "aes_key_sealed.bin"; +pub const AES_KEY_FILE_AND_INIT_V: &str = "aes_key_and_iv_sealed_data.bin"; #[derive(Debug, Default, Encode, Decode, Clone, Copy, PartialEq, Eq)] pub struct Aes { From 26ece6696e8d853149c09f7c367830466ee255fe Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 13:36:54 +0200 Subject: [PATCH 29/49] [itp-sgx-crypto] minor test fixes --- core-primitives/stf-state-handler/src/file_io.rs | 12 ------------ .../stf-state-handler/src/test/sgx_tests.rs | 4 ++-- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index fd020c5752..d9eb3cc0ce 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -358,18 +358,6 @@ fn list_items_in_directory(directory: &Path) -> Vec { .collect() } -/// Remove a shard directory with all of its content. -pub fn purge_shard_dir(shard: &ShardIdentifier) { - let shard_dir_path = shard_path(shard); - if let Err(e) = std::fs::remove_dir_all(&shard_dir_path) { - error!("Failed to remove shard directory {:?}: {:?}", shard_dir_path, e); - } -} - -pub(crate) fn shard_path(shard: &ShardIdentifier) -> PathBuf { - PathBuf::from(format!("./{}/{}", SHARDS_PATH, shard.encode().to_base58())) -} - fn to_file_name(state_id: StateId) -> String { format!("{}_{}", state_id, ENCRYPTED_STATE_FILE) } diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index aab46e9bf4..d2e02467ba 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -17,7 +17,7 @@ use crate::{ error::{Error, Result}, - file_io::{sgx::SgxStateFileIo, shard_path, StateFileIo, StatePathProvider}, + file_io::{sgx::SgxStateFileIo, StateFileIo, StatePathProvider}, handle_state::HandleState, in_memory_state_file_io::sgx::create_in_memory_state_io_from_shards_directories, query_shard_state::QueryShardState, @@ -302,7 +302,7 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); path_provider.given_initialized_shard(&shard); - let file_io = TestStateFileIo::new(state_key_access, path_provider); + let file_io = TestStateFileIo::new(state_key_access, path_provider.clone()); let invalid_state_file_path = path_provider.shard_path(&shard).join("invalid-state.bin"); write(&[0, 1, 2, 3, 4, 5], invalid_state_file_path).unwrap(); From 6106469729948dfcacff3e61a3e8245b9fcc22fd Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 13:46:54 +0200 Subject: [PATCH 30/49] [itp-state-handler/sgx_test] extract setup method --- .../stf-state-handler/src/test/sgx_tests.rs | 70 ++++++++----------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index d2e02467ba..1bff88f7de 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -76,7 +76,6 @@ pub fn test_encrypt_decrypt_state_type_works() { // given let state = given_hello_world_state(); let temp_dir = TempDir::with_prefix("test_encrypt_decrypt_state_type_works").unwrap(); - let state_key = aes_repo(temp_dir.path().to_path_buf()).retrieve_key().unwrap(); // when @@ -93,10 +92,8 @@ pub fn test_encrypt_decrypt_state_type_works() { pub fn test_write_and_load_state_works() { // given let shard: ShardIdentifier = [94u8; 32].into(); - let temp_dir = TempDir::with_prefix("test_write_and_load_state_works").unwrap(); - let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_write_and_load_state_works", &shard); let state_handler = initialize_state_handler(state_key_access, path_provider); @@ -115,11 +112,8 @@ pub fn test_write_and_load_state_works() { pub fn test_ensure_subsequent_state_loads_have_same_hash() { // given let shard: ShardIdentifier = [49u8; 32].into(); - let temp_dir = - TempDir::with_prefix("test_ensure_subsequent_state_loads_have_same_hash").unwrap(); - let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_ensure_subsequent_state_loads_have_same_hash", &shard); let state_handler = initialize_state_handler(state_key_access, path_provider); @@ -137,10 +131,8 @@ pub fn test_write_access_locks_read_until_finished() { // given let shard: ShardIdentifier = [47u8; 32].into(); - let temp_dir = TempDir::with_prefix("test_write_access_locks_read_until_finished").unwrap(); - let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_write_access_locks_read_until_finished", &shard); let state_handler = initialize_state_handler(state_key_access, path_provider); @@ -169,10 +161,8 @@ pub fn test_write_access_locks_read_until_finished() { pub fn test_state_handler_file_backend_is_initialized() { let shard: ShardIdentifier = [11u8; 32].into(); - let temp_dir = TempDir::with_prefix("test_state_handler_file_backend_is_initialized").unwrap(); - let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_state_handler_file_backend_is_initialized", &shard); let state_handler = initialize_state_handler(state_key_access, path_provider.clone()); @@ -187,10 +177,8 @@ pub fn test_state_handler_file_backend_is_initialized() { pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let shard: ShardIdentifier = [17u8; 32].into(); - let temp_dir = TempDir::with_prefix("test_state_handler_file_backend_is_initialized").unwrap(); - let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_state_handler_file_backend_is_initialized", &shard); let state_handler = initialize_state_handler(state_key_access, path_provider.clone()); @@ -239,10 +227,8 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); - let temp_dir = TempDir::with_prefix("test_file_io_get_state_hash_works").unwrap(); - let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_file_io_get_state_hash_works", &shard); let file_io = TestStateFileIo::new(state_key_access, path_provider); @@ -258,11 +244,8 @@ pub fn test_file_io_get_state_hash_works() { pub fn test_state_files_from_handler_can_be_loaded_again() { let shard: ShardIdentifier = [15u8; 32].into(); - let temp_dir = - TempDir::with_prefix("test_state_files_from_handler_can_be_loaded_again").unwrap(); - let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_state_files_from_handler_can_be_loaded_again", &shard); let state_handler = initialize_state_handler(state_key_access.clone(), path_provider.clone()); @@ -296,11 +279,8 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); - let temp_dir = - TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); - let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (_temp_dir, state_key_access, path_provider) = + setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); let file_io = TestStateFileIo::new(state_key_access, path_provider.clone()); @@ -316,10 +296,8 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { pub fn test_in_memory_state_initializes_from_shard_directory() { let shard: ShardIdentifier = [45u8; 32].into(); - let temp_dir = - TempDir::with_prefix("test_list_state_ids_ignores_files_not_matching_the_pattern").unwrap(); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(&shard); + let (temp_dir, _, _) = + setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); let file_io = create_in_memory_state_io_from_shards_directories(&temp_dir.path()).unwrap(); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); @@ -373,6 +351,18 @@ fn given_hello_world_state() -> StfState { state } +fn setup( + id: &str, + shard: &ShardIdentifier, +) -> (TempDir, Arc, StatePathProvider) { + let temp_dir = TempDir::with_prefix(id).unwrap(); + let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); + let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); + path_provider.given_initialized_shard(shard); + + (temp_dir, state_key_access, path_provider) +} + impl StatePathProvider { fn given_initialized_shard(&self, shard: &ShardIdentifier) { if self.shard_exists(shard) { From 34ed2e6734859e4e86a4200790871fc210e31ffa Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 14:01:12 +0200 Subject: [PATCH 31/49] [itp-state-handler/sgx_test] fix last test --- core-primitives/stf-state-handler/src/test/sgx_tests.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 1bff88f7de..5617b9e8d2 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -296,10 +296,12 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { pub fn test_in_memory_state_initializes_from_shard_directory() { let shard: ShardIdentifier = [45u8; 32].into(); - let (temp_dir, _, _) = + let (_temp_dir, _, path_provider) = setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); - let file_io = create_in_memory_state_io_from_shards_directories(&temp_dir.path()).unwrap(); + let file_io = + create_in_memory_state_io_from_shards_directories(&path_provider.shards_directory()) + .unwrap(); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = StateSnapshotRepositoryLoader::new(file_io.clone(), state_initializer); From 10d6b3f6551bcd61a76911b25f98fd7c10b9be72 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 14:24:37 +0200 Subject: [PATCH 32/49] minor cleanup --- .../stf-state-handler/src/file_io.rs | 31 +++--- .../stf-state-handler/src/test/sgx_tests.rs | 98 ++++++++----------- enclave-runtime/src/initialization/mod.rs | 4 +- 3 files changed, 60 insertions(+), 73 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index d9eb3cc0ce..1936724373 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -45,11 +45,11 @@ use std::{ pub const ENCRYPTED_STATE_FILE: &str = "state.bin"; #[derive(Debug, Clone, Eq, PartialEq)] -pub struct StatePathProvider { +pub struct StatePathHelper { base_path: PathBuf, } -impl StatePathProvider { +impl StatePathHelper { pub fn new(base_path: PathBuf) -> Self { Self { base_path } } @@ -62,8 +62,9 @@ impl StatePathProvider { self.shards_directory().join(shard.encode().to_base58()) } - /// List any valid shards that are found in the shard path. - /// Ignore any items (files, directories) that are not valid shard identifiers. + /// Lists any valid shards that are found in the shard path. + /// + /// Ignores any items (files, directories) that are not valid shard identifiers. pub fn list_shards(&self) -> Result> { list_shards(&self.shards_directory()) } @@ -189,7 +190,7 @@ pub mod sgx { /// SGX state file I/O. pub struct SgxStateFileIo { state_key_repository: Arc, - path_provider: StatePathProvider, + path_helper: StatePathHelper, _phantom: PhantomData, } @@ -201,9 +202,9 @@ pub mod sgx { { pub fn new( state_key_repository: Arc, - path_provider: StatePathProvider, + path_helper: StatePathHelper, ) -> Self { - SgxStateFileIo { state_key_repository, path_provider, _phantom: PhantomData } + SgxStateFileIo { state_key_repository, path_helper, _phantom: PhantomData } } fn read(&self, path: &Path) -> Result> { @@ -248,11 +249,11 @@ pub mod sgx { shard_identifier: &ShardIdentifier, state_id: StateId, ) -> Result { - if !self.path_provider.file_for_state_exists(shard_identifier, state_id) { + if !self.path_helper.file_for_state_exists(shard_identifier, state_id) { return Err(Error::InvalidStateId(state_id)) } - let state_path = self.path_provider.state_file_path(shard_identifier, state_id); + let state_path = self.path_helper.state_file_path(shard_identifier, state_id); trace!("loading state from: {:?}", state_path); let state_encoded = self.read(&state_path)?; @@ -288,7 +289,7 @@ pub mod sgx { state_id: StateId, state: &Self::StateType, ) -> Result { - self.path_provider.create_shard(&shard_identifier)?; + self.path_helper.create_shard(&shard_identifier)?; self.write(shard_identifier, state_id, state) } @@ -300,7 +301,7 @@ pub mod sgx { state_id: StateId, state: &Self::StateType, ) -> Result { - let state_path = self.path_provider.state_file_path(shard_identifier, state_id); + let state_path = self.path_helper.state_file_path(shard_identifier, state_id); trace!("writing state to: {:?}", state_path); // Only save the state, the state diff is pruned. @@ -314,20 +315,20 @@ pub mod sgx { } fn remove(&self, shard_identifier: &ShardIdentifier, state_id: StateId) -> Result<()> { - fs::remove_file(self.path_provider.state_file_path(shard_identifier, state_id)) + fs::remove_file(self.path_helper.state_file_path(shard_identifier, state_id)) .map_err(|e| Error::Other(e.into())) } fn shard_exists(&self, shard_identifier: &ShardIdentifier) -> bool { - self.path_provider.shard_exists(shard_identifier) + self.path_helper.shard_exists(shard_identifier) } fn list_shards(&self) -> Result> { - self.path_provider.list_shards() + self.path_helper.list_shards() } fn list_state_ids_for_shard(&self, shard: &ShardIdentifier) -> Result> { - self.path_provider.list_state_ids_for_shard(shard) + self.path_helper.list_state_ids_for_shard(shard) } } } diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 37e86de7b5..31f413fa45 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -17,7 +17,7 @@ use crate::{ error::{Error, Result}, - file_io::{sgx::SgxStateFileIo, StateFileIo, StatePathProvider}, + file_io::{sgx::SgxStateFileIo, StateFileIo, StatePathHelper}, handle_state::HandleState, in_memory_state_file_io::sgx::create_in_memory_state_io_from_shards_directories, query_shard_state::QueryShardState, @@ -52,19 +52,6 @@ type TestStateRepositoryLoader = type TestStateObserver = StateObserver; type TestStateHandler = StateHandler; -// For better readability in tests. -fn aes_repo(path: PathBuf) -> StateKeyRepository { - get_aes_repository(path).unwrap() -} - -/// Gets a temporary key repository. -/// -/// We pass and ID such that it doesn't clash with other temp repositories. -fn temp_state_key_repository(id: &str) -> StateKeyRepository { - let temp_dir = TempDir::with_prefix(id).unwrap(); - get_aes_repository(temp_dir.path().to_path_buf()).unwrap() -} - // Fixme: Move this test to sgx-runtime: // // https://github.com/integritee-network/sgx-runtime/issues/23 @@ -84,7 +71,10 @@ pub fn test_encrypt_decrypt_state_type_works() { // given let state = given_hello_world_state(); let temp_dir = TempDir::with_prefix("test_encrypt_decrypt_state_type_works").unwrap(); - let state_key = aes_repo(temp_dir.path().to_path_buf()).retrieve_key().unwrap(); + let state_key = get_aes_repository(temp_dir.path().to_path_buf()) + .unwrap() + .retrieve_key() + .unwrap(); // when let mut state_buffer = state.state.encode(); @@ -100,10 +90,10 @@ pub fn test_encrypt_decrypt_state_type_works() { pub fn test_write_and_load_state_works() { // given let shard: ShardIdentifier = [94u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_write_and_load_state_works", &shard); - let state_handler = initialize_state_handler(state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_helper); let state = given_hello_world_state(); @@ -120,10 +110,10 @@ pub fn test_write_and_load_state_works() { pub fn test_ensure_subsequent_state_loads_have_same_hash() { // given let shard: ShardIdentifier = [49u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_ensure_subsequent_state_loads_have_same_hash", &shard); - let state_handler = initialize_state_handler(state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_helper); let (lock, initial_state) = state_handler.load_for_mutation(&shard).unwrap(); state_handler.write_after_mutation(initial_state.clone(), lock, &shard).unwrap(); @@ -139,10 +129,10 @@ pub fn test_write_access_locks_read_until_finished() { // given let shard: ShardIdentifier = [47u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_write_access_locks_read_until_finished", &shard); - let state_handler = initialize_state_handler(state_key_access, path_provider); + let state_handler = initialize_state_handler(state_key_access, path_helper); let new_state_key = "my_new_state".encode(); let (lock, mut state_to_mutate) = state_handler.load_for_mutation(&shard).unwrap(); @@ -169,56 +159,56 @@ pub fn test_write_access_locks_read_until_finished() { pub fn test_state_handler_file_backend_is_initialized() { let shard: ShardIdentifier = [11u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_state_handler_file_backend_is_initialized", &shard); - let state_handler = initialize_state_handler(state_key_access, path_provider.clone()); + let state_handler = initialize_state_handler(state_key_access, path_helper.clone()); assert!(state_handler.shard_exists(&shard).unwrap()); assert!(1 <= state_handler.list_shards().unwrap().len()); // only greater equal, because there might be other (non-test) shards present - assert_eq!(1, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); // creates a first initialized file + assert_eq!(1, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); // creates a first initialized file let _state = state_handler.load_cloned(&shard).unwrap(); - assert_eq!(1, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(1, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); } pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let shard: ShardIdentifier = [17u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_state_handler_file_backend_is_initialized", &shard); - let state_handler = initialize_state_handler(state_key_access, path_provider.clone()); + let state_handler = initialize_state_handler(state_key_access, path_helper.clone()); - assert_eq!(1, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(1, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); let hash_1 = update_state( state_handler.as_ref(), &shard, ("my_key_1".encode(), "mega_secret_value".encode()), ); - assert_eq!(2, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(2, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); let hash_2 = update_state( state_handler.as_ref(), &shard, ("my_key_2".encode(), "mega_secret_value222".encode()), ); - assert_eq!(3, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); let hash_3 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_value3".encode()), ); - assert_eq!(3, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); let hash_4 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_valuenot3".encode()), ); - assert_eq!(3, path_provider.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); assert_ne!(hash_1, hash_2); assert_ne!(hash_1, hash_3); @@ -229,16 +219,16 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { assert_eq!( STATE_SNAPSHOTS_CACHE_SIZE, - path_provider.number_of_files_in_shard_dir(&shard).unwrap() + path_helper.number_of_files_in_shard_dir(&shard).unwrap() ); } pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_file_io_get_state_hash_works", &shard); - let file_io = TestStateFileIo::new(state_key_access, path_provider); + let file_io = TestStateFileIo::new(state_key_access, path_helper); let state_id = 1234u128; let state_hash = file_io @@ -252,10 +242,10 @@ pub fn test_file_io_get_state_hash_works() { pub fn test_state_files_from_handler_can_be_loaded_again() { let shard: ShardIdentifier = [15u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_state_files_from_handler_can_be_loaded_again", &shard); - let state_handler = initialize_state_handler(state_key_access.clone(), path_provider.clone()); + let state_handler = initialize_state_handler(state_key_access.clone(), path_helper.clone()); update_state(state_handler.as_ref(), &shard, ("test_key_1".encode(), "value1".encode())); update_state(state_handler.as_ref(), &shard, ("test_key_2".encode(), "value2".encode())); @@ -267,11 +257,11 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { update_state(state_handler.as_ref(), &shard, ("test_key_3".encode(), "value3".encode())); // We initialize another state handler to load the state from the changes we just made. - let updated_state_handler = initialize_state_handler(state_key_access, path_provider.clone()); + let updated_state_handler = initialize_state_handler(state_key_access, path_helper.clone()); assert_eq!( STATE_SNAPSHOTS_CACHE_SIZE, - path_provider.number_of_files_in_shard_dir(&shard).unwrap() + path_helper.number_of_files_in_shard_dir(&shard).unwrap() ); assert_eq!( &"value3".encode(), @@ -287,12 +277,12 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); - let (_temp_dir, state_key_access, path_provider) = + let (_temp_dir, state_key_access, path_helper) = setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); - let file_io = TestStateFileIo::new(state_key_access, path_provider.clone()); + let file_io = TestStateFileIo::new(state_key_access, path_helper.clone()); - let invalid_state_file_path = path_provider.shard_path(&shard).join("invalid-state.bin"); + let invalid_state_file_path = path_helper.shard_path(&shard).join("invalid-state.bin"); write(&[0, 1, 2, 3, 4, 5], invalid_state_file_path).unwrap(); file_io @@ -304,12 +294,11 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { pub fn test_in_memory_state_initializes_from_shard_directory() { let shard: ShardIdentifier = [45u8; 32].into(); - let (_temp_dir, _, path_provider) = + let (_temp_dir, _, path_helper) = setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); let file_io = - create_in_memory_state_io_from_shards_directories(&path_provider.shards_directory()) - .unwrap(); + create_in_memory_state_io_from_shards_directories(&path_helper.shards_directory()).unwrap(); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = StateSnapshotRepositoryLoader::new(file_io.clone(), state_initializer); @@ -323,9 +312,9 @@ pub fn test_in_memory_state_initializes_from_shard_directory() { fn initialize_state_handler( state_key_access: Arc, - path_provider: StatePathProvider, + path_helper: StatePathHelper, ) -> Arc { - let file_io = Arc::new(TestStateFileIo::new(state_key_access, path_provider)); + let file_io = Arc::new(TestStateFileIo::new(state_key_access, path_helper)); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = TestStateRepositoryLoader::new(file_io, state_initializer.clone()); @@ -361,19 +350,16 @@ fn given_hello_world_state() -> StfState { state } -fn setup( - id: &str, - shard: &ShardIdentifier, -) -> (TempDir, Arc, StatePathProvider) { +fn setup(id: &str, shard: &ShardIdentifier) -> (TempDir, Arc, StatePathHelper) { let temp_dir = TempDir::with_prefix(id).unwrap(); - let state_key_access = Arc::new(aes_repo(temp_dir.path().to_path_buf())); - let path_provider = StatePathProvider::new(temp_dir.path().to_path_buf()); - path_provider.given_initialized_shard(shard); + let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); + let path_helper = StatePathHelper::new(temp_dir.path().to_path_buf()); + path_helper.given_initialized_shard(shard); - (temp_dir, state_key_access, path_provider) + (temp_dir, state_key_access, path_helper) } -impl StatePathProvider { +impl StatePathHelper { fn given_initialized_shard(&self, shard: &ShardIdentifier) { if self.shard_exists(shard) { self.purge_shard_dir(shard); diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index 143f30c1ef..242d16d32a 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -64,7 +64,7 @@ use itp_sgx_crypto::{ get_aes_repository, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey, }; use itp_stf_state_handler::{ - file_io::StatePathProvider, handle_state::HandleState, query_shard_state::QueryShardState, + file_io::StatePathHelper, handle_state::HandleState, query_shard_state::QueryShardState, state_snapshot_repository::VersionedStateAccess, state_snapshot_repository_loader::StateSnapshotRepositoryLoader, StateHandler, }; @@ -95,7 +95,7 @@ pub(crate) fn init_enclave( GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.initialize(state_key_repository.clone()); let state_file_io = - Arc::new(EnclaveStateFileIo::new(state_key_repository, StatePathProvider::new(base_dir))); + Arc::new(EnclaveStateFileIo::new(state_key_repository, StatePathHelper::new(base_dir))); let state_initializer = Arc::new(EnclaveStateInitializer::new(shielding_key_repository.clone())); let state_snapshot_repository_loader = StateSnapshotRepositoryLoader::< From 9ef3f20ee258640e93672127755a704a4c1145c8 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 14:29:06 +0200 Subject: [PATCH 33/49] [itp-stf-staten-handler] add minor docs. --- core-primitives/stf-state-handler/src/file_io.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 1936724373..be7a7302cb 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -44,6 +44,7 @@ use std::{ /// Encrypted state file suffix pub const ENCRYPTED_STATE_FILE: &str = "state.bin"; +/// Helps with file system operations for all files relevant for the State. #[derive(Debug, Clone, Eq, PartialEq)] pub struct StatePathHelper { base_path: PathBuf, @@ -69,6 +70,7 @@ impl StatePathHelper { list_shards(&self.shards_directory()) } + /// Lists all files with a valid state snapshot naming pattern. pub fn list_state_ids_for_shard( &self, shard_identifier: &ShardIdentifier, From d1ba94fdcedab8585bc70236fb59844f564a835c Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 14:38:24 +0200 Subject: [PATCH 34/49] fix unused import --- core-primitives/stf-state-handler/src/test/sgx_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 31f413fa45..3b8bb13630 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -39,7 +39,7 @@ use itp_sgx_io::write; use itp_sgx_temp_dir::TempDir; use itp_stf_state_observer::state_observer::StateObserver; use itp_types::{ShardIdentifier, H256}; -use std::{path::PathBuf, sync::Arc, thread, vec::Vec}; +use std::{sync::Arc, thread, vec::Vec}; const STATE_SNAPSHOTS_CACHE_SIZE: usize = 3; From 7752f5cbb189fc5ed49d13eab12ed81f42d5caf6 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 14:50:04 +0200 Subject: [PATCH 35/49] fix clippy --- core-primitives/stf-state-handler/src/file_io.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index be7a7302cb..09fcd7660a 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -339,13 +339,10 @@ pub(crate) fn list_shards(path: &Path) -> Result> { let directory_items = list_items_in_directory(path); Ok(directory_items .iter() - .flat_map(|item| { - item.from_base58() - .ok() - .map(|encoded_shard_id| { - ShardIdentifier::decode(&mut encoded_shard_id.as_slice()).ok() - }) - .flatten() + .filter_map(|item| { + item.from_base58().ok().and_then(|encoded_shard_id| { + ShardIdentifier::decode(&mut encoded_shard_id.as_slice()).ok() + }) }) .collect()) } @@ -357,7 +354,7 @@ fn list_items_in_directory(directory: &Path) -> Vec { }; items - .flat_map(|fr| fr.map(|de| de.file_name().into_string().ok()).ok().flatten()) + .filter_map(|fr| fr.ok().and_then(|de| de.file_name().into_string().ok())) .collect() } From b53f1080cf596b0beb4cee649b6b913b358b952c Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 14:51:34 +0200 Subject: [PATCH 36/49] minor typos --- core-primitives/stf-state-handler/src/file_io.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 09fcd7660a..2f1424ca6a 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -41,10 +41,12 @@ use std::{ vec::Vec, }; -/// Encrypted state file suffix +/// File name of the encrypted state file. +/// +/// It is also the suffix of all past snapshots. pub const ENCRYPTED_STATE_FILE: &str = "state.bin"; -/// Helps with file system operations for all files relevant for the State. +/// Helps with file system operations of all files relevant for the State. #[derive(Debug, Clone, Eq, PartialEq)] pub struct StatePathHelper { base_path: PathBuf, From 84879cc9e4b239d8257efc080deaf51998e75d6c Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 14:58:12 +0200 Subject: [PATCH 37/49] [itp-stf-state-handler] rename `StatePathHelper` to `StateDir` --- .../stf-state-handler/src/file_io.rs | 29 +++---- .../stf-state-handler/src/test/sgx_tests.rs | 81 +++++++++---------- enclave-runtime/src/initialization/mod.rs | 4 +- 3 files changed, 52 insertions(+), 62 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 2f1424ca6a..9d11cad9d5 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -48,11 +48,11 @@ pub const ENCRYPTED_STATE_FILE: &str = "state.bin"; /// Helps with file system operations of all files relevant for the State. #[derive(Debug, Clone, Eq, PartialEq)] -pub struct StatePathHelper { +pub struct StateDir { base_path: PathBuf, } -impl StatePathHelper { +impl StateDir { pub fn new(base_path: PathBuf) -> Self { Self { base_path } } @@ -194,7 +194,7 @@ pub mod sgx { /// SGX state file I/O. pub struct SgxStateFileIo { state_key_repository: Arc, - path_helper: StatePathHelper, + state_dir: StateDir, _phantom: PhantomData, } @@ -204,11 +204,8 @@ pub mod sgx { ::KeyType: StateCrypto, State: SgxExternalitiesTrait, { - pub fn new( - state_key_repository: Arc, - path_helper: StatePathHelper, - ) -> Self { - SgxStateFileIo { state_key_repository, path_helper, _phantom: PhantomData } + pub fn new(state_key_repository: Arc, state_dir: StateDir) -> Self { + SgxStateFileIo { state_key_repository, state_dir, _phantom: PhantomData } } fn read(&self, path: &Path) -> Result> { @@ -253,11 +250,11 @@ pub mod sgx { shard_identifier: &ShardIdentifier, state_id: StateId, ) -> Result { - if !self.path_helper.file_for_state_exists(shard_identifier, state_id) { + if !self.state_dir.file_for_state_exists(shard_identifier, state_id) { return Err(Error::InvalidStateId(state_id)) } - let state_path = self.path_helper.state_file_path(shard_identifier, state_id); + let state_path = self.state_dir.state_file_path(shard_identifier, state_id); trace!("loading state from: {:?}", state_path); let state_encoded = self.read(&state_path)?; @@ -293,7 +290,7 @@ pub mod sgx { state_id: StateId, state: &Self::StateType, ) -> Result { - self.path_helper.create_shard(&shard_identifier)?; + self.state_dir.create_shard(&shard_identifier)?; self.write(shard_identifier, state_id, state) } @@ -305,7 +302,7 @@ pub mod sgx { state_id: StateId, state: &Self::StateType, ) -> Result { - let state_path = self.path_helper.state_file_path(shard_identifier, state_id); + let state_path = self.state_dir.state_file_path(shard_identifier, state_id); trace!("writing state to: {:?}", state_path); // Only save the state, the state diff is pruned. @@ -319,20 +316,20 @@ pub mod sgx { } fn remove(&self, shard_identifier: &ShardIdentifier, state_id: StateId) -> Result<()> { - fs::remove_file(self.path_helper.state_file_path(shard_identifier, state_id)) + fs::remove_file(self.state_dir.state_file_path(shard_identifier, state_id)) .map_err(|e| Error::Other(e.into())) } fn shard_exists(&self, shard_identifier: &ShardIdentifier) -> bool { - self.path_helper.shard_exists(shard_identifier) + self.state_dir.shard_exists(shard_identifier) } fn list_shards(&self) -> Result> { - self.path_helper.list_shards() + self.state_dir.list_shards() } fn list_state_ids_for_shard(&self, shard: &ShardIdentifier) -> Result> { - self.path_helper.list_state_ids_for_shard(shard) + self.state_dir.list_state_ids_for_shard(shard) } } } diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 3b8bb13630..dfdf946751 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -17,7 +17,7 @@ use crate::{ error::{Error, Result}, - file_io::{sgx::SgxStateFileIo, StateFileIo, StatePathHelper}, + file_io::{sgx::SgxStateFileIo, StateDir, StateFileIo}, handle_state::HandleState, in_memory_state_file_io::sgx::create_in_memory_state_io_from_shards_directories, query_shard_state::QueryShardState, @@ -90,10 +90,9 @@ pub fn test_encrypt_decrypt_state_type_works() { pub fn test_write_and_load_state_works() { // given let shard: ShardIdentifier = [94u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = - setup("test_write_and_load_state_works", &shard); + let (_temp_dir, state_key_access, state_dir) = setup("test_write_and_load_state_works", &shard); - let state_handler = initialize_state_handler(state_key_access, path_helper); + let state_handler = initialize_state_handler(state_key_access, state_dir); let state = given_hello_world_state(); @@ -110,10 +109,10 @@ pub fn test_write_and_load_state_works() { pub fn test_ensure_subsequent_state_loads_have_same_hash() { // given let shard: ShardIdentifier = [49u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = + let (_temp_dir, state_key_access, state_dir) = setup("test_ensure_subsequent_state_loads_have_same_hash", &shard); - let state_handler = initialize_state_handler(state_key_access, path_helper); + let state_handler = initialize_state_handler(state_key_access, state_dir); let (lock, initial_state) = state_handler.load_for_mutation(&shard).unwrap(); state_handler.write_after_mutation(initial_state.clone(), lock, &shard).unwrap(); @@ -129,10 +128,10 @@ pub fn test_write_access_locks_read_until_finished() { // given let shard: ShardIdentifier = [47u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = + let (_temp_dir, state_key_access, state_dir) = setup("test_write_access_locks_read_until_finished", &shard); - let state_handler = initialize_state_handler(state_key_access, path_helper); + let state_handler = initialize_state_handler(state_key_access, state_dir); let new_state_key = "my_new_state".encode(); let (lock, mut state_to_mutate) = state_handler.load_for_mutation(&shard).unwrap(); @@ -159,56 +158,56 @@ pub fn test_write_access_locks_read_until_finished() { pub fn test_state_handler_file_backend_is_initialized() { let shard: ShardIdentifier = [11u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = + let (_temp_dir, state_key_access, state_dir) = setup("test_state_handler_file_backend_is_initialized", &shard); - let state_handler = initialize_state_handler(state_key_access, path_helper.clone()); + let state_handler = initialize_state_handler(state_key_access, state_dir.clone()); assert!(state_handler.shard_exists(&shard).unwrap()); assert!(1 <= state_handler.list_shards().unwrap().len()); // only greater equal, because there might be other (non-test) shards present - assert_eq!(1, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); // creates a first initialized file + assert_eq!(1, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); // creates a first initialized file let _state = state_handler.load_cloned(&shard).unwrap(); - assert_eq!(1, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(1, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); } pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let shard: ShardIdentifier = [17u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = + let (_temp_dir, state_key_access, state_dir) = setup("test_state_handler_file_backend_is_initialized", &shard); - let state_handler = initialize_state_handler(state_key_access, path_helper.clone()); + let state_handler = initialize_state_handler(state_key_access, state_dir.clone()); - assert_eq!(1, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(1, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); let hash_1 = update_state( state_handler.as_ref(), &shard, ("my_key_1".encode(), "mega_secret_value".encode()), ); - assert_eq!(2, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(2, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); let hash_2 = update_state( state_handler.as_ref(), &shard, ("my_key_2".encode(), "mega_secret_value222".encode()), ); - assert_eq!(3, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); let hash_3 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_value3".encode()), ); - assert_eq!(3, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); let hash_4 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_valuenot3".encode()), ); - assert_eq!(3, path_helper.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); assert_ne!(hash_1, hash_2); assert_ne!(hash_1, hash_3); @@ -217,18 +216,15 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { assert_ne!(hash_2, hash_4); assert_ne!(hash_3, hash_4); - assert_eq!( - STATE_SNAPSHOTS_CACHE_SIZE, - path_helper.number_of_files_in_shard_dir(&shard).unwrap() - ); + assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); } pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = + let (_temp_dir, state_key_access, state_dir) = setup("test_file_io_get_state_hash_works", &shard); - let file_io = TestStateFileIo::new(state_key_access, path_helper); + let file_io = TestStateFileIo::new(state_key_access, state_dir); let state_id = 1234u128; let state_hash = file_io @@ -242,10 +238,10 @@ pub fn test_file_io_get_state_hash_works() { pub fn test_state_files_from_handler_can_be_loaded_again() { let shard: ShardIdentifier = [15u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = + let (_temp_dir, state_key_access, state_dir) = setup("test_state_files_from_handler_can_be_loaded_again", &shard); - let state_handler = initialize_state_handler(state_key_access.clone(), path_helper.clone()); + let state_handler = initialize_state_handler(state_key_access.clone(), state_dir.clone()); update_state(state_handler.as_ref(), &shard, ("test_key_1".encode(), "value1".encode())); update_state(state_handler.as_ref(), &shard, ("test_key_2".encode(), "value2".encode())); @@ -257,12 +253,9 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { update_state(state_handler.as_ref(), &shard, ("test_key_3".encode(), "value3".encode())); // We initialize another state handler to load the state from the changes we just made. - let updated_state_handler = initialize_state_handler(state_key_access, path_helper.clone()); + let updated_state_handler = initialize_state_handler(state_key_access, state_dir.clone()); - assert_eq!( - STATE_SNAPSHOTS_CACHE_SIZE, - path_helper.number_of_files_in_shard_dir(&shard).unwrap() - ); + assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); assert_eq!( &"value3".encode(), updated_state_handler @@ -277,12 +270,12 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); - let (_temp_dir, state_key_access, path_helper) = + let (_temp_dir, state_key_access, state_dir) = setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); - let file_io = TestStateFileIo::new(state_key_access, path_helper.clone()); + let file_io = TestStateFileIo::new(state_key_access, state_dir.clone()); - let invalid_state_file_path = path_helper.shard_path(&shard).join("invalid-state.bin"); + let invalid_state_file_path = state_dir.shard_path(&shard).join("invalid-state.bin"); write(&[0, 1, 2, 3, 4, 5], invalid_state_file_path).unwrap(); file_io @@ -294,11 +287,11 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { pub fn test_in_memory_state_initializes_from_shard_directory() { let shard: ShardIdentifier = [45u8; 32].into(); - let (_temp_dir, _, path_helper) = + let (_temp_dir, _, state_dir) = setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); let file_io = - create_in_memory_state_io_from_shards_directories(&path_helper.shards_directory()).unwrap(); + create_in_memory_state_io_from_shards_directories(&state_dir.shards_directory()).unwrap(); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = StateSnapshotRepositoryLoader::new(file_io.clone(), state_initializer); @@ -312,9 +305,9 @@ pub fn test_in_memory_state_initializes_from_shard_directory() { fn initialize_state_handler( state_key_access: Arc, - path_helper: StatePathHelper, + state_dir: StateDir, ) -> Arc { - let file_io = Arc::new(TestStateFileIo::new(state_key_access, path_helper)); + let file_io = Arc::new(TestStateFileIo::new(state_key_access, state_dir)); let state_initializer = Arc::new(TestStateInitializer::new(StfState::new(Default::default()))); let state_repository_loader = TestStateRepositoryLoader::new(file_io, state_initializer.clone()); @@ -350,16 +343,16 @@ fn given_hello_world_state() -> StfState { state } -fn setup(id: &str, shard: &ShardIdentifier) -> (TempDir, Arc, StatePathHelper) { +fn setup(id: &str, shard: &ShardIdentifier) -> (TempDir, Arc, StateDir) { let temp_dir = TempDir::with_prefix(id).unwrap(); let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); - let path_helper = StatePathHelper::new(temp_dir.path().to_path_buf()); - path_helper.given_initialized_shard(shard); + let state_dir = StateDir::new(temp_dir.path().to_path_buf()); + state_dir.given_initialized_shard(shard); - (temp_dir, state_key_access, path_helper) + (temp_dir, state_key_access, state_dir) } -impl StatePathHelper { +impl StateDir { fn given_initialized_shard(&self, shard: &ShardIdentifier) { if self.shard_exists(shard) { self.purge_shard_dir(shard); diff --git a/enclave-runtime/src/initialization/mod.rs b/enclave-runtime/src/initialization/mod.rs index 242d16d32a..98fb9bc8f2 100644 --- a/enclave-runtime/src/initialization/mod.rs +++ b/enclave-runtime/src/initialization/mod.rs @@ -64,7 +64,7 @@ use itp_sgx_crypto::{ get_aes_repository, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey, }; use itp_stf_state_handler::{ - file_io::StatePathHelper, handle_state::HandleState, query_shard_state::QueryShardState, + file_io::StateDir, handle_state::HandleState, query_shard_state::QueryShardState, state_snapshot_repository::VersionedStateAccess, state_snapshot_repository_loader::StateSnapshotRepositoryLoader, StateHandler, }; @@ -95,7 +95,7 @@ pub(crate) fn init_enclave( GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.initialize(state_key_repository.clone()); let state_file_io = - Arc::new(EnclaveStateFileIo::new(state_key_repository, StatePathHelper::new(base_dir))); + Arc::new(EnclaveStateFileIo::new(state_key_repository, StateDir::new(base_dir))); let state_initializer = Arc::new(EnclaveStateInitializer::new(shielding_key_repository.clone())); let state_snapshot_repository_loader = StateSnapshotRepositoryLoader::< From 2a8d3de15fc7c680440eb19f42f78b1c9f12df1f Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 15:23:19 +0200 Subject: [PATCH 38/49] [itp-stf-state-handler] move test methods of `StateDir` to its definition --- .../stf-state-handler/src/file_io.rs | 19 +++++++++++++++++++ .../stf-state-handler/src/test/sgx_tests.rs | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 9d11cad9d5..b5625ce5be 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -123,6 +123,25 @@ impl StateDir { pub fn file_for_state_exists(&self, shard: &ShardIdentifier, state_id: StateId) -> bool { self.state_file_path(shard, state_id).exists() } + + #[cfg(feature = "test")] + fn given_initialized_shard(&self, shard: &ShardIdentifier) { + if self.shard_exists(shard) { + self.purge_shard_dir(shard); + } + self.create_shard(&shard).unwrap() + } + + #[cfg(feature = "test")] + fn number_of_files_in_shard_dir(&self, shard: &ShardIdentifier) -> Result { + let shard_dir_path = self.shard_path(shard); + let files_in_dir = + std::fs::read_dir(shard_dir_path.clone()).map_err(|e| Error::Other(e.into()))?; + + log::info!("File in shard dir: {:?}", files_in_dir); + + Ok(files_in_dir.count()) + } } /// Trait to abstract file I/O for state. diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index dfdf946751..6acff31470 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -351,22 +351,3 @@ fn setup(id: &str, shard: &ShardIdentifier) -> (TempDir, Arc (temp_dir, state_key_access, state_dir) } - -impl StateDir { - fn given_initialized_shard(&self, shard: &ShardIdentifier) { - if self.shard_exists(shard) { - self.purge_shard_dir(shard); - } - self.create_shard(&shard).unwrap() - } - - fn number_of_files_in_shard_dir(&self, shard: &ShardIdentifier) -> Result { - let shard_dir_path = self.shard_path(shard); - let files_in_dir = - std::fs::read_dir(shard_dir_path.clone()).map_err(|e| Error::Other(e.into()))?; - - log::info!("File in shard dir: {:?}", files_in_dir); - - Ok(files_in_dir.count()) - } -} From 101867c35d59e15665c9775b008f9bde5d498f49 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 15:24:35 +0200 Subject: [PATCH 39/49] [itp-stf-state-handler] replace flat_map with filter_map --- core-primitives/stf-state-handler/src/file_io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index b5625ce5be..6898cc69fb 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -82,7 +82,7 @@ impl StateDir { Ok(directory_items .iter() - .flat_map(|item| { + .filter_map(|item| { let maybe_state_id = extract_state_id_from_file_name(item.as_str()); if maybe_state_id.is_none() { log::warn!("Found item ({}) that does not match state snapshot naming pattern, ignoring it", item) From bc27cbc265e1545ed91e7999133c0c1b923eaef8 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 15:25:23 +0200 Subject: [PATCH 40/49] [itp-stf-state-handler] fix: make `StateDir` test methods public --- core-primitives/stf-state-handler/src/file_io.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 6898cc69fb..bb281e5bfe 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -125,7 +125,7 @@ impl StateDir { } #[cfg(feature = "test")] - fn given_initialized_shard(&self, shard: &ShardIdentifier) { + pub fn given_initialized_shard(&self, shard: &ShardIdentifier) { if self.shard_exists(shard) { self.purge_shard_dir(shard); } @@ -133,7 +133,7 @@ impl StateDir { } #[cfg(feature = "test")] - fn number_of_files_in_shard_dir(&self, shard: &ShardIdentifier) -> Result { + pub fn number_of_files_in_shard_dir(&self, shard: &ShardIdentifier) -> Result { let shard_dir_path = self.shard_path(shard); let files_in_dir = std::fs::read_dir(shard_dir_path.clone()).map_err(|e| Error::Other(e.into()))?; From f43c5eb637f6497cf9c43df2e696a80ffa62ef0d Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 15:42:49 +0200 Subject: [PATCH 41/49] [itp-stf-state-handler] remove unnecessary method. --- .../stf-state-handler/src/file_io.rs | 11 -------- .../stf-state-handler/src/test/sgx_tests.rs | 25 +++++++++++-------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index bb281e5bfe..e467c983d6 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -131,17 +131,6 @@ impl StateDir { } self.create_shard(&shard).unwrap() } - - #[cfg(feature = "test")] - pub fn number_of_files_in_shard_dir(&self, shard: &ShardIdentifier) -> Result { - let shard_dir_path = self.shard_path(shard); - let files_in_dir = - std::fs::read_dir(shard_dir_path.clone()).map_err(|e| Error::Other(e.into()))?; - - log::info!("File in shard dir: {:?}", files_in_dir); - - Ok(files_in_dir.count()) - } } /// Trait to abstract file I/O for state. diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 6acff31470..85e17f4719 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -16,7 +16,6 @@ */ use crate::{ - error::{Error, Result}, file_io::{sgx::SgxStateFileIo, StateDir, StateFileIo}, handle_state::HandleState, in_memory_state_file_io::sgx::create_in_memory_state_io_from_shards_directories, @@ -165,11 +164,11 @@ pub fn test_state_handler_file_backend_is_initialized() { assert!(state_handler.shard_exists(&shard).unwrap()); assert!(1 <= state_handler.list_shards().unwrap().len()); // only greater equal, because there might be other (non-test) shards present - assert_eq!(1, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); // creates a first initialized file + assert_eq!(1, state_dir.list_state_ids_for_shard(&shard).unwrap().len()); // creates a first initialized file let _state = state_handler.load_cloned(&shard).unwrap(); - assert_eq!(1, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(1, state_dir.list_state_ids_for_shard(&shard).unwrap().len()); } pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { @@ -179,35 +178,35 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let state_handler = initialize_state_handler(state_key_access, state_dir.clone()); - assert_eq!(1, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(1, state_dir.list_state_ids_for_shard(&shard).unwrap().len()); let hash_1 = update_state( state_handler.as_ref(), &shard, ("my_key_1".encode(), "mega_secret_value".encode()), ); - assert_eq!(2, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(2, state_dir.list_state_ids_for_shard(&shard).unwrap().len()); let hash_2 = update_state( state_handler.as_ref(), &shard, ("my_key_2".encode(), "mega_secret_value222".encode()), ); - assert_eq!(3, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, state_dir.list_state_ids_for_shard(&shard).unwrap().len()); let hash_3 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_value3".encode()), ); - assert_eq!(3, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, state_dir.list_state_ids_for_shard(&shard).unwrap().len()); let hash_4 = update_state( state_handler.as_ref(), &shard, ("my_key_3".encode(), "mega_secret_valuenot3".encode()), ); - assert_eq!(3, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!(3, state_dir.list_state_ids_for_shard(&shard).unwrap().len()); assert_ne!(hash_1, hash_2); assert_ne!(hash_1, hash_3); @@ -216,7 +215,10 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { assert_ne!(hash_2, hash_4); assert_ne!(hash_3, hash_4); - assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!( + STATE_SNAPSHOTS_CACHE_SIZE, + state_dir.list_state_ids_for_shard(&shard).unwrap().len() + ); } pub fn test_file_io_get_state_hash_works() { @@ -255,7 +257,10 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { // We initialize another state handler to load the state from the changes we just made. let updated_state_handler = initialize_state_handler(state_key_access, state_dir.clone()); - assert_eq!(STATE_SNAPSHOTS_CACHE_SIZE, state_dir.number_of_files_in_shard_dir(&shard).unwrap()); + assert_eq!( + STATE_SNAPSHOTS_CACHE_SIZE, + state_dir.list_state_ids_for_shard(&shard).unwrap().len() + ); assert_eq!( &"value3".encode(), updated_state_handler From a46f16ac1359d58c195a7dfb9befbd2b92f4dd11 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Fri, 26 May 2023 15:46:16 +0200 Subject: [PATCH 42/49] [itp-stf-state-handler] annotate todo with issue number --- core-primitives/stf-state-handler/src/file_io.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index e467c983d6..c6936921c2 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -32,6 +32,7 @@ use crate::{ state_snapshot_primitives::StateId, }; use codec::{Decode, Encode}; +// Todo: Can be migrated to here in the course of #1292. use itp_settings::files::SHARDS_PATH; use itp_types::ShardIdentifier; use log::error; From baa01add2a2282ab8b9e3a94ac608801ce1a3b69 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Sun, 28 May 2023 17:01:12 +0200 Subject: [PATCH 43/49] [itp-stf-state-handler/file_io] refactor methods to be more ergonomic and fix redundant `iter.collects()` --- .../stf-state-handler/src/error.rs | 4 +- .../stf-state-handler/src/file_io.rs | 101 +++++++++--------- .../src/in_memory_state_file_io.rs | 2 +- 3 files changed, 57 insertions(+), 50 deletions(-) diff --git a/core-primitives/stf-state-handler/src/error.rs b/core-primitives/stf-state-handler/src/error.rs index e2db62301c..e283c657a8 100644 --- a/core-primitives/stf-state-handler/src/error.rs +++ b/core-primitives/stf-state-handler/src/error.rs @@ -51,6 +51,8 @@ pub enum Error { OsStringConversion, #[error("SGX crypto error: {0}")] CryptoError(itp_sgx_crypto::Error), + #[error("IO error: {0}")] + IO(std::io::Error), #[error("SGX error, status: {0}")] SgxError(sgx_status_t), #[error(transparent)] @@ -59,7 +61,7 @@ pub enum Error { impl From for Error { fn from(e: std::io::Error) -> Self { - Self::Other(e.into()) + Self::IO(e) } } diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index c6936921c2..85e840f84a 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -27,10 +27,7 @@ use base58::{FromBase58, ToBase58}; #[cfg(any(test, feature = "sgx"))] use std::string::String; -use crate::{ - error::{Error, Result}, - state_snapshot_primitives::StateId, -}; +use crate::{error::Result, state_snapshot_primitives::StateId}; use codec::{Decode, Encode}; // Todo: Can be migrated to here in the course of #1292. use itp_settings::files::SHARDS_PATH; @@ -66,31 +63,16 @@ impl StateDir { self.shards_directory().join(shard.encode().to_base58()) } - /// Lists any valid shards that are found in the shard path. - /// - /// Ignores any items (files, directories) that are not valid shard identifiers. pub fn list_shards(&self) -> Result> { - list_shards(&self.shards_directory()) + Ok(list_shards(&self.shards_directory())?.collect()) } - /// Lists all files with a valid state snapshot naming pattern. pub fn list_state_ids_for_shard( &self, shard_identifier: &ShardIdentifier, ) -> Result> { let shard_path = self.shard_path(shard_identifier); - let directory_items = list_items_in_directory(&shard_path); - - Ok(directory_items - .iter() - .filter_map(|item| { - let maybe_state_id = extract_state_id_from_file_name(item.as_str()); - if maybe_state_id.is_none() { - log::warn!("Found item ({}) that does not match state snapshot naming pattern, ignoring it", item) - } - maybe_state_id - }) - .collect()) + Ok(state_ids_for_shard(shard_path.as_path())?.collect()) } pub fn purge_shard_dir(&self, shard: &ShardIdentifier) { @@ -102,19 +84,11 @@ impl StateDir { pub fn shard_exists(&self, shard: &ShardIdentifier) -> bool { let shard_path = self.shard_path(shard); - if !shard_path.exists() { - return false - } - - shard_path - .read_dir() - // When the iterator over all files in the directory returns none, the directory is empty. - .map(|mut d| d.next().is_some()) - .unwrap_or(false) + shard_path.exists() && shard_contains_state(&shard_path) } pub fn create_shard(&self, shard: &ShardIdentifier) -> Result<()> { - std::fs::create_dir_all(self.shard_path(shard)).map_err(|e| Error::Other(e.into())) + Ok(std::fs::create_dir_all(self.shard_path(shard))?) } pub fn state_file_path(&self, shard: &ShardIdentifier, state_id: StateId) -> PathBuf { @@ -343,27 +317,58 @@ pub mod sgx { } } -pub(crate) fn list_shards(path: &Path) -> Result> { - let directory_items = list_items_in_directory(path); - Ok(directory_items - .iter() - .filter_map(|item| { - item.from_base58().ok().and_then(|encoded_shard_id| { - ShardIdentifier::decode(&mut encoded_shard_id.as_slice()).ok() - }) +/// Lists all files with a valid state snapshot naming pattern. +pub(crate) fn state_ids_for_shard(shard_path: &Path) -> Result> { + Ok(items_in_directory(shard_path)?.filter_map(|item| { + match extract_state_id_from_file_name(&item) { + Some(state_id) => Some(state_id), + None => { + log::warn!( + "Found item ({}) that does not match state snapshot naming pattern, ignoring it", + item + ); + None + }, + } + })) +} + +/// Returns an iterator over all valid shards in a directory. +/// +/// Ignore any items (files, directories) that are not valid shard identifiers. +pub(crate) fn list_shards(path: &Path) -> Result> { + items_in_directory(path).map(|items| { + items.filter_map(|base58| match shard_from_base58(&base58) { + Ok(shard) => Some(shard), + Err(e) => { + error!("Found invalid shard ({}). Error: {:?}", base58, e); + None + }, }) - .collect()) + }) +} + +fn shard_from_base58(base58: &str) -> Result { + let vec = base58.from_base58()?; + Ok(Decode::decode(&mut vec.as_slice())?) } -fn list_items_in_directory(directory: &Path) -> Vec { - let items = match directory.read_dir() { - Ok(rd) => rd, - Err(_) => return Vec::new(), - }; +/// Returns an iterator over all filenames in a directory. +fn items_in_directory(directory: &Path) -> Result> { + Ok(directory + .read_dir()? + .filter_map(|fr| fr.ok().and_then(|de| de.file_name().into_string().ok()))) +} - items - .filter_map(|fr| fr.ok().and_then(|de| de.file_name().into_string().ok())) - .collect() +fn shard_contains_state(path: &Path) -> bool { + // If at least on item can be decoded into a state id, the shard is not empty. + match state_ids_for_shard(path) { + Ok(mut iter) => iter.next().is_some(), + Err(e) => { + error!("Error in reading shard dir: {:?}", e); + false + }, + } } fn to_file_name(state_id: StateId) -> String { diff --git a/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs b/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs index 449c499552..44c539e1bb 100644 --- a/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs +++ b/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs @@ -230,7 +230,7 @@ pub mod sgx { pub fn create_in_memory_state_io_from_shards_directories( path: &Path, ) -> Result>> { - let shards = list_shards(path)?; + let shards: Vec = list_shards(path)?.collect(); Ok(create_in_memory_externalities_state_io(&shards)) } } From 3940250c1a2b5f7e069e581e3fa88481f60bd866 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Sun, 28 May 2023 17:18:07 +0200 Subject: [PATCH 44/49] [itp-stf-state-handler/file_io] rename `directory_contains_state` to `directory_contains_valid_state_id` --- core-primitives/stf-state-handler/src/file_io.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 85e840f84a..1b07e8d4c6 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -84,7 +84,7 @@ impl StateDir { pub fn shard_exists(&self, shard: &ShardIdentifier) -> bool { let shard_path = self.shard_path(shard); - shard_path.exists() && shard_contains_state(&shard_path) + shard_path.exists() && shard_contains_valid_state_id(&shard_path) } pub fn create_shard(&self, shard: &ShardIdentifier) -> Result<()> { @@ -360,7 +360,7 @@ fn items_in_directory(directory: &Path) -> Result> .filter_map(|fr| fr.ok().and_then(|de| de.file_name().into_string().ok()))) } -fn shard_contains_state(path: &Path) -> bool { +fn shard_contains_valid_state_id(path: &Path) -> bool { // If at least on item can be decoded into a state id, the shard is not empty. match state_ids_for_shard(path) { Ok(mut iter) => iter.next().is_some(), From 7f489a502aacb79837d54ef08c6eccdba42acd42 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Sun, 28 May 2023 17:18:45 +0200 Subject: [PATCH 45/49] [itp-stf-state-handler/file_io] fix test by defaulting to empty vec in case the shard directory does not exist --- core-primitives/stf-state-handler/src/file_io.rs | 5 ++++- .../stf-state-handler/src/in_memory_state_file_io.rs | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 1b07e8d4c6..f5f3b29899 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -64,7 +64,10 @@ impl StateDir { } pub fn list_shards(&self) -> Result> { - Ok(list_shards(&self.shards_directory())?.collect()) + Ok(list_shards(&self.shards_directory()) + .map(|iter| iter.collect()) + // return an empty vec in case the directory does not exis. + .unwrap_or_default()) } pub fn list_state_ids_for_shard( diff --git a/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs b/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs index 44c539e1bb..702ccac0ab 100644 --- a/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs +++ b/core-primitives/stf-state-handler/src/in_memory_state_file_io.rs @@ -230,7 +230,8 @@ pub mod sgx { pub fn create_in_memory_state_io_from_shards_directories( path: &Path, ) -> Result>> { - let shards: Vec = list_shards(path)?.collect(); + let shards: Vec = + list_shards(path).map(|iter| iter.collect()).unwrap_or_default(); Ok(create_in_memory_externalities_state_io(&shards)) } } From 9418730789864481f698da2a59a85a90760c9354 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Sun, 28 May 2023 17:19:31 +0200 Subject: [PATCH 46/49] [itp-stf-state-handler/file_io] remove unnecessary nesting --- core-primitives/stf-state-handler/src/file_io.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index f5f3b29899..9f0b5d7ea0 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -340,15 +340,13 @@ pub(crate) fn state_ids_for_shard(shard_path: &Path) -> Result Result> { - items_in_directory(path).map(|items| { - items.filter_map(|base58| match shard_from_base58(&base58) { - Ok(shard) => Some(shard), - Err(e) => { - error!("Found invalid shard ({}). Error: {:?}", base58, e); - None - }, - }) - }) + Ok(items_in_directory(path)?.filter_map(|base58| match shard_from_base58(&base58) { + Ok(shard) => Some(shard), + Err(e) => { + error!("Found invalid shard ({}). Error: {:?}", base58, e); + None + }, + })) } fn shard_from_base58(base58: &str) -> Result { From 27e613de3a2864626e061c2bb3d6b9cdc523fbf9 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Sun, 28 May 2023 17:20:30 +0200 Subject: [PATCH 47/49] [itp-stf-state-handler/file_io] typo --- core-primitives/stf-state-handler/src/file_io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 9f0b5d7ea0..2979039c78 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -66,7 +66,7 @@ impl StateDir { pub fn list_shards(&self) -> Result> { Ok(list_shards(&self.shards_directory()) .map(|iter| iter.collect()) - // return an empty vec in case the directory does not exis. + // return an empty vec in case the directory does not exist. .unwrap_or_default()) } From b472e154b2fcb0f778088933f6676a4416f14567 Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Mon, 29 May 2023 09:22:59 +0200 Subject: [PATCH 48/49] [itp-stf-state-handler/file_io] minor improvement in function --- core-primitives/stf-state-handler/src/file_io.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core-primitives/stf-state-handler/src/file_io.rs b/core-primitives/stf-state-handler/src/file_io.rs index 2979039c78..c0de994cb5 100644 --- a/core-primitives/stf-state-handler/src/file_io.rs +++ b/core-primitives/stf-state-handler/src/file_io.rs @@ -302,8 +302,7 @@ pub mod sgx { } fn remove(&self, shard_identifier: &ShardIdentifier, state_id: StateId) -> Result<()> { - fs::remove_file(self.state_dir.state_file_path(shard_identifier, state_id)) - .map_err(|e| Error::Other(e.into())) + Ok(fs::remove_file(self.state_dir.state_file_path(shard_identifier, state_id))?) } fn shard_exists(&self, shard_identifier: &ShardIdentifier) -> bool { From 3476506f7dded7fa8afb4ffefe4e420dd03a2fde Mon Sep 17 00:00:00 2001 From: Christian Langenbacher Date: Mon, 29 May 2023 09:26:14 +0200 Subject: [PATCH 49/49] [itp-stf-state-handler/sgx_tests] rename setup -> test_setup --- .../stf-state-handler/src/test/sgx_tests.rs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/core-primitives/stf-state-handler/src/test/sgx_tests.rs b/core-primitives/stf-state-handler/src/test/sgx_tests.rs index 85e17f4719..42c33f512b 100644 --- a/core-primitives/stf-state-handler/src/test/sgx_tests.rs +++ b/core-primitives/stf-state-handler/src/test/sgx_tests.rs @@ -89,7 +89,8 @@ pub fn test_encrypt_decrypt_state_type_works() { pub fn test_write_and_load_state_works() { // given let shard: ShardIdentifier = [94u8; 32].into(); - let (_temp_dir, state_key_access, state_dir) = setup("test_write_and_load_state_works", &shard); + let (_temp_dir, state_key_access, state_dir) = + test_setup("test_write_and_load_state_works", &shard); let state_handler = initialize_state_handler(state_key_access, state_dir); @@ -109,7 +110,7 @@ pub fn test_ensure_subsequent_state_loads_have_same_hash() { // given let shard: ShardIdentifier = [49u8; 32].into(); let (_temp_dir, state_key_access, state_dir) = - setup("test_ensure_subsequent_state_loads_have_same_hash", &shard); + test_setup("test_ensure_subsequent_state_loads_have_same_hash", &shard); let state_handler = initialize_state_handler(state_key_access, state_dir); @@ -128,7 +129,7 @@ pub fn test_write_access_locks_read_until_finished() { // given let shard: ShardIdentifier = [47u8; 32].into(); let (_temp_dir, state_key_access, state_dir) = - setup("test_write_access_locks_read_until_finished", &shard); + test_setup("test_write_access_locks_read_until_finished", &shard); let state_handler = initialize_state_handler(state_key_access, state_dir); @@ -158,7 +159,7 @@ pub fn test_write_access_locks_read_until_finished() { pub fn test_state_handler_file_backend_is_initialized() { let shard: ShardIdentifier = [11u8; 32].into(); let (_temp_dir, state_key_access, state_dir) = - setup("test_state_handler_file_backend_is_initialized", &shard); + test_setup("test_state_handler_file_backend_is_initialized", &shard); let state_handler = initialize_state_handler(state_key_access, state_dir.clone()); @@ -174,7 +175,7 @@ pub fn test_state_handler_file_backend_is_initialized() { pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { let shard: ShardIdentifier = [17u8; 32].into(); let (_temp_dir, state_key_access, state_dir) = - setup("test_state_handler_file_backend_is_initialized", &shard); + test_setup("test_state_handler_file_backend_is_initialized", &shard); let state_handler = initialize_state_handler(state_key_access, state_dir.clone()); @@ -224,7 +225,7 @@ pub fn test_multiple_state_updates_create_snapshots_up_to_cache_size() { pub fn test_file_io_get_state_hash_works() { let shard: ShardIdentifier = [21u8; 32].into(); let (_temp_dir, state_key_access, state_dir) = - setup("test_file_io_get_state_hash_works", &shard); + test_setup("test_file_io_get_state_hash_works", &shard); let file_io = TestStateFileIo::new(state_key_access, state_dir); @@ -241,7 +242,7 @@ pub fn test_file_io_get_state_hash_works() { pub fn test_state_files_from_handler_can_be_loaded_again() { let shard: ShardIdentifier = [15u8; 32].into(); let (_temp_dir, state_key_access, state_dir) = - setup("test_state_files_from_handler_can_be_loaded_again", &shard); + test_setup("test_state_files_from_handler_can_be_loaded_again", &shard); let state_handler = initialize_state_handler(state_key_access.clone(), state_dir.clone()); @@ -276,7 +277,7 @@ pub fn test_state_files_from_handler_can_be_loaded_again() { pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { let shard: ShardIdentifier = [21u8; 32].into(); let (_temp_dir, state_key_access, state_dir) = - setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); + test_setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); let file_io = TestStateFileIo::new(state_key_access, state_dir.clone()); @@ -293,7 +294,7 @@ pub fn test_list_state_ids_ignores_files_not_matching_the_pattern() { pub fn test_in_memory_state_initializes_from_shard_directory() { let shard: ShardIdentifier = [45u8; 32].into(); let (_temp_dir, _, state_dir) = - setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); + test_setup("test_list_state_ids_ignores_files_not_matching_the_pattern", &shard); let file_io = create_in_memory_state_io_from_shards_directories(&state_dir.shards_directory()).unwrap(); @@ -348,7 +349,7 @@ fn given_hello_world_state() -> StfState { state } -fn setup(id: &str, shard: &ShardIdentifier) -> (TempDir, Arc, StateDir) { +fn test_setup(id: &str, shard: &ShardIdentifier) -> (TempDir, Arc, StateDir) { let temp_dir = TempDir::with_prefix(id).unwrap(); let state_key_access = Arc::new(get_aes_repository(temp_dir.path().to_path_buf()).unwrap()); let state_dir = StateDir::new(temp_dir.path().to_path_buf());