feat: initialize Kurdistan SDK - independent fork of Polkadot SDK
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
[package]
|
||||
name = "substrate-test-runtime-client"
|
||||
version = "2.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "Apache-2.0"
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
publish = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
futures = { workspace = true }
|
||||
sc-block-builder = { workspace = true, default-features = true }
|
||||
sc-client-api = { workspace = true, default-features = true }
|
||||
sc-consensus = { workspace = true, default-features = true }
|
||||
sp-api = { workspace = true, default-features = true }
|
||||
sp-blockchain = { workspace = true, default-features = true }
|
||||
sp-consensus = { workspace = true, default-features = true }
|
||||
sp-core = { workspace = true, default-features = true }
|
||||
sp-runtime = { workspace = true, default-features = true }
|
||||
substrate-test-client = { workspace = true }
|
||||
substrate-test-runtime = { workspace = true }
|
||||
|
||||
[features]
|
||||
bls-experimental = ["substrate-test-runtime/bls-experimental"]
|
||||
runtime-benchmarks = [
|
||||
"sc-block-builder/runtime-benchmarks",
|
||||
"sc-client-api/runtime-benchmarks",
|
||||
"sc-consensus/runtime-benchmarks",
|
||||
"sp-api/runtime-benchmarks",
|
||||
"sp-blockchain/runtime-benchmarks",
|
||||
"sp-consensus/runtime-benchmarks",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
"substrate-test-client/runtime-benchmarks",
|
||||
"substrate-test-runtime/runtime-benchmarks",
|
||||
]
|
||||
@@ -0,0 +1,74 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Block Builder extensions for tests.
|
||||
|
||||
use sc_block_builder::BlockBuilderApi;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use substrate_test_runtime::*;
|
||||
|
||||
/// Extension trait for test block builder.
|
||||
pub trait BlockBuilderExt {
|
||||
/// Add transfer extrinsic to the block.
|
||||
fn push_transfer(
|
||||
&mut self,
|
||||
transfer: substrate_test_runtime::Transfer,
|
||||
) -> Result<(), sp_blockchain::Error>;
|
||||
|
||||
/// Add unsigned storage change extrinsic to the block.
|
||||
fn push_storage_change(
|
||||
&mut self,
|
||||
key: Vec<u8>,
|
||||
value: Option<Vec<u8>>,
|
||||
) -> Result<(), sp_blockchain::Error>;
|
||||
|
||||
/// Adds an extrinsic which pushes DigestItem to header's log
|
||||
fn push_deposit_log_digest_item(
|
||||
&mut self,
|
||||
log: sp_runtime::generic::DigestItem,
|
||||
) -> Result<(), sp_blockchain::Error>;
|
||||
}
|
||||
|
||||
impl<'a, A> BlockBuilderExt for sc_block_builder::BlockBuilder<'a, substrate_test_runtime::Block, A>
|
||||
where
|
||||
A: ProvideRuntimeApi<substrate_test_runtime::Block>
|
||||
+ sp_api::CallApiAt<substrate_test_runtime::Block>
|
||||
+ 'a,
|
||||
A::Api: BlockBuilderApi<substrate_test_runtime::Block> + ApiExt<substrate_test_runtime::Block>,
|
||||
{
|
||||
fn push_transfer(
|
||||
&mut self,
|
||||
transfer: substrate_test_runtime::Transfer,
|
||||
) -> Result<(), sp_blockchain::Error> {
|
||||
self.push(transfer.into_unchecked_extrinsic())
|
||||
}
|
||||
|
||||
fn push_storage_change(
|
||||
&mut self,
|
||||
key: Vec<u8>,
|
||||
value: Option<Vec<u8>>,
|
||||
) -> Result<(), sp_blockchain::Error> {
|
||||
self.push(ExtrinsicBuilder::new_storage_change(key, value).build())
|
||||
}
|
||||
|
||||
fn push_deposit_log_digest_item(
|
||||
&mut self,
|
||||
log: sp_runtime::generic::DigestItem,
|
||||
) -> Result<(), sp_blockchain::Error> {
|
||||
self.push(ExtrinsicBuilder::new_deposit_log_digest_item(log).build())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Client testing utilities.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub mod trait_tests;
|
||||
|
||||
mod block_builder_ext;
|
||||
|
||||
pub use sc_consensus::LongestChain;
|
||||
use std::sync::Arc;
|
||||
pub use substrate_test_client::*;
|
||||
pub use substrate_test_runtime as runtime;
|
||||
|
||||
pub use self::block_builder_ext::BlockBuilderExt;
|
||||
|
||||
use sp_core::storage::ChildInfo;
|
||||
use substrate_test_runtime::genesismap::GenesisStorageBuilder;
|
||||
|
||||
/// A prelude to import in tests.
|
||||
pub mod prelude {
|
||||
// Trait extensions
|
||||
pub use super::{
|
||||
BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt,
|
||||
TestClientBuilderExt,
|
||||
};
|
||||
// Client structs
|
||||
pub use super::{
|
||||
Backend, ExecutorDispatch, TestClient, TestClientBuilder, WasmExecutionMethod,
|
||||
};
|
||||
// Keyring
|
||||
pub use super::Sr25519Keyring;
|
||||
pub use futures::executor::block_on;
|
||||
pub use sc_block_builder::BlockBuilderBuilder;
|
||||
pub use sp_blockchain::HeaderBackend;
|
||||
}
|
||||
|
||||
/// Test client database backend.
|
||||
pub type Backend = substrate_test_client::Backend<substrate_test_runtime::Block>;
|
||||
|
||||
/// Test client executor.
|
||||
pub type ExecutorDispatch =
|
||||
client::LocalCallExecutor<substrate_test_runtime::Block, Backend, WasmExecutor>;
|
||||
|
||||
/// Parameters of test-client builder with test-runtime.
|
||||
#[derive(Default)]
|
||||
pub struct GenesisParameters {
|
||||
heap_pages_override: Option<u64>,
|
||||
extra_storage: Storage,
|
||||
wasm_code: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl GenesisParameters {
|
||||
/// Set the wasm code that should be used at genesis.
|
||||
pub fn set_wasm_code(&mut self, code: Vec<u8>) {
|
||||
self.wasm_code = Some(code);
|
||||
}
|
||||
|
||||
/// Access extra genesis storage.
|
||||
pub fn extra_storage(&mut self) -> &mut Storage {
|
||||
&mut self.extra_storage
|
||||
}
|
||||
}
|
||||
|
||||
impl GenesisInit for GenesisParameters {
|
||||
fn genesis_storage(&self) -> Storage {
|
||||
GenesisStorageBuilder::default()
|
||||
.with_heap_pages(self.heap_pages_override)
|
||||
.with_wasm_code(&self.wasm_code)
|
||||
.with_extra_storage(self.extra_storage.clone())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
/// A `TestClient` with `test-runtime` builder.
|
||||
pub type TestClientBuilder<E, B> = substrate_test_client::TestClientBuilder<
|
||||
substrate_test_runtime::Block,
|
||||
E,
|
||||
B,
|
||||
GenesisParameters,
|
||||
>;
|
||||
|
||||
/// Test client type with `WasmExecutor` and generic Backend.
|
||||
pub type Client<B> = client::Client<
|
||||
B,
|
||||
client::LocalCallExecutor<substrate_test_runtime::Block, B, WasmExecutor>,
|
||||
substrate_test_runtime::Block,
|
||||
substrate_test_runtime::RuntimeApi,
|
||||
>;
|
||||
|
||||
/// A test client with default backend.
|
||||
pub type TestClient = Client<Backend>;
|
||||
|
||||
/// A `TestClientBuilder` with default backend and executor.
|
||||
pub trait DefaultTestClientBuilderExt: Sized {
|
||||
/// Create new `TestClientBuilder`
|
||||
fn new() -> Self;
|
||||
}
|
||||
|
||||
impl DefaultTestClientBuilderExt for TestClientBuilder<ExecutorDispatch, Backend> {
|
||||
fn new() -> Self {
|
||||
Self::with_default_backend()
|
||||
}
|
||||
}
|
||||
|
||||
/// A `test-runtime` extensions to `TestClientBuilder`.
|
||||
pub trait TestClientBuilderExt<B>: Sized {
|
||||
/// Returns a mutable reference to the genesis parameters.
|
||||
fn genesis_init_mut(&mut self) -> &mut GenesisParameters;
|
||||
|
||||
/// Override the default value for Wasm heap pages.
|
||||
fn set_heap_pages(mut self, heap_pages: u64) -> Self {
|
||||
self.genesis_init_mut().heap_pages_override = Some(heap_pages);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an extra value into the genesis storage.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the key is empty.
|
||||
fn add_extra_child_storage<K: Into<Vec<u8>>, V: Into<Vec<u8>>>(
|
||||
mut self,
|
||||
child_info: &ChildInfo,
|
||||
key: K,
|
||||
value: V,
|
||||
) -> Self {
|
||||
let storage_key = child_info.storage_key().to_vec();
|
||||
let key = key.into();
|
||||
assert!(!storage_key.is_empty());
|
||||
assert!(!key.is_empty());
|
||||
self.genesis_init_mut()
|
||||
.extra_storage
|
||||
.children_default
|
||||
.entry(storage_key)
|
||||
.or_insert_with(|| StorageChild {
|
||||
data: Default::default(),
|
||||
child_info: child_info.clone(),
|
||||
})
|
||||
.data
|
||||
.insert(key, value.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an extra child value into the genesis storage.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the key is empty.
|
||||
fn add_extra_storage<K: Into<Vec<u8>>, V: Into<Vec<u8>>>(mut self, key: K, value: V) -> Self {
|
||||
let key = key.into();
|
||||
assert!(!key.is_empty());
|
||||
self.genesis_init_mut().extra_storage.top.insert(key, value.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the test client.
|
||||
fn build(self) -> Client<B> {
|
||||
self.build_with_longest_chain().0
|
||||
}
|
||||
|
||||
/// Build the test client and longest chain selector.
|
||||
fn build_with_longest_chain(
|
||||
self,
|
||||
) -> (Client<B>, sc_consensus::LongestChain<B, substrate_test_runtime::Block>);
|
||||
|
||||
/// Build the test client and the backend.
|
||||
fn build_with_backend(self) -> (Client<B>, Arc<B>);
|
||||
}
|
||||
|
||||
impl<B> TestClientBuilderExt<B>
|
||||
for TestClientBuilder<client::LocalCallExecutor<substrate_test_runtime::Block, B, WasmExecutor>, B>
|
||||
where
|
||||
B: sc_client_api::backend::Backend<substrate_test_runtime::Block> + 'static,
|
||||
{
|
||||
fn genesis_init_mut(&mut self) -> &mut GenesisParameters {
|
||||
Self::genesis_init_mut(self)
|
||||
}
|
||||
|
||||
fn build_with_longest_chain(
|
||||
self,
|
||||
) -> (Client<B>, sc_consensus::LongestChain<B, substrate_test_runtime::Block>) {
|
||||
self.build_with_native_executor(None)
|
||||
}
|
||||
|
||||
fn build_with_backend(self) -> (Client<B>, Arc<B>) {
|
||||
let backend = self.backend();
|
||||
(self.build_with_native_executor(None).0, backend)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new client instance used for tests.
|
||||
pub fn new() -> Client<Backend> {
|
||||
TestClientBuilder::new().build()
|
||||
}
|
||||
|
||||
/// Create a new native executor.
|
||||
#[deprecated(note = "Switch to `WasmExecutor:default()`.")]
|
||||
pub fn new_native_or_wasm_executor() -> WasmExecutor {
|
||||
WasmExecutor::default()
|
||||
}
|
||||
@@ -0,0 +1,546 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! tests that should hold for all implementations of certain traits.
|
||||
//! to test implementations without duplication.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
BlockBuilderExt, ClientBlockImportExt, Sr25519Keyring, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
use futures::executor::block_on;
|
||||
use sc_block_builder::BlockBuilderBuilder;
|
||||
use sc_client_api::{
|
||||
backend,
|
||||
blockchain::{Backend as BlockChainBackendT, HeaderBackend},
|
||||
};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use substrate_test_runtime::Transfer;
|
||||
|
||||
/// helper to test the `leaves` implementation for various backends
|
||||
pub fn test_leaves_for_backend<B: 'static>(backend: Arc<B>)
|
||||
where
|
||||
B: backend::Backend<substrate_test_runtime::Block>,
|
||||
{
|
||||
// block tree:
|
||||
// G -> A1 -> A2 -> A3 -> A4 -> A5
|
||||
// A1 -> B2 -> B3 -> B4
|
||||
// B2 -> C3
|
||||
// A1 -> D2
|
||||
|
||||
let client = TestClientBuilder::with_backend(backend.clone()).build();
|
||||
let blockchain = backend.blockchain();
|
||||
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![genesis_hash]);
|
||||
|
||||
// G -> A1
|
||||
let a1 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(genesis_hash)
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a1.hash()]);
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a2.hash()]);
|
||||
|
||||
// A2 -> A3
|
||||
let a3 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap();
|
||||
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a3.hash()]);
|
||||
|
||||
// A3 -> A4
|
||||
let a4 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a3.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a4.hash()]);
|
||||
|
||||
// A4 -> A5
|
||||
let a5 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a4.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
|
||||
block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash()]);
|
||||
|
||||
// A1 -> B2
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let b2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b2.hash()]);
|
||||
|
||||
// B2 -> B3
|
||||
let b3 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
|
||||
block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b3.hash()]);
|
||||
|
||||
// B3 -> B4
|
||||
let b4 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b3.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash()]);
|
||||
|
||||
// // B2 -> C3
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
})
|
||||
.unwrap();
|
||||
let c3 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash(), c3.hash()]);
|
||||
|
||||
// A1 -> D2
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let d2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, d2.clone())).unwrap();
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash(), c3.hash(), d2.hash()]);
|
||||
}
|
||||
|
||||
/// helper to test the `children` implementation for various backends
|
||||
pub fn test_children_for_backend<B: 'static>(backend: Arc<B>)
|
||||
where
|
||||
B: backend::LocalBackend<substrate_test_runtime::Block>,
|
||||
{
|
||||
// block tree:
|
||||
// G -> A1 -> A2 -> A3 -> A4 -> A5
|
||||
// A1 -> B2 -> B3 -> B4
|
||||
// B2 -> C3
|
||||
// A1 -> D2
|
||||
|
||||
let client = TestClientBuilder::with_backend(backend.clone()).build();
|
||||
let blockchain = backend.blockchain();
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
|
||||
// G -> A1
|
||||
let a1 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(genesis_hash)
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
// A2 -> A3
|
||||
let a3 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap();
|
||||
|
||||
// A3 -> A4
|
||||
let a4 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a3.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap();
|
||||
|
||||
// A4 -> A5
|
||||
let a5 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a4.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap();
|
||||
|
||||
// A1 -> B2
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let b2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap();
|
||||
|
||||
// B2 -> B3
|
||||
let b3 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap();
|
||||
|
||||
// B3 -> B4
|
||||
let b4 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b3.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b4)).unwrap();
|
||||
|
||||
// // B2 -> C3
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
})
|
||||
.unwrap();
|
||||
let c3 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, c3.clone())).unwrap();
|
||||
|
||||
// A1 -> D2
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let d2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, d2.clone())).unwrap();
|
||||
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
|
||||
let children1 = blockchain.children(a4.hash()).unwrap();
|
||||
assert_eq!(vec![a5.hash()], children1);
|
||||
|
||||
let children2 = blockchain.children(a1.hash()).unwrap();
|
||||
assert_eq!(vec![a2.hash(), b2.hash(), d2.hash()], children2);
|
||||
|
||||
let children3 = blockchain.children(genesis_hash).unwrap();
|
||||
assert_eq!(vec![a1.hash()], children3);
|
||||
|
||||
let children4 = blockchain.children(b2.hash()).unwrap();
|
||||
assert_eq!(vec![b3.hash(), c3.hash()], children4);
|
||||
}
|
||||
|
||||
pub fn test_blockchain_query_by_number_gets_canonical<B: 'static>(backend: Arc<B>)
|
||||
where
|
||||
B: backend::LocalBackend<substrate_test_runtime::Block>,
|
||||
{
|
||||
// block tree:
|
||||
// G -> A1 -> A2 -> A3 -> A4 -> A5
|
||||
// A1 -> B2 -> B3 -> B4
|
||||
// B2 -> C3
|
||||
// A1 -> D2
|
||||
let client = TestClientBuilder::with_backend(backend.clone()).build();
|
||||
let blockchain = backend.blockchain();
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
|
||||
// G -> A1
|
||||
let a1 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(genesis_hash)
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
// A2 -> A3
|
||||
let a3 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap();
|
||||
|
||||
// A3 -> A4
|
||||
let a4 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a3.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap();
|
||||
|
||||
// A4 -> A5
|
||||
let a5 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a4.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap();
|
||||
|
||||
// A1 -> B2
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let b2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, b2.clone())).unwrap();
|
||||
|
||||
// B2 -> B3
|
||||
let b3 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap();
|
||||
|
||||
// B3 -> B4
|
||||
let b4 = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b3.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b4)).unwrap();
|
||||
|
||||
// // B2 -> C3
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(b2.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
})
|
||||
.unwrap();
|
||||
let c3 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, c3)).unwrap();
|
||||
|
||||
// A1 -> D2
|
||||
let mut builder = BlockBuilderBuilder::new(&client)
|
||||
.on_parent_block(a1.hash())
|
||||
.fetch_parent_block_number(&client)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: Sr25519Keyring::Alice.into(),
|
||||
to: Sr25519Keyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let d2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, d2)).unwrap();
|
||||
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
|
||||
assert_eq!(blockchain.hash(0).unwrap().unwrap(), genesis_hash);
|
||||
assert_eq!(blockchain.hash(1).unwrap().unwrap(), a1.hash());
|
||||
assert_eq!(blockchain.hash(2).unwrap().unwrap(), a2.hash());
|
||||
assert_eq!(blockchain.hash(3).unwrap().unwrap(), a3.hash());
|
||||
assert_eq!(blockchain.hash(4).unwrap().unwrap(), a4.hash());
|
||||
assert_eq!(blockchain.hash(5).unwrap().unwrap(), a5.hash());
|
||||
}
|
||||
Reference in New Issue
Block a user