feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit e4778b4576
6838 changed files with 1847450 additions and 0 deletions
@@ -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());
}