diff --git a/Cargo.lock b/Cargo.lock index fe45180763..483d6a04e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2761,6 +2761,7 @@ dependencies = [ "itp-enclave-metrics", "itp-node-api", "itp-settings", + "itp-storage", "itp-types", "itp-utils", "its-consensus-slots", @@ -3338,6 +3339,7 @@ dependencies = [ "itc-parentchain", "itp-enclave-api-ffi", "itp-settings", + "itp-storage", "itp-types", "log 0.4.17", "parity-scale-codec", @@ -7980,9 +7982,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0959fd6f767df20b231736396e4f602171e00d95205676286e79d4a4eb67bef" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" @@ -9078,7 +9080,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" dependencies = [ - "spin 0.9.7", + "spin 0.9.8", "wasmi_arena", "wasmi_core 0.5.0", "wasmparser-nostd", diff --git a/core-primitives/enclave-api/Cargo.toml b/core-primitives/enclave-api/Cargo.toml index dfb221f160..e4dffe62e1 100644 --- a/core-primitives/enclave-api/Cargo.toml +++ b/core-primitives/enclave-api/Cargo.toml @@ -22,4 +22,5 @@ sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "po itc-parentchain = { path = "../../core/parentchain/parentchain-crate" } itp-enclave-api-ffi = { path = "ffi" } itp-settings = { path = "../settings" } +itp-storage = { path = "../storage" } itp-types = { path = "../types" } diff --git a/core-primitives/enclave-api/ffi/src/lib.rs b/core-primitives/enclave-api/ffi/src/lib.rs index 5e14b7b904..b4038c7094 100644 --- a/core-primitives/enclave-api/ffi/src/lib.rs +++ b/core-primitives/enclave-api/ffi/src/lib.rs @@ -67,6 +67,10 @@ extern "C" { retval: *mut sgx_status_t, blocks: *const u8, blocks_size: usize, + events: *const u8, + events_size: usize, + events_proofs: *const u8, + events_proofs_size: usize, nonce: *const u32, ) -> sgx_status_t; diff --git a/core-primitives/enclave-api/src/sidechain.rs b/core-primitives/enclave-api/src/sidechain.rs index 0b045839d3..196852c3f0 100644 --- a/core-primitives/enclave-api/src/sidechain.rs +++ b/core-primitives/enclave-api/src/sidechain.rs @@ -20,15 +20,19 @@ use crate::{error::Error, Enclave, EnclaveResult}; use codec::Encode; use frame_support::ensure; use itp_enclave_api_ffi as ffi; +use itp_storage::StorageProof; use sgx_types::sgx_status_t; use sp_runtime::{generic::SignedBlock, traits::Block as ParentchainBlockTrait}; /// trait for handling blocks on the side chain pub trait Sidechain: Send + Sync + 'static { - /// Sync parentchain blocks and execute pending tops in the enclave + /// Sync parentchain blocks and events. Execute pending tops + /// and events proof in the enclave. fn sync_parentchain( &self, blocks: &[SignedBlock], + events: &[Vec], + events_proofs: &[StorageProof], nonce: u32, ) -> EnclaveResult<()>; @@ -39,10 +43,14 @@ impl Sidechain for Enclave { fn sync_parentchain( &self, blocks: &[SignedBlock], + events: &[Vec], + events_proofs: &[StorageProof], nonce: u32, ) -> EnclaveResult<()> { let mut retval = sgx_status_t::SGX_SUCCESS; let blocks_enc = blocks.encode(); + let events_enc = events.encode(); + let events_proofs_enc = events_proofs.encode(); let result = unsafe { ffi::sync_parentchain( @@ -50,6 +58,10 @@ impl Sidechain for Enclave { &mut retval, blocks_enc.as_ptr(), blocks_enc.len(), + events_enc.as_ptr(), + events_enc.len(), + events_proofs_enc.as_ptr(), + events_proofs_enc.len(), &nonce, ) }; diff --git a/core-primitives/node-api/api-client-extensions/src/chain.rs b/core-primitives/node-api/api-client-extensions/src/chain.rs index 3630409918..11376adbe2 100644 --- a/core-primitives/node-api/api-client-extensions/src/chain.rs +++ b/core-primitives/node-api/api-client-extensions/src/chain.rs @@ -17,14 +17,19 @@ use crate::{ApiClientError, ApiResult}; use itp_api_client_types::{Block, SignedBlock}; -use itp_types::parentchain::{BlockNumber, Hash, Header, StorageProof}; +use itp_types::{ + parentchain::{BlockNumber, Hash, Header, StorageProof}, + H256, +}; use sp_finality_grandpa::{AuthorityList, VersionedAuthorityList, GRANDPA_AUTHORITIES_KEY}; use sp_runtime::traits::GetRuntimeBlockType; use substrate_api_client::{ - primitives::StorageKey, rpc::Request, Api, ExtrinsicParams, FrameSystemConfig, GetBlock, + rpc::Request, serde_impls::StorageKey, Api, ExtrinsicParams, FrameSystemConfig, GetBlock, GetHeader, GetStorage, }; +pub type Events = Vec; + /// ApiClient extension that simplifies chain data access. pub trait ChainApi { fn last_finalized_block(&self) -> ApiResult>; @@ -36,8 +41,10 @@ pub trait ChainApi { /// Returns an empty vector if from is greater than to. fn get_blocks(&self, from: BlockNumber, to: BlockNumber) -> ApiResult>; fn is_grandpa_available(&self) -> ApiResult; - fn grandpa_authorities(&self, hash: Option) -> ApiResult; - fn grandpa_authorities_proof(&self, hash: Option) -> ApiResult; + fn grandpa_authorities(&self, hash: Option) -> ApiResult; + fn grandpa_authorities_proof(&self, hash: Option) -> ApiResult; + fn get_events_value_proof(&self, block_hash: Option) -> ApiResult; + fn get_events_for_block(&self, block_hash: Option) -> ApiResult; } impl ChainApi for Api @@ -100,4 +107,15 @@ where .map(|read_proof| read_proof.proof.into_iter().map(|bytes| bytes.0).collect()) .unwrap_or_default()) } + + fn get_events_value_proof(&self, block_hash: Option) -> ApiResult { + Ok(self + .get_storage_value_proof("System", "Events", block_hash)? + .map(|read_proof| read_proof.proof.into_iter().map(|bytes| bytes.0).collect()) + .unwrap_or_default()) + } + + fn get_events_for_block(&self, block_hash: Option) -> ApiResult { + Ok(self.get_storage_value("System", "Events", block_hash)?.unwrap_or_default()) + } } diff --git a/enclave-runtime/Enclave.edl b/enclave-runtime/Enclave.edl index 924c002c5e..625bb1e5fb 100644 --- a/enclave-runtime/Enclave.edl +++ b/enclave-runtime/Enclave.edl @@ -63,6 +63,8 @@ enclave { public sgx_status_t sync_parentchain( [in, size=blocks_size] uint8_t* blocks, size_t blocks_size, + [in, size=events_size] uint8_t* events, size_t events_size, + [in, size=events_proofs_size] uint8_t* events_proofs, size_t events_proofs_size, [in] uint32_t* nonce ); diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index 4fb612c2aa..dbb83f5adb 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -52,6 +52,7 @@ 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_io::StaticSealedIO; +use itp_storage::StorageProof; use itp_types::{ShardIdentifier, SignedBlock}; use itp_utils::write_slice_and_whitespace_pad; use log::*; @@ -338,6 +339,10 @@ pub unsafe extern "C" fn init_shard(shard: *const u8, shard_size: u32) -> sgx_st pub unsafe extern "C" fn sync_parentchain( blocks_to_sync: *const u8, blocks_to_sync_size: usize, + _events_to_sync: *const u8, + _events_to_sync_size: *const u8, + events_proofs_to_sync: *const u8, + events_proofs_to_sync_size: usize, _nonce: *const u32, ) -> sgx_status_t { let blocks_to_sync = match Vec::::decode_raw(blocks_to_sync, blocks_to_sync_size) { @@ -345,6 +350,21 @@ pub unsafe extern "C" fn sync_parentchain( Err(e) => return Error::Codec(e).into(), }; + let events_proofs_to_sync = + match Vec::::decode_raw(events_proofs_to_sync, events_proofs_to_sync_size) { + Ok(events_proofs) => events_proofs, + Err(e) => return Error::Codec(e).into(), + }; + + let blocks_to_sync_merkle_roots: Vec = + blocks_to_sync.iter().map(|block| block.block.header.state_root).collect(); + + if let Err(e) = validate_events(&events_proofs_to_sync, &blocks_to_sync_merkle_roots) { + return e.into() + } + + // TODO: Need to pass validated events down this path or store them somewhere such that + // the `indirect_calls_executor` can access them to verify extrinsics in each block have succeeded or not. if let Err(e) = dispatch_parentchain_blocks_for_import::(blocks_to_sync) { return e.into() } @@ -381,6 +401,20 @@ fn dispatch_parentchain_blocks_for_import Ok(()) } +// ANDREW +/// Validates the events coming from the parentchain +fn validate_events( + events_proofs: &Vec, + blocks_merkle_roots: &Vec, +) -> Result<()> { + info!( + "Validating events, events_proofs_length: {:?}, blocks_merkle_roots_lengths: {:?}", + events_proofs.len(), + blocks_merkle_roots.len() + ); + Ok(()) +} + /// Triggers the import of parentchain blocks when using a queue to sync parentchain block import /// with sidechain block production. /// diff --git a/service/Cargo.toml b/service/Cargo.toml index 1da4b473c4..1eb564c6be 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -48,6 +48,7 @@ itp-enclave-api = { path = "../core-primitives/enclave-api" } itp-enclave-metrics = { path = "../core-primitives/enclave-metrics" } itp-node-api = { path = "../core-primitives/node-api" } itp-settings = { path = "../core-primitives/settings" } +itp-storage = { path = "../core-primitives/storage" } itp-types = { path = "../core-primitives/types" } itp-utils = { path = "../core-primitives/utils" } its-consensus-slots = { path = "../sidechain/consensus/slots" } diff --git a/service/src/parentchain_handler.rs b/service/src/parentchain_handler.rs index 3a64aaaf0b..62aafb0bde 100644 --- a/service/src/parentchain_handler.rs +++ b/service/src/parentchain_handler.rs @@ -23,6 +23,7 @@ use itc_parentchain::{ }; use itp_enclave_api::{enclave_base::EnclaveBase, sidechain::Sidechain}; use itp_node_api::api_client::ChainApi; +use itp_storage::StorageProof; use log::*; use my_node_runtime::Header; use sp_finality_grandpa::VersionedAuthorityList; @@ -140,7 +141,26 @@ where return Ok(until_synced_header) } - self.enclave_api.sync_parentchain(block_chunk_to_sync.as_slice(), 0)?; + let events_chunk_to_sync: Vec> = block_chunk_to_sync + .iter() + .map(|block| { + self.parentchain_api.get_events_for_block(Some(block.block.header.hash())) + }) + .collect::, _>>()?; + + let events_proofs_chunk_to_sync: Vec = block_chunk_to_sync + .iter() + .map(|block| { + self.parentchain_api.get_events_value_proof(Some(block.block.header.hash())) + }) + .collect::, _>>()?; + + self.enclave_api.sync_parentchain( + block_chunk_to_sync.as_slice(), + events_chunk_to_sync.as_slice(), + events_proofs_chunk_to_sync.as_slice(), + 0, + )?; until_synced_header = block_chunk_to_sync .last() diff --git a/service/src/tests/mocks/enclave_api_mock.rs b/service/src/tests/mocks/enclave_api_mock.rs index c4952f4cdb..b1a0ca2209 100644 --- a/service/src/tests/mocks/enclave_api_mock.rs +++ b/service/src/tests/mocks/enclave_api_mock.rs @@ -24,6 +24,7 @@ use itc_parentchain::primitives::{ }; use itp_enclave_api::{enclave_base::EnclaveBase, sidechain::Sidechain, EnclaveResult}; use itp_settings::worker::MR_ENCLAVE_SIZE; +use itp_storage::StorageProof; use sgx_crypto_helper::rsa3072::Rsa3072PubKey; use sp_core::ed25519; @@ -88,6 +89,8 @@ impl Sidechain for EnclaveMock { fn sync_parentchain( &self, _blocks: &[sp_runtime::generic::SignedBlock], + _events: &[Vec], + _events_proofs: &[StorageProof], _nonce: u32, ) -> EnclaveResult<()> { Ok(()) diff --git a/service/src/tests/mocks/parentchain_api_mock.rs b/service/src/tests/mocks/parentchain_api_mock.rs index 8971a95ebe..cc19c2baa4 100644 --- a/service/src/tests/mocks/parentchain_api_mock.rs +++ b/service/src/tests/mocks/parentchain_api_mock.rs @@ -20,7 +20,10 @@ use itc_parentchain_test::{ parentchain_header_builder::ParentchainHeaderBuilder, }; use itp_node_api::api_client::{ApiResult, ChainApi, SignedBlock}; -use itp_types::parentchain::{Hash, Header, StorageProof}; +use itp_types::{ + parentchain::{Hash, Header, StorageProof}, + H256, +}; use sp_finality_grandpa::AuthorityList; pub struct ParentchainApiMock { @@ -84,4 +87,15 @@ impl ChainApi for ParentchainApiMock { fn grandpa_authorities_proof(&self, _hash: Option) -> ApiResult { todo!() } + + fn get_events_value_proof(&self, _block_hash: Option) -> ApiResult { + Ok(Default::default()) + } + + fn get_events_for_block( + &self, + _block_hash: Option, + ) -> ApiResult { + Ok(Default::default()) + } }