diff --git a/Cargo.lock b/Cargo.lock index bd8046f0f4..2339ab7f3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3754,6 +3754,7 @@ dependencies = [ name = "its-consensus-common" version = "0.9.0" dependencies = [ + "fork-tree", "itc-parentchain-light-client", "itc-parentchain-test", "itp-block-import-queue", diff --git a/core/rpc-server/src/tests.rs b/core/rpc-server/src/tests.rs index cfb1922d0d..4c99081804 100644 --- a/core/rpc-server/src/tests.rs +++ b/core/rpc-server/src/tests.rs @@ -19,7 +19,7 @@ use super::*; use crate::mock::MockSidechainBlockFetcher; use itp_rpc::RpcResponse; use its_rpc_handler::constants::RPC_METHOD_NAME_IMPORT_BLOCKS; -use its_test::sidechain_block_builder::SidechainBlockBuilder; +use its_test::sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}; use jsonrpsee::{ types::{to_json_value, traits::Client}, ws_client::WsClientBuilder, diff --git a/enclave-runtime/Cargo.lock b/enclave-runtime/Cargo.lock index e8fa72ab05..0089d52645 100644 --- a/enclave-runtime/Cargo.lock +++ b/enclave-runtime/Cargo.lock @@ -887,6 +887,14 @@ dependencies = [ "hashbrown 0.3.1", ] +[[package]] +name = "fork-tree" +version = "3.0.0" +dependencies = [ + "parity-scale-codec", + "sgx_tstd", +] + [[package]] name = "fp-evm" version = "3.0.0-dev" @@ -2252,6 +2260,7 @@ dependencies = [ name = "its-consensus-common" version = "0.9.0" dependencies = [ + "fork-tree", "itc-parentchain-light-client", "itp-block-import-queue", "itp-extrinsics-factory", diff --git a/service/src/ocall_bridge/ffi/fetch_sidechain_blocks_from_peer.rs b/service/src/ocall_bridge/ffi/fetch_sidechain_blocks_from_peer.rs index f1433e1329..c6c8b9e89e 100644 --- a/service/src/ocall_bridge/ffi/fetch_sidechain_blocks_from_peer.rs +++ b/service/src/ocall_bridge/ffi/fetch_sidechain_blocks_from_peer.rs @@ -108,7 +108,7 @@ mod tests { use crate::ocall_bridge::test::mocks::sidechain_bridge_mock::SidechainBridgeMock; use codec::{Decode, Encode}; use its_primitives::types::block::SignedBlock; - use its_test::sidechain_block_builder::SidechainBlockBuilder; + use its_test::sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}; use primitive_types::H256; #[test] diff --git a/service/src/ocall_bridge/sidechain_ocall.rs b/service/src/ocall_bridge/sidechain_ocall.rs index fdc801fbe8..fe648eb44e 100644 --- a/service/src/ocall_bridge/sidechain_ocall.rs +++ b/service/src/ocall_bridge/sidechain_ocall.rs @@ -203,7 +203,7 @@ mod tests { use its_peer_fetch::mocks::fetch_blocks_from_peer_mock::FetchBlocksFromPeerMock; use its_primitives::types::block::SignedBlock as SignedSidechainBlock; use its_storage::{interface::BlockStorage, Result as StorageResult}; - use its_test::sidechain_block_builder::SidechainBlockBuilder; + use its_test::sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}; use primitive_types::H256; use std::{collections::HashMap, vec::Vec}; diff --git a/service/src/worker.rs b/service/src/worker.rs index c67bffe849..18e67d82eb 100644 --- a/service/src/worker.rs +++ b/service/src/worker.rs @@ -188,7 +188,7 @@ mod tests { use frame_support::assert_ok; use itp_node_api::node_api_factory::NodeApiFactory; use its_primitives::types::block::SignedBlock as SignedSidechainBlock; - use its_test::sidechain_block_builder::SidechainBlockBuilder; + use its_test::sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}; use jsonrpsee::{ws_server::WsServerBuilder, RpcModule}; use log::debug; use sp_keyring::AccountKeyring; diff --git a/sidechain/block-verification/src/lib.rs b/sidechain/block-verification/src/lib.rs index 662e693233..2da0e80bb1 100644 --- a/sidechain/block-verification/src/lib.rs +++ b/sidechain/block-verification/src/lib.rs @@ -208,7 +208,7 @@ mod tests { use itp_types::{AccountId, Block as ParentchainBlock}; use its_primitives::types::{block::SignedBlock, header::SidechainHeader as Header}; use its_test::{ - sidechain_block_builder::SidechainBlockBuilder, + sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}, sidechain_block_data_builder::SidechainBlockDataBuilder, sidechain_header_builder::SidechainHeaderBuilder, }; diff --git a/sidechain/consensus/aura/src/test/block_importer_tests.rs b/sidechain/consensus/aura/src/test/block_importer_tests.rs index f5d69c7f82..5421baa9e6 100644 --- a/sidechain/consensus/aura/src/test/block_importer_tests.rs +++ b/sidechain/consensus/aura/src/test/block_importer_tests.rs @@ -37,7 +37,7 @@ use its_primitives::{ }; use its_state::StateUpdate; use its_test::{ - sidechain_block_builder::SidechainBlockBuilder, + sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}, sidechain_block_data_builder::SidechainBlockDataBuilder, sidechain_header_builder::SidechainHeaderBuilder, }; diff --git a/sidechain/consensus/aura/src/test/mocks/proposer_mock.rs b/sidechain/consensus/aura/src/test/mocks/proposer_mock.rs index af0c13d2f9..574083aaf9 100644 --- a/sidechain/consensus/aura/src/test/mocks/proposer_mock.rs +++ b/sidechain/consensus/aura/src/test/mocks/proposer_mock.rs @@ -20,7 +20,7 @@ use itp_types::{Block as ParentchainBlock, Header}; use its_consensus_common::{Proposal, Proposer}; use its_primitives::types::block::SignedBlock as SignedSidechainBlock; use its_test::{ - sidechain_block_builder::SidechainBlockBuilder, + sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}, sidechain_block_data_builder::SidechainBlockDataBuilder, }; use std::time::Duration; diff --git a/sidechain/consensus/common/Cargo.toml b/sidechain/consensus/common/Cargo.toml index 911d7e3c4d..9caf19bbfc 100644 --- a/sidechain/consensus/common/Cargo.toml +++ b/sidechain/consensus/common/Cargo.toml @@ -10,6 +10,7 @@ log = { version = "0.4", default-features = false } thiserror = { version = "1.0.26", optional = true } # local deps +fork-tree = { path = "../../fork-tree", default-features = false } itc-parentchain-light-client = { path = "../../../core/parentchain/light-client", default-features = false } itp-block-import-queue = { path = "../../../core-primitives/block-import-queue", default-features = false } itp-extrinsics-factory = { path = "../../../core-primitives/extrinsics-factory", default-features = false } @@ -60,6 +61,7 @@ std = [ "its-primitives/std", "its-block-verification/std", "its-state/std", + "fork-tree/std", # substrate "sp-runtime/std", # scs @@ -76,6 +78,7 @@ sgx = [ "itp-sgx-crypto/sgx", "itp-sgx-externalities/sgx", "its-state/sgx", + "fork-tree/sgx", # scs "its-block-verification/sgx", ] diff --git a/sidechain/consensus/common/src/is_descendent_of_builder.rs b/sidechain/consensus/common/src/is_descendent_of_builder.rs new file mode 100644 index 0000000000..a90b3acff0 --- /dev/null +++ b/sidechain/consensus/common/src/is_descendent_of_builder.rs @@ -0,0 +1,35 @@ +#[cfg(test)] +use std::marker::PhantomData; + +#[cfg(test)] +pub struct IsDescendentOfBuilder(PhantomData); +#[cfg(test)] +impl<'a, Hash: PartialEq> IsDescendentOfBuilder { + #[cfg(test)] + /// Build the `is_descendent_of` closure for the fork-tree structure + /// to utilize when adding and removing nodes from the tree. + pub fn build_is_descendent_of( + _curr_block: Option<(&Hash, &Hash)>, + ) -> impl Fn(&Hash, &Hash) -> Result + 'a { + move |_base, _head| Ok(true) + } +} + +#[cfg(test)] +pub struct LowestCommonAncestorFinder(PhantomData); +#[cfg(test)] +impl LowestCommonAncestorFinder { + #[cfg(test)] + /// Used by the `build_is_descendent_of` to find the LCA of two nodes in the fork-tree. + pub fn find_lowest_common_ancestor(_a: Hash, _b: Hash) -> Hash { + Default::default() + } +} + +#[cfg(test)] +#[test] +fn test_build_is_descendent_of_works() { + let is_descendent_of = >::build_is_descendent_of(None); + let my_result = is_descendent_of(&42u64, &42u64); + assert_eq!(my_result, Ok(true)); +} diff --git a/sidechain/consensus/common/src/lib.rs b/sidechain/consensus/common/src/lib.rs index 60ce5d17e3..4b0352fd47 100644 --- a/sidechain/consensus/common/src/lib.rs +++ b/sidechain/consensus/common/src/lib.rs @@ -36,6 +36,7 @@ mod block_import; mod block_import_confirmation_handler; mod block_import_queue_worker; mod error; +mod is_descendent_of_builder; mod peer_block_sync; #[cfg(test)] diff --git a/sidechain/consensus/common/src/peer_block_sync.rs b/sidechain/consensus/common/src/peer_block_sync.rs index f8fe7c86f1..181848b075 100644 --- a/sidechain/consensus/common/src/peer_block_sync.rs +++ b/sidechain/consensus/common/src/peer_block_sync.rs @@ -227,7 +227,7 @@ mod tests { use itp_test::mock::sidechain_ocall_api_mock::SidechainOCallApiMock; use itp_types::Block as ParentchainBlock; use its_primitives::types::block::SignedBlock as SignedSidechainBlock; - use its_test::sidechain_block_builder::SidechainBlockBuilder; + use its_test::sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}; type TestBlockImport = BlockImportMock; type TestOCallApi = SidechainOCallApiMock; diff --git a/sidechain/consensus/common/src/test/mocks/block_import_queue_worker_mock.rs b/sidechain/consensus/common/src/test/mocks/block_import_queue_worker_mock.rs new file mode 100644 index 0000000000..455dbaaa73 --- /dev/null +++ b/sidechain/consensus/common/src/test/mocks/block_import_queue_worker_mock.rs @@ -0,0 +1,130 @@ +use crate::{ + test::mocks::verifier_mock::VerifierMock, + BlockImport, + Error, + Result, + BlockImportQueueWorker, + SyncBlockFromPeer, + IsDescendentOfBuilder, +}; +use its_test::{ + sidechain_block_builder::SidechainBlockBuilderTrait, + sidechain_block_builder::SidechainBlockBuilder, + sidechain_block_data_builder::SidechainBlockDataBuilder as SidechainBlockData, + sidechain_header_builder::SidechainHeaderBuilder as SidechainHeader, +}; +use core::marker::PhantomData; +use itp_sgx_crypto::aes::Aes; +use itp_sgx_externalities::SgxExternalities; +use itp_test::mock::onchain_mock::OnchainMock; +use itp_types::{H256}; +use its_primitives::traits::{ShardIdentifierFor, SignedBlock as SignedSidechainBlockTrait}; +use sp_core::Pair; +use itp_block_import_queue::PopFromBlockQueue; +use its_primitives::{ + traits::{Block as BlockT, Header as HeaderT}, + types::{block_data::BlockData, header::SidechainHeader as Header, Block, SignedBlock} +}; +use sp_runtime::traits::Block as ParentchainBlockTrait; +use std::{collections::VecDeque, sync::RwLock}; + +#[derive(Default)] +pub struct BlockQueueBuilder { + queue: VecDeque, + _phantom_data: PhantomData, +} + +impl BlockQueueBuilder +where + Builder: SidechainBlockBuilderTrait + Default, + B: BlockT + From +{ + + fn new() -> Self { + Self { + queue: VecDeque::new(), + _phantom_data: PhantomData::default(), + } + } + + /// Allows definining a mock queue based and assumes that a genesis block + /// will need to be appended to the queue as the first item. + /// Returns: BuiltQueue + fn build_queue(&mut self, f: impl Fn(VecDeque) -> VecDeque) -> VecDeque { + self.add_genesis_block_to_queue(); + f(self.queue.clone()) + } + + fn add_genesis_block_to_queue(&mut self) { + let genesis_header = Header { + block_number: 0, + parent_hash: H256::from_slice(&[0; 32]), + ..Default::default() + }; + let block: B = Builder::default().with_header(genesis_header).build().into(); + self.queue.push_back(block); + } +} + +pub trait BlockQueueHeaderBuild { + type QueueHeader; + /// Helper trait to build a Header for a BlockQueue. + fn build_queue_header(block_number: BlockNumber, parent_hash: Hash) -> Self::QueueHeader; +} + +pub struct BlockQueueHeaderBuilder(PhantomData<(BlockNumber, Hash)>); + +impl BlockQueueHeaderBuild for BlockQueueHeaderBuilder +where + BlockNumber: Into, + Hash: Into, +{ + type QueueHeader = Header; + fn build_queue_header(block_number: BlockNumber, parent_hash: Hash) -> Self::QueueHeader { + Header { + block_number: block_number.into(), + parent_hash: parent_hash.into(), + ..Default::default() + } + } +} + +mod tests { + use super::*; + + #[test] + fn process_sequential_queue_no_forks() { + + let queue = >::new().build_queue(|mut queue| { + for i in 1..5 { + let parent_header = queue.back().unwrap().header(); + let header = >::build_queue_header(i, parent_header.hash()); + queue.push_back(SidechainBlockBuilder::default().with_header(header).build()); + } + queue + }); + + // TODO: Add blocks to the fork-tree and assert that everything is correct + // + // H1 - H2 - H3 - H4 - H5 + // + todo!(); + println!("Process Sequential Queue With No Forks"); + } + + #[test] + fn process_sequential_queue_with_forks() { + // TODO: Make sure this works correctly + // + // - H2.. + // / + // H1.. - H4.. + // \ / + // - H3.. + // \ + // - H5.. + // + todo!(); + println!("Process Sequential Queue with Forks") + } +} diff --git a/sidechain/peer-fetch/src/block_fetch_client.rs b/sidechain/peer-fetch/src/block_fetch_client.rs index 4077f95908..320d916d7a 100644 --- a/sidechain/peer-fetch/src/block_fetch_client.rs +++ b/sidechain/peer-fetch/src/block_fetch_client.rs @@ -97,7 +97,7 @@ mod tests { }; use its_primitives::types::block::SignedBlock; use its_storage::fetch_blocks_mock::FetchBlocksMock; - use its_test::sidechain_block_builder::SidechainBlockBuilder; + use its_test::sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}; use jsonrpsee::ws_server::WsServerBuilder; use std::{net::SocketAddr, sync::Arc}; diff --git a/sidechain/storage/src/test_utils.rs b/sidechain/storage/src/test_utils.rs index 2b02c55dd5..3eec0e2911 100644 --- a/sidechain/storage/src/test_utils.rs +++ b/sidechain/storage/src/test_utils.rs @@ -20,7 +20,7 @@ use itp_time_utils::now_as_millis; use itp_types::ShardIdentifier; use its_primitives::types::{BlockHash, SignedBlock as SignedSidechainBlock}; use its_test::{ - sidechain_block_builder::SidechainBlockBuilder, + sidechain_block_builder::{SidechainBlockBuilder, SidechainBlockBuilderTrait}, sidechain_block_data_builder::SidechainBlockDataBuilder, sidechain_header_builder::SidechainHeaderBuilder, }; diff --git a/sidechain/test/src/sidechain_block_builder.rs b/sidechain/test/src/sidechain_block_builder.rs index 5db5ab62eb..1261cf51bc 100644 --- a/sidechain/test/src/sidechain_block_builder.rs +++ b/sidechain/test/src/sidechain_block_builder.rs @@ -23,7 +23,7 @@ use crate::{ sidechain_header_builder::SidechainHeaderBuilder, }; use its_primitives::{ - traits::SignBlock, + traits::{Block as BlockT, SignBlock}, types::{block_data::BlockData, header::SidechainHeader as Header, Block, SignedBlock}, }; use sp_core::{ed25519, Pair}; @@ -31,6 +31,7 @@ use sp_core::{ed25519, Pair}; type Seed = [u8; 32]; const ENCLAVE_SEED: Seed = *b"12345678901234567890123456789012"; +#[derive(Clone)] pub struct SidechainBlockBuilder { signer: ed25519::Pair, header: Header, @@ -47,8 +48,19 @@ impl Default for SidechainBlockBuilder { } } -impl SidechainBlockBuilder { - pub fn random() -> Self { +pub trait SidechainBlockBuilderTrait { + type Block: BlockT; + fn random() -> Self; + fn with_header(self, header: Header) -> Self; + fn with_block_data(self, block_data: BlockData) -> Self; + fn with_signer(self, signer: ed25519::Pair) -> Self; + fn build(&self) -> Self::Block; + fn build_signed(&self) -> SignedBlock; +} + +impl SidechainBlockBuilderTrait for SidechainBlockBuilder { + type Block = Block; + fn random() -> Self { SidechainBlockBuilder { signer: Pair::from_seed(&ENCLAVE_SEED), header: SidechainHeaderBuilder::random().build(), @@ -56,26 +68,29 @@ impl SidechainBlockBuilder { } } - pub fn with_header(mut self, header: Header) -> Self { - self.header = header; - self + fn with_header(self, header: Header) -> Self { + let mut self_mut = self; + self_mut.header = header; + self_mut } - pub fn with_block_data(mut self, block_data: BlockData) -> Self { - self.block_data = block_data; - self + fn with_block_data(self, block_data: BlockData) -> Self { + let mut self_mut = self; + self_mut.block_data = block_data; + self_mut } - pub fn with_signer(mut self, signer: ed25519::Pair) -> Self { - self.signer = signer; - self + fn with_signer(self, signer: ed25519::Pair) -> Self { + let mut self_mut = self; + self_mut.signer = signer; + self_mut } - pub fn build(self) -> Block { - Block { header: self.header, block_data: self.block_data } + fn build(&self) -> Self::Block { + Block { header: self.header, block_data: self.block_data.clone() } } - pub fn build_signed(self) -> SignedBlock { + fn build_signed(&self) -> SignedBlock { let signer = self.signer; self.build().sign_block(&signer) }