mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Run cargo fmt on the whole code base (#9394)
* Run cargo fmt on the whole code base * Second run * Add CI check * Fix compilation * More unnecessary braces * Handle weights * Use --all * Use correct attributes... * Fix UI tests * AHHHHHHHHH * 🤦 * Docs * Fix compilation * 🤷 * Please stop * 🤦 x 2 * More * make rustfmt.toml consistent with polkadot Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
@@ -17,16 +17,19 @@
|
||||
|
||||
//! Block Builder extensions for tests.
|
||||
|
||||
use sc_client_api::backend;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
use sp_core::ChangesTrieConfiguration;
|
||||
use sc_client_api::backend;
|
||||
|
||||
use sc_block_builder::BlockBuilderApi;
|
||||
|
||||
/// 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>;
|
||||
fn push_transfer(
|
||||
&mut self,
|
||||
transfer: substrate_test_runtime::Transfer,
|
||||
) -> Result<(), sp_blockchain::Error>;
|
||||
/// Add storage change extrinsic to the block.
|
||||
fn push_storage_change(
|
||||
&mut self,
|
||||
@@ -40,16 +43,21 @@ pub trait BlockBuilderExt {
|
||||
) -> Result<(), sp_blockchain::Error>;
|
||||
}
|
||||
|
||||
impl<'a, A, B> BlockBuilderExt for sc_block_builder::BlockBuilder<'a, substrate_test_runtime::Block, A, B> where
|
||||
impl<'a, A, B> BlockBuilderExt
|
||||
for sc_block_builder::BlockBuilder<'a, substrate_test_runtime::Block, A, B>
|
||||
where
|
||||
A: ProvideRuntimeApi<substrate_test_runtime::Block> + 'a,
|
||||
A::Api: BlockBuilderApi<substrate_test_runtime::Block> +
|
||||
ApiExt<
|
||||
A::Api: BlockBuilderApi<substrate_test_runtime::Block>
|
||||
+ ApiExt<
|
||||
substrate_test_runtime::Block,
|
||||
StateBackend = backend::StateBackendFor<B, substrate_test_runtime::Block>
|
||||
StateBackend = backend::StateBackendFor<B, substrate_test_runtime::Block>,
|
||||
>,
|
||||
B: backend::Backend<substrate_test_runtime::Block>,
|
||||
{
|
||||
fn push_transfer(&mut self, transfer: substrate_test_runtime::Transfer) -> Result<(), sp_blockchain::Error> {
|
||||
fn push_transfer(
|
||||
&mut self,
|
||||
transfer: substrate_test_runtime::Transfer,
|
||||
) -> Result<(), sp_blockchain::Error> {
|
||||
self.push(transfer.into_signed_tx())
|
||||
}
|
||||
|
||||
|
||||
@@ -23,34 +23,36 @@ pub mod trait_tests;
|
||||
|
||||
mod block_builder_ext;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
pub use sc_consensus::LongestChain;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
pub use substrate_test_client::*;
|
||||
pub use substrate_test_runtime as runtime;
|
||||
pub use sc_consensus::LongestChain;
|
||||
|
||||
pub use self::block_builder_ext::BlockBuilderExt;
|
||||
|
||||
use sp_core::{sr25519, ChangesTrieConfiguration};
|
||||
use sp_core::storage::{ChildInfo, Storage, StorageChild};
|
||||
use substrate_test_runtime::genesismap::{GenesisConfig, additional_storage_with_genesis};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Hash as HashT, NumberFor, HashFor};
|
||||
use sc_client_api::light::{
|
||||
RemoteCallRequest, RemoteChangesRequest, RemoteBodyRequest,
|
||||
Fetcher, RemoteHeaderRequest, RemoteReadRequest, RemoteReadChildRequest,
|
||||
Fetcher, RemoteBodyRequest, RemoteCallRequest, RemoteChangesRequest, RemoteHeaderRequest,
|
||||
RemoteReadChildRequest, RemoteReadRequest,
|
||||
};
|
||||
use sp_core::{
|
||||
sr25519,
|
||||
storage::{ChildInfo, Storage, StorageChild},
|
||||
ChangesTrieConfiguration,
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, Hash as HashT, HashFor, Header as HeaderT, NumberFor};
|
||||
use substrate_test_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig};
|
||||
|
||||
/// A prelude to import in tests.
|
||||
pub mod prelude {
|
||||
// Trait extensions
|
||||
pub use super::{
|
||||
BlockBuilderExt, DefaultTestClientBuilderExt, TestClientBuilderExt, ClientExt,
|
||||
ClientBlockImportExt,
|
||||
BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt,
|
||||
TestClientBuilderExt,
|
||||
};
|
||||
// Client structs
|
||||
pub use super::{
|
||||
TestClient, TestClientBuilder, Backend, LightBackend,
|
||||
Executor, LightExecutor, LocalExecutor, NativeExecutor, WasmExecutionMethod,
|
||||
Backend, Executor, LightBackend, LightExecutor, LocalExecutor, NativeExecutor, TestClient,
|
||||
TestClientBuilder, WasmExecutionMethod,
|
||||
};
|
||||
// Keyring
|
||||
pub use super::{AccountKeyring, Sr25519Keyring};
|
||||
@@ -82,10 +84,10 @@ pub type LightExecutor = sc_light::GenesisCallExecutor<
|
||||
substrate_test_runtime::Block,
|
||||
sc_light::Backend<
|
||||
sc_client_db::light::LightStorage<substrate_test_runtime::Block>,
|
||||
HashFor<substrate_test_runtime::Block>
|
||||
HashFor<substrate_test_runtime::Block>,
|
||||
>,
|
||||
NativeExecutor<LocalExecutor>
|
||||
>
|
||||
NativeExecutor<LocalExecutor>,
|
||||
>,
|
||||
>;
|
||||
|
||||
/// Parameters of test-client builder with test-runtime.
|
||||
@@ -130,19 +132,23 @@ impl substrate_test_client::GenesisInit for GenesisParameters {
|
||||
let mut storage = self.genesis_config().genesis_map();
|
||||
|
||||
if let Some(ref code) = self.wasm_code {
|
||||
storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone());
|
||||
storage
|
||||
.top
|
||||
.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone());
|
||||
}
|
||||
|
||||
let child_roots = storage.children_default.iter().map(|(_sk, child_content)| {
|
||||
let state_root = <<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
child_content.data.clone().into_iter().collect()
|
||||
);
|
||||
let state_root =
|
||||
<<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
child_content.data.clone().into_iter().collect(),
|
||||
);
|
||||
let prefixed_storage_key = child_content.child_info.prefixed_storage_key();
|
||||
(prefixed_storage_key.into_inner(), state_root.encode())
|
||||
});
|
||||
let state_root = <<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
storage.top.clone().into_iter().chain(child_roots).collect()
|
||||
);
|
||||
let state_root =
|
||||
<<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
storage.top.clone().into_iter().chain(child_roots).collect(),
|
||||
);
|
||||
let block: runtime::Block = client::genesis::construct_genesis_block(state_root);
|
||||
storage.top.extend(additional_storage_with_genesis(&block));
|
||||
|
||||
@@ -164,7 +170,7 @@ pub type Client<B> = client::Client<
|
||||
client::LocalCallExecutor<
|
||||
substrate_test_runtime::Block,
|
||||
B,
|
||||
sc_executor::NativeExecutor<LocalExecutor>
|
||||
sc_executor::NativeExecutor<LocalExecutor>,
|
||||
>,
|
||||
substrate_test_runtime::Block,
|
||||
substrate_test_runtime::RuntimeApi,
|
||||
@@ -217,12 +223,16 @@ pub trait TestClientBuilderExt<B>: Sized {
|
||||
let key = key.into();
|
||||
assert!(!storage_key.is_empty());
|
||||
assert!(!key.is_empty());
|
||||
self.genesis_init_mut().extra_storage.children_default
|
||||
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());
|
||||
})
|
||||
.data
|
||||
.insert(key, value.into());
|
||||
self
|
||||
}
|
||||
|
||||
@@ -244,27 +254,32 @@ pub trait TestClientBuilderExt<B>: Sized {
|
||||
}
|
||||
|
||||
/// Build the test client and longest chain selector.
|
||||
fn build_with_longest_chain(self) -> (Client<B>, sc_consensus::LongestChain<B, substrate_test_runtime::Block>);
|
||||
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,
|
||||
impl<B> TestClientBuilderExt<B>
|
||||
for TestClientBuilder<
|
||||
client::LocalCallExecutor<
|
||||
substrate_test_runtime::Block,
|
||||
B,
|
||||
sc_executor::NativeExecutor<LocalExecutor>,
|
||||
>,
|
||||
B,
|
||||
sc_executor::NativeExecutor<LocalExecutor>
|
||||
>,
|
||||
B
|
||||
> where
|
||||
> 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>) {
|
||||
fn build_with_longest_chain(
|
||||
self,
|
||||
) -> (Client<B>, sc_consensus::LongestChain<B, substrate_test_runtime::Block>) {
|
||||
self.build_with_native_executor(None)
|
||||
}
|
||||
|
||||
@@ -275,7 +290,8 @@ impl<B> TestClientBuilderExt<B> for TestClientBuilder<
|
||||
}
|
||||
|
||||
/// Type of optional fetch callback.
|
||||
type MaybeFetcherCallback<Req, Resp> = Option<Box<dyn Fn(Req) -> Result<Resp, sp_blockchain::Error> + Send + Sync>>;
|
||||
type MaybeFetcherCallback<Req, Resp> =
|
||||
Option<Box<dyn Fn(Req) -> Result<Resp, sp_blockchain::Error> + Send + Sync>>;
|
||||
|
||||
/// Type of fetcher future result.
|
||||
type FetcherFutureResult<Resp> = futures::future::Ready<Result<Resp, sp_blockchain::Error>>;
|
||||
@@ -284,7 +300,10 @@ type FetcherFutureResult<Resp> = futures::future::Ready<Result<Resp, sp_blockcha
|
||||
#[derive(Default)]
|
||||
pub struct LightFetcher {
|
||||
call: MaybeFetcherCallback<RemoteCallRequest<substrate_test_runtime::Header>, Vec<u8>>,
|
||||
body: MaybeFetcherCallback<RemoteBodyRequest<substrate_test_runtime::Header>, Vec<substrate_test_runtime::Extrinsic>>,
|
||||
body: MaybeFetcherCallback<
|
||||
RemoteBodyRequest<substrate_test_runtime::Header>,
|
||||
Vec<substrate_test_runtime::Extrinsic>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl LightFetcher {
|
||||
@@ -293,21 +312,18 @@ impl LightFetcher {
|
||||
self,
|
||||
call: MaybeFetcherCallback<RemoteCallRequest<substrate_test_runtime::Header>, Vec<u8>>,
|
||||
) -> Self {
|
||||
LightFetcher {
|
||||
call,
|
||||
body: self.body,
|
||||
}
|
||||
LightFetcher { call, body: self.body }
|
||||
}
|
||||
|
||||
/// Sets remote body callback.
|
||||
pub fn with_remote_body(
|
||||
self,
|
||||
body: MaybeFetcherCallback<RemoteBodyRequest<substrate_test_runtime::Header>, Vec<substrate_test_runtime::Extrinsic>>,
|
||||
body: MaybeFetcherCallback<
|
||||
RemoteBodyRequest<substrate_test_runtime::Header>,
|
||||
Vec<substrate_test_runtime::Extrinsic>,
|
||||
>,
|
||||
) -> Self {
|
||||
LightFetcher {
|
||||
call: self.call,
|
||||
body,
|
||||
}
|
||||
LightFetcher { call: self.call, body }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,14 +331,21 @@ impl Fetcher<substrate_test_runtime::Block> for LightFetcher {
|
||||
type RemoteHeaderResult = FetcherFutureResult<substrate_test_runtime::Header>;
|
||||
type RemoteReadResult = FetcherFutureResult<HashMap<Vec<u8>, Option<Vec<u8>>>>;
|
||||
type RemoteCallResult = FetcherFutureResult<Vec<u8>>;
|
||||
type RemoteChangesResult = FetcherFutureResult<Vec<(NumberFor<substrate_test_runtime::Block>, u32)>>;
|
||||
type RemoteChangesResult =
|
||||
FetcherFutureResult<Vec<(NumberFor<substrate_test_runtime::Block>, u32)>>;
|
||||
type RemoteBodyResult = FetcherFutureResult<Vec<substrate_test_runtime::Extrinsic>>;
|
||||
|
||||
fn remote_header(&self, _: RemoteHeaderRequest<substrate_test_runtime::Header>) -> Self::RemoteHeaderResult {
|
||||
fn remote_header(
|
||||
&self,
|
||||
_: RemoteHeaderRequest<substrate_test_runtime::Header>,
|
||||
) -> Self::RemoteHeaderResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn remote_read(&self, _: RemoteReadRequest<substrate_test_runtime::Header>) -> Self::RemoteReadResult {
|
||||
fn remote_read(
|
||||
&self,
|
||||
_: RemoteReadRequest<substrate_test_runtime::Header>,
|
||||
) -> Self::RemoteReadResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -333,18 +356,27 @@ impl Fetcher<substrate_test_runtime::Block> for LightFetcher {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn remote_call(&self, req: RemoteCallRequest<substrate_test_runtime::Header>) -> Self::RemoteCallResult {
|
||||
fn remote_call(
|
||||
&self,
|
||||
req: RemoteCallRequest<substrate_test_runtime::Header>,
|
||||
) -> Self::RemoteCallResult {
|
||||
match self.call {
|
||||
Some(ref call) => futures::future::ready(call(req)),
|
||||
None => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn remote_changes(&self, _: RemoteChangesRequest<substrate_test_runtime::Header>) -> Self::RemoteChangesResult {
|
||||
fn remote_changes(
|
||||
&self,
|
||||
_: RemoteChangesRequest<substrate_test_runtime::Header>,
|
||||
) -> Self::RemoteChangesResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn remote_body(&self, req: RemoteBodyRequest<substrate_test_runtime::Header>) -> Self::RemoteBodyResult {
|
||||
fn remote_body(
|
||||
&self,
|
||||
req: RemoteBodyRequest<substrate_test_runtime::Header>,
|
||||
) -> Self::RemoteBodyResult {
|
||||
match self.body {
|
||||
Some(ref body) => futures::future::ready(body(req)),
|
||||
None => unimplemented!(),
|
||||
@@ -359,10 +391,14 @@ pub fn new() -> Client<Backend> {
|
||||
|
||||
/// Creates new light client instance used for tests.
|
||||
pub fn new_light() -> (
|
||||
client::Client<LightBackend, LightExecutor, substrate_test_runtime::Block, substrate_test_runtime::RuntimeApi>,
|
||||
client::Client<
|
||||
LightBackend,
|
||||
LightExecutor,
|
||||
substrate_test_runtime::Block,
|
||||
substrate_test_runtime::RuntimeApi,
|
||||
>,
|
||||
Arc<LightBackend>,
|
||||
) {
|
||||
|
||||
let storage = sc_client_db::light::LightStorage::new_test();
|
||||
let blockchain = Arc::new(sc_light::Blockchain::new(storage));
|
||||
let backend = Arc::new(LightBackend::new(blockchain));
|
||||
@@ -372,11 +408,9 @@ pub fn new_light() -> (
|
||||
executor,
|
||||
Box::new(sp_core::testing::TaskExecutor::new()),
|
||||
Default::default(),
|
||||
).expect("Creates LocalCallExecutor");
|
||||
let call_executor = LightExecutor::new(
|
||||
backend.clone(),
|
||||
local_call_executor,
|
||||
);
|
||||
)
|
||||
.expect("Creates LocalCallExecutor");
|
||||
let call_executor = LightExecutor::new(backend.clone(), local_call_executor);
|
||||
|
||||
(
|
||||
TestClientBuilder::with_backend(backend.clone())
|
||||
|
||||
@@ -23,192 +23,169 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
AccountKeyring, ClientBlockImportExt, BlockBuilderExt, TestClientBuilder, TestClientBuilderExt,
|
||||
AccountKeyring, BlockBuilderExt, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
use sc_client_api::backend;
|
||||
use sc_client_api::blockchain::{Backend as BlockChainBackendT, HeaderBackend};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use substrate_test_runtime::{self, Transfer};
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use futures::executor::block_on;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sc_client_api::{
|
||||
backend,
|
||||
blockchain::{Backend as BlockChainBackendT, HeaderBackend},
|
||||
};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_runtime::{generic::BlockId, traits::Block as BlockT};
|
||||
use substrate_test_runtime::{self, Transfer};
|
||||
|
||||
/// helper to test the `leaves` implementation for various backends
|
||||
pub fn test_leaves_for_backend<B: 'static>(backend: Arc<B>) where
|
||||
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
|
||||
// A1 -> B2 -> B3 -> B4
|
||||
// B2 -> C3
|
||||
// A1 -> D2
|
||||
|
||||
let mut 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]);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![genesis_hash]);
|
||||
|
||||
// G -> A1
|
||||
let a1 = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
assert_eq!(
|
||||
blockchain.leaves().unwrap(),
|
||||
vec![a1.hash()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a1.hash()],);
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a2 = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
#[allow(deprecated)]
|
||||
assert_eq!(
|
||||
blockchain.leaves().unwrap(),
|
||||
vec![a2.hash()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a2.hash()],);
|
||||
|
||||
// A2 -> A3
|
||||
let a3 = client.new_block_at(
|
||||
&BlockId::Hash(a2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a3 = client
|
||||
.new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
blockchain.leaves().unwrap(),
|
||||
vec![a3.hash()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a3.hash()],);
|
||||
|
||||
// A3 -> A4
|
||||
let a4 = client.new_block_at(
|
||||
&BlockId::Hash(a3.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a4 = client
|
||||
.new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap();
|
||||
assert_eq!(
|
||||
blockchain.leaves().unwrap(),
|
||||
vec![a4.hash()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a4.hash()],);
|
||||
|
||||
// A4 -> A5
|
||||
let a5 = client.new_block_at(
|
||||
&BlockId::Hash(a4.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a5 = client
|
||||
.new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
|
||||
block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap();
|
||||
assert_eq!(
|
||||
blockchain.leaves().unwrap(),
|
||||
vec![a5.hash()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash()],);
|
||||
|
||||
// A1 -> B2
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
|
||||
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
nonce: 0,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::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()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b2.hash()],);
|
||||
|
||||
// B2 -> B3
|
||||
let b3 = client.new_block_at(
|
||||
&BlockId::Hash(b2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let b3 = client
|
||||
.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
|
||||
block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap();
|
||||
assert_eq!(
|
||||
blockchain.leaves().unwrap(),
|
||||
vec![a5.hash(), b3.hash()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b3.hash()],);
|
||||
|
||||
// B3 -> B4
|
||||
let b4 = client.new_block_at(
|
||||
&BlockId::Hash(b3.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let b4 = client
|
||||
.new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b4.clone())).unwrap();
|
||||
assert_eq!(
|
||||
blockchain.leaves().unwrap(),
|
||||
vec![a5.hash(), b4.hash()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash()],);
|
||||
|
||||
// // B2 -> C3
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(b2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::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()],
|
||||
);
|
||||
assert_eq!(blockchain.leaves().unwrap(), vec![a5.hash(), b4.hash(), c3.hash()],);
|
||||
|
||||
// A1 -> D2
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::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()],
|
||||
);
|
||||
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
|
||||
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
|
||||
// A1 -> B2 -> B3 -> B4
|
||||
// B2 -> C3
|
||||
// A1 -> D2
|
||||
|
||||
let mut client = TestClientBuilder::with_backend(backend.clone()).build();
|
||||
let blockchain = backend.blockchain();
|
||||
@@ -218,98 +195,104 @@ pub fn test_children_for_backend<B: 'static>(backend: Arc<B>) where
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a2 = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
// A2 -> A3
|
||||
let a3 = client.new_block_at(
|
||||
&BlockId::Hash(a2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a3 = client
|
||||
.new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap();
|
||||
|
||||
// A3 -> A4
|
||||
let a4 = client.new_block_at(
|
||||
&BlockId::Hash(a3.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a4 = client
|
||||
.new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap();
|
||||
|
||||
// A4 -> A5
|
||||
let a5 = client.new_block_at(
|
||||
&BlockId::Hash(a4.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a5 = client
|
||||
.new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap();
|
||||
|
||||
// A1 -> B2
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
nonce: 0,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::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 = client.new_block_at(
|
||||
&BlockId::Hash(b2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let b3 = client
|
||||
.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap();
|
||||
|
||||
// B3 -> B4
|
||||
let b4 = client.new_block_at(
|
||||
&BlockId::Hash(b3.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let b4 = client
|
||||
.new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b4)).unwrap();
|
||||
|
||||
// // B2 -> C3
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(b2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::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 = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let d2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, d2.clone())).unwrap();
|
||||
|
||||
@@ -334,9 +317,9 @@ where
|
||||
{
|
||||
// block tree:
|
||||
// G -> A1 -> A2 -> A3 -> A4 -> A5
|
||||
// A1 -> B2 -> B3 -> B4
|
||||
// B2 -> C3
|
||||
// A1 -> D2
|
||||
// A1 -> B2 -> B3 -> B4
|
||||
// B2 -> C3
|
||||
// A1 -> D2
|
||||
let mut client = TestClientBuilder::with_backend(backend.clone()).build();
|
||||
let blockchain = backend.blockchain();
|
||||
|
||||
@@ -345,98 +328,104 @@ where
|
||||
block_on(client.import(BlockOrigin::Own, a1.clone())).unwrap();
|
||||
|
||||
// A1 -> A2
|
||||
let a2 = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a2 = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a2.clone())).unwrap();
|
||||
|
||||
// A2 -> A3
|
||||
let a3 = client.new_block_at(
|
||||
&BlockId::Hash(a2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a3 = client
|
||||
.new_block_at(&BlockId::Hash(a2.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a3.clone())).unwrap();
|
||||
|
||||
// A3 -> A4
|
||||
let a4 = client.new_block_at(
|
||||
&BlockId::Hash(a3.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a4 = client
|
||||
.new_block_at(&BlockId::Hash(a3.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a4.clone())).unwrap();
|
||||
|
||||
// A4 -> A5
|
||||
let a5 = client.new_block_at(
|
||||
&BlockId::Hash(a4.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let a5 = client
|
||||
.new_block_at(&BlockId::Hash(a4.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, a5.clone())).unwrap();
|
||||
|
||||
// A1 -> B2
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise B2 has the same hash as A2 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
nonce: 0,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::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 = client.new_block_at(
|
||||
&BlockId::Hash(b2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let b3 = client
|
||||
.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b3.clone())).unwrap();
|
||||
|
||||
// B3 -> B4
|
||||
let b4 = client.new_block_at(
|
||||
&BlockId::Hash(b3.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap().build().unwrap().block;
|
||||
let b4 = client
|
||||
.new_block_at(&BlockId::Hash(b3.hash()), Default::default(), false)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block;
|
||||
block_on(client.import(BlockOrigin::Own, b4)).unwrap();
|
||||
|
||||
// // B2 -> C3
|
||||
let mut builder = client.new_block_at(
|
||||
&BlockId::Hash(b2.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(b2.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise C3 has the same hash as B3 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 1,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::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 = client.new_block_at(
|
||||
&BlockId::Hash(a1.hash()),
|
||||
Default::default(),
|
||||
false,
|
||||
).unwrap();
|
||||
let mut builder = client
|
||||
.new_block_at(&BlockId::Hash(a1.hash()), Default::default(), false)
|
||||
.unwrap();
|
||||
// this push is required as otherwise D2 has the same hash as B2 and won't get imported
|
||||
builder.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
}).unwrap();
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
let d2 = builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, d2)).unwrap();
|
||||
|
||||
|
||||
@@ -17,14 +17,17 @@
|
||||
|
||||
//! Tool for creating the genesis block.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use sp_io::hashing::{blake2_256, twox_128};
|
||||
use super::{AuthorityId, AccountId, wasm_binary_unwrap, system};
|
||||
use codec::{Encode, KeyedVec, Joiner};
|
||||
use sp_core::{ChangesTrieConfiguration, map};
|
||||
use sp_core::storage::{well_known_keys, Storage};
|
||||
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
|
||||
use super::{system, wasm_binary_unwrap, AccountId, AuthorityId};
|
||||
use codec::{Encode, Joiner, KeyedVec};
|
||||
use sc_service::client::genesis;
|
||||
use sp_core::{
|
||||
map,
|
||||
storage::{well_known_keys, Storage},
|
||||
ChangesTrieConfiguration,
|
||||
};
|
||||
use sp_io::hashing::{blake2_256, twox_128};
|
||||
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Configuration of a general Substrate test genesis block.
|
||||
pub struct GenesisConfig {
|
||||
@@ -47,7 +50,7 @@ impl GenesisConfig {
|
||||
) -> Self {
|
||||
GenesisConfig {
|
||||
changes_trie_config,
|
||||
authorities: authorities,
|
||||
authorities,
|
||||
balances: endowed_accounts.into_iter().map(|a| (a, balance)).collect(),
|
||||
heap_pages_override,
|
||||
extra_storage,
|
||||
@@ -56,16 +59,23 @@ impl GenesisConfig {
|
||||
|
||||
pub fn genesis_map(&self) -> Storage {
|
||||
let wasm_runtime = wasm_binary_unwrap().to_vec();
|
||||
let mut map: BTreeMap<Vec<u8>, Vec<u8>> = self.balances.iter()
|
||||
.map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance)))
|
||||
let mut map: BTreeMap<Vec<u8>, Vec<u8>> = self
|
||||
.balances
|
||||
.iter()
|
||||
.map(|&(ref account, balance)| {
|
||||
(account.to_keyed_vec(b"balance:"), vec![].and(&balance))
|
||||
})
|
||||
.map(|(k, v)| (blake2_256(&k[..])[..].to_vec(), v.to_vec()))
|
||||
.chain(vec![
|
||||
(well_known_keys::CODE.into(), wasm_runtime),
|
||||
(
|
||||
well_known_keys::HEAP_PAGES.into(),
|
||||
vec![].and(&(self.heap_pages_override.unwrap_or(16 as u64))),
|
||||
),
|
||||
].into_iter())
|
||||
.chain(
|
||||
vec![
|
||||
(well_known_keys::CODE.into(), wasm_runtime),
|
||||
(
|
||||
well_known_keys::HEAP_PAGES.into(),
|
||||
vec![].and(&(self.heap_pages_override.unwrap_or(16 as u64))),
|
||||
),
|
||||
]
|
||||
.into_iter(),
|
||||
)
|
||||
.collect();
|
||||
if let Some(ref changes_trie_config) = self.changes_trie_config {
|
||||
map.insert(well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), changes_trie_config.encode());
|
||||
@@ -75,28 +85,30 @@ impl GenesisConfig {
|
||||
map.extend(self.extra_storage.top.clone().into_iter());
|
||||
|
||||
// Assimilate the system genesis config.
|
||||
let mut storage = Storage { top: map, children_default: self.extra_storage.children_default.clone()};
|
||||
let mut storage =
|
||||
Storage { top: map, children_default: self.extra_storage.children_default.clone() };
|
||||
let mut config = system::GenesisConfig::default();
|
||||
config.authorities = self.authorities.clone();
|
||||
config.assimilate_storage(&mut storage).expect("Adding `system::GensisConfig` to the genesis");
|
||||
config
|
||||
.assimilate_storage(&mut storage)
|
||||
.expect("Adding `system::GensisConfig` to the genesis");
|
||||
|
||||
storage
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_genesis_block(
|
||||
storage: &mut Storage,
|
||||
) -> sp_core::hash::H256 {
|
||||
pub fn insert_genesis_block(storage: &mut Storage) -> sp_core::hash::H256 {
|
||||
let child_roots = storage.children_default.iter().map(|(sk, child_content)| {
|
||||
let state_root = <<<crate::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
child_content.data.clone().into_iter().collect(),
|
||||
);
|
||||
let state_root =
|
||||
<<<crate::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
child_content.data.clone().into_iter().collect(),
|
||||
);
|
||||
(sk.clone(), state_root.encode())
|
||||
});
|
||||
// add child roots to storage
|
||||
storage.top.extend(child_roots);
|
||||
let state_root = <<<crate::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
storage.top.clone().into_iter().collect()
|
||||
storage.top.clone().into_iter().collect(),
|
||||
);
|
||||
let block: crate::Block = genesis::construct_genesis_block(state_root);
|
||||
let genesis_hash = block.header.hash();
|
||||
|
||||
@@ -23,45 +23,43 @@
|
||||
pub mod genesismap;
|
||||
pub mod system;
|
||||
|
||||
use sp_std::{prelude::*, marker::PhantomData};
|
||||
use codec::{Encode, Decode, Input, Error};
|
||||
use codec::{Decode, Encode, Error, Input};
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
|
||||
use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic};
|
||||
use sp_core::{offchain::KeyTypeId, ChangesTrieConfiguration, OpaqueMetadata, RuntimeDebug};
|
||||
use sp_application_crypto::{ed25519, sr25519, ecdsa, RuntimeAppPublic};
|
||||
use trie_db::{TrieMut, Trie};
|
||||
use sp_trie::{PrefixedMemoryDB, StorageProof};
|
||||
use sp_trie::trie_types::{TrieDB, TrieDBMut};
|
||||
|
||||
use sp_api::{decl_runtime_apis, impl_runtime_apis};
|
||||
use sp_runtime::{
|
||||
create_runtime_str, impl_opaque_keys,
|
||||
ApplyExtrinsicResult, Perbill,
|
||||
transaction_validity::{
|
||||
TransactionValidity, ValidTransaction, TransactionValidityError, InvalidTransaction,
|
||||
TransactionSource,
|
||||
},
|
||||
traits::{
|
||||
BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT,
|
||||
GetNodeBlockType, GetRuntimeBlockType, Verify, IdentityLookup,
|
||||
},
|
||||
use sp_trie::{
|
||||
trie_types::{TrieDB, TrieDBMut},
|
||||
PrefixedMemoryDB, StorageProof,
|
||||
};
|
||||
use trie_db::{Trie, TrieMut};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use frame_support::{parameter_types, traits::KeyOwnerProofSystem, weights::RuntimeDbWeight};
|
||||
use frame_system::limits::{BlockLength, BlockWeights};
|
||||
use sp_api::{decl_runtime_apis, impl_runtime_apis};
|
||||
pub use sp_core::hash::H256;
|
||||
use sp_inherents::{CheckInherentsResult, InherentData};
|
||||
#[cfg(feature = "std")]
|
||||
use sp_runtime::traits::NumberFor;
|
||||
use sp_version::RuntimeVersion;
|
||||
pub use sp_core::hash::H256;
|
||||
use sp_runtime::{
|
||||
create_runtime_str, impl_opaque_keys,
|
||||
traits::{
|
||||
BlakeTwo256, BlindCheckable, Block as BlockT, Extrinsic as ExtrinsicT, GetNodeBlockType,
|
||||
GetRuntimeBlockType, IdentityLookup, Verify,
|
||||
},
|
||||
transaction_validity::{
|
||||
InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
|
||||
ValidTransaction,
|
||||
},
|
||||
ApplyExtrinsicResult, Perbill,
|
||||
};
|
||||
#[cfg(any(feature = "std", test))]
|
||||
use sp_version::NativeVersion;
|
||||
use frame_support::{
|
||||
parameter_types,
|
||||
traits::KeyOwnerProofSystem,
|
||||
weights::RuntimeDbWeight,
|
||||
};
|
||||
use frame_system::limits::{BlockWeights, BlockLength};
|
||||
use sp_inherents::{CheckInherentsResult, InherentData};
|
||||
use cfg_if::cfg_if;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
// Ensure Babe and Aura use the same crypto to simplify things a bit.
|
||||
pub use sp_consensus_babe::{AuthorityId, Slot, AllowedSlots};
|
||||
pub use sp_consensus_babe::{AllowedSlots, AuthorityId, Slot};
|
||||
|
||||
pub type AuraId = sp_consensus_aura::sr25519::AuthorityId;
|
||||
|
||||
@@ -77,18 +75,19 @@ pub mod wasm_binary_logging_disabled {
|
||||
/// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn wasm_binary_unwrap() -> &'static [u8] {
|
||||
WASM_BINARY.expect("Development wasm binary is not available. Testing is only \
|
||||
supported with the flag disabled.")
|
||||
WASM_BINARY.expect(
|
||||
"Development wasm binary is not available. Testing is only \
|
||||
supported with the flag disabled.",
|
||||
)
|
||||
}
|
||||
|
||||
/// Wasm binary unwrapped. If built with `SKIP_WASM_BUILD`, the function panics.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn wasm_binary_logging_disabled_unwrap() -> &'static [u8] {
|
||||
wasm_binary_logging_disabled::WASM_BINARY
|
||||
.expect(
|
||||
"Development wasm binary is not available. Testing is only supported with the flag \
|
||||
disabled."
|
||||
)
|
||||
wasm_binary_logging_disabled::WASM_BINARY.expect(
|
||||
"Development wasm binary is not available. Testing is only supported with the flag \
|
||||
disabled.",
|
||||
)
|
||||
}
|
||||
|
||||
/// Test runtime version.
|
||||
@@ -110,10 +109,7 @@ fn version() -> RuntimeVersion {
|
||||
/// Native version.
|
||||
#[cfg(any(feature = "std", test))]
|
||||
pub fn native_version() -> NativeVersion {
|
||||
NativeVersion {
|
||||
runtime_version: VERSION,
|
||||
can_author_with: Default::default(),
|
||||
}
|
||||
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
|
||||
}
|
||||
|
||||
/// Calls in transactions.
|
||||
@@ -130,12 +126,10 @@ impl Transfer {
|
||||
#[cfg(feature = "std")]
|
||||
pub fn into_signed_tx(self) -> Extrinsic {
|
||||
let signature = sp_keyring::AccountKeyring::from_public(&self.from)
|
||||
.expect("Creates keyring from public key.").sign(&self.encode()).into();
|
||||
Extrinsic::Transfer {
|
||||
transfer: self,
|
||||
signature,
|
||||
exhaust_resources_when_not_first: false,
|
||||
}
|
||||
.expect("Creates keyring from public key.")
|
||||
.sign(&self.encode())
|
||||
.into();
|
||||
Extrinsic::Transfer { transfer: self, signature, exhaust_resources_when_not_first: false }
|
||||
}
|
||||
|
||||
/// Convert into a signed extrinsic, which will only end up included in the block
|
||||
@@ -144,12 +138,10 @@ impl Transfer {
|
||||
#[cfg(feature = "std")]
|
||||
pub fn into_resources_exhausting_tx(self) -> Extrinsic {
|
||||
let signature = sp_keyring::AccountKeyring::from_public(&self.from)
|
||||
.expect("Creates keyring from public key.").sign(&self.encode()).into();
|
||||
Extrinsic::Transfer {
|
||||
transfer: self,
|
||||
signature,
|
||||
exhaust_resources_when_not_first: true,
|
||||
}
|
||||
.expect("Creates keyring from public key.")
|
||||
.sign(&self.encode())
|
||||
.into();
|
||||
Extrinsic::Transfer { transfer: self, signature, exhaust_resources_when_not_first: true }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +166,10 @@ parity_util_mem::malloc_size_of_is_0!(Extrinsic); // non-opaque extrinsic does n
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl serde::Serialize for Extrinsic {
|
||||
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
|
||||
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ::serde::Serializer,
|
||||
{
|
||||
self.using_encoded(|bytes| seq.serialize_bytes(bytes))
|
||||
}
|
||||
}
|
||||
@@ -185,21 +180,22 @@ impl BlindCheckable for Extrinsic {
|
||||
fn check(self) -> Result<Self, TransactionValidityError> {
|
||||
match self {
|
||||
Extrinsic::AuthoritiesChange(new_auth) => Ok(Extrinsic::AuthoritiesChange(new_auth)),
|
||||
Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first } => {
|
||||
Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first } =>
|
||||
if sp_runtime::verify_encoded_lazy(&signature, &transfer, &transfer.from) {
|
||||
Ok(Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first })
|
||||
Ok(Extrinsic::Transfer {
|
||||
transfer,
|
||||
signature,
|
||||
exhaust_resources_when_not_first,
|
||||
})
|
||||
} else {
|
||||
Err(InvalidTransaction::BadProof.into())
|
||||
}
|
||||
},
|
||||
},
|
||||
Extrinsic::IncludeData(v) => Ok(Extrinsic::IncludeData(v)),
|
||||
Extrinsic::StorageChange(key, value) => Ok(Extrinsic::StorageChange(key, value)),
|
||||
Extrinsic::ChangesTrieConfigUpdate(new_config) =>
|
||||
Ok(Extrinsic::ChangesTrieConfigUpdate(new_config)),
|
||||
Extrinsic::OffchainIndexSet(key, value) =>
|
||||
Ok(Extrinsic::OffchainIndexSet(key, value)),
|
||||
Extrinsic::OffchainIndexClear(key) =>
|
||||
Ok(Extrinsic::OffchainIndexClear(key)),
|
||||
Extrinsic::OffchainIndexSet(key, value) => Ok(Extrinsic::OffchainIndexSet(key, value)),
|
||||
Extrinsic::OffchainIndexClear(key) => Ok(Extrinsic::OffchainIndexClear(key)),
|
||||
Extrinsic::Store(data) => Ok(Extrinsic::Store(data)),
|
||||
}
|
||||
}
|
||||
@@ -301,9 +297,7 @@ impl<B: BlockT> codec::EncodeLike for DecodeFails<B> {}
|
||||
impl<B: BlockT> DecodeFails<B> {
|
||||
/// Create a new instance.
|
||||
pub fn new() -> DecodeFails<B> {
|
||||
DecodeFails {
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
DecodeFails { _phantom: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,7 +613,8 @@ fn code_using_trie() -> u64 {
|
||||
let pairs = [
|
||||
(b"0103000000000000000464".to_vec(), b"0400000000".to_vec()),
|
||||
(b"0103000000000000000469".to_vec(), b"0401000000".to_vec()),
|
||||
].to_vec();
|
||||
]
|
||||
.to_vec();
|
||||
|
||||
let mut mdb = PrefixedMemoryDB::default();
|
||||
let mut root = sp_std::default::Default::default();
|
||||
@@ -627,10 +622,10 @@ fn code_using_trie() -> u64 {
|
||||
let v = &pairs;
|
||||
let mut t = TrieDBMut::<Hashing>::new(&mut mdb, &mut root);
|
||||
for i in 0..v.len() {
|
||||
let key: &[u8]= &v[i].0;
|
||||
let key: &[u8] = &v[i].0;
|
||||
let val: &[u8] = &v[i].1;
|
||||
if !t.insert(key, val).is_ok() {
|
||||
return 101;
|
||||
return 101
|
||||
}
|
||||
}
|
||||
t
|
||||
@@ -645,8 +640,12 @@ fn code_using_trie() -> u64 {
|
||||
}
|
||||
}
|
||||
iter_pairs.len() as u64
|
||||
} else { 102 }
|
||||
} else { 103 }
|
||||
} else {
|
||||
102
|
||||
}
|
||||
} else {
|
||||
103
|
||||
}
|
||||
}
|
||||
|
||||
impl_opaque_keys! {
|
||||
@@ -1206,29 +1205,15 @@ fn test_read_storage() {
|
||||
fn test_read_child_storage() {
|
||||
const STORAGE_KEY: &[u8] = b"unique_id_1";
|
||||
const KEY: &[u8] = b":read_child_storage";
|
||||
sp_io::default_child_storage::set(
|
||||
STORAGE_KEY,
|
||||
KEY,
|
||||
b"test",
|
||||
);
|
||||
sp_io::default_child_storage::set(STORAGE_KEY, KEY, b"test");
|
||||
|
||||
let mut v = [0u8; 4];
|
||||
let r = sp_io::default_child_storage::read(
|
||||
STORAGE_KEY,
|
||||
KEY,
|
||||
&mut v,
|
||||
0,
|
||||
);
|
||||
let r = sp_io::default_child_storage::read(STORAGE_KEY, KEY, &mut v, 0);
|
||||
assert_eq!(r, Some(4));
|
||||
assert_eq!(&v, b"test");
|
||||
|
||||
let mut v = [0u8; 4];
|
||||
let r = sp_io::default_child_storage::read(
|
||||
STORAGE_KEY,
|
||||
KEY,
|
||||
&mut v,
|
||||
8,
|
||||
);
|
||||
let r = sp_io::default_child_storage::read(STORAGE_KEY, KEY, &mut v, 8);
|
||||
assert_eq!(r, Some(0));
|
||||
assert_eq!(&v, &[0, 0, 0, 0]);
|
||||
}
|
||||
@@ -1236,10 +1221,7 @@ fn test_read_child_storage() {
|
||||
fn test_witness(proof: StorageProof, root: crate::Hash) {
|
||||
use sp_externalities::Externalities;
|
||||
let db: sp_trie::MemoryDB<crate::Hashing> = proof.into_memory_db();
|
||||
let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new(
|
||||
db,
|
||||
root,
|
||||
);
|
||||
let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new(db, root);
|
||||
let mut overlay = sp_state_machine::OverlayedChanges::default();
|
||||
let mut cache = sp_state_machine::StorageTransactionCache::<_, _, BlockNumber>::default();
|
||||
let mut ext = sp_state_machine::Ext::new(
|
||||
@@ -1259,18 +1241,16 @@ fn test_witness(proof: StorageProof, root: crate::Hash) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
sp_consensus::BlockOrigin,
|
||||
DefaultTestClientBuilderExt, TestClientBuilder,
|
||||
runtime::TestAPI,
|
||||
};
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_core::storage::well_known_keys::HEAP_PAGES;
|
||||
use sp_state_machine::ExecutionStrategy;
|
||||
use codec::Encode;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sp_api::ProvideRuntimeApi;
|
||||
use sp_core::storage::well_known_keys::HEAP_PAGES;
|
||||
use sp_runtime::generic::BlockId;
|
||||
use sp_state_machine::ExecutionStrategy;
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*, runtime::TestAPI, sp_consensus::BlockOrigin, DefaultTestClientBuilderExt,
|
||||
TestClientBuilder,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn heap_pages_is_respected() {
|
||||
@@ -1307,9 +1287,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_storage() {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::Both)
|
||||
.build();
|
||||
let client =
|
||||
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
||||
|
||||
@@ -1331,14 +1310,10 @@ mod tests {
|
||||
#[test]
|
||||
fn witness_backend_works() {
|
||||
let (db, root) = witness_backend();
|
||||
let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new(
|
||||
db,
|
||||
root,
|
||||
);
|
||||
let backend = sp_state_machine::TrieBackend::<_, crate::Hashing>::new(db, root);
|
||||
let proof = sp_state_machine::prove_read(backend, vec![b"value3"]).unwrap();
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::Both)
|
||||
.build();
|
||||
let client =
|
||||
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
||||
|
||||
|
||||
@@ -18,25 +18,27 @@
|
||||
//! System manager: Handles all of the top-level stuff; executing block/transaction, setting code
|
||||
//! and depositing logs.
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use sp_io::{
|
||||
storage::root as storage_root, storage::changes_root as storage_changes_root,
|
||||
hashing::blake2_256, trie,
|
||||
};
|
||||
use frame_support::storage;
|
||||
use frame_support::{decl_storage, decl_module};
|
||||
use sp_runtime::{
|
||||
traits::Header as _, generic, ApplyExtrinsicResult,
|
||||
transaction_validity::{
|
||||
TransactionValidity, ValidTransaction, InvalidTransaction, TransactionValidityError,
|
||||
},
|
||||
};
|
||||
use codec::{KeyedVec, Encode, Decode};
|
||||
use frame_system::Config;
|
||||
use crate::{
|
||||
AccountId, BlockNumber, Extrinsic, Transfer, H256 as Hash, Block, Header, Digest, AuthorityId
|
||||
AccountId, AuthorityId, Block, BlockNumber, Digest, Extrinsic, Header, Transfer, H256 as Hash,
|
||||
};
|
||||
use codec::{Decode, Encode, KeyedVec};
|
||||
use frame_support::{decl_module, decl_storage, storage};
|
||||
use frame_system::Config;
|
||||
use sp_core::{storage::well_known_keys, ChangesTrieConfiguration};
|
||||
use sp_io::{
|
||||
hashing::blake2_256,
|
||||
storage::{changes_root as storage_changes_root, root as storage_root},
|
||||
trie,
|
||||
};
|
||||
use sp_runtime::{
|
||||
generic,
|
||||
traits::Header as _,
|
||||
transaction_validity::{
|
||||
InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,
|
||||
},
|
||||
ApplyExtrinsicResult,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
const NONCE_OF: &[u8] = b"nonce:";
|
||||
const BALANCE_OF: &[u8] = b"balance:";
|
||||
@@ -159,17 +161,17 @@ impl frame_support::traits::ExecuteBlock<Block> for BlockExecutor {
|
||||
/// This doesn't attempt to validate anything regarding the block.
|
||||
pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity {
|
||||
if check_signature(&utx).is_err() {
|
||||
return InvalidTransaction::BadProof.into();
|
||||
return InvalidTransaction::BadProof.into()
|
||||
}
|
||||
|
||||
let tx = utx.transfer();
|
||||
let nonce_key = tx.from.to_keyed_vec(NONCE_OF);
|
||||
let expected_nonce: u64 = storage::hashed::get_or(&blake2_256, &nonce_key, 0);
|
||||
if tx.nonce < expected_nonce {
|
||||
return InvalidTransaction::Stale.into();
|
||||
return InvalidTransaction::Stale.into()
|
||||
}
|
||||
if tx.nonce > expected_nonce + 64 {
|
||||
return InvalidTransaction::Future.into();
|
||||
return InvalidTransaction::Future.into()
|
||||
}
|
||||
|
||||
let encode = |from: &AccountId, nonce: u64| (from, nonce).encode();
|
||||
@@ -181,20 +183,14 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity {
|
||||
|
||||
let provides = vec![encode(&tx.from, tx.nonce)];
|
||||
|
||||
Ok(ValidTransaction {
|
||||
priority: tx.amount,
|
||||
requires,
|
||||
provides,
|
||||
longevity: 64,
|
||||
propagate: true,
|
||||
})
|
||||
Ok(ValidTransaction { priority: tx.amount, requires, provides, longevity: 64, propagate: true })
|
||||
}
|
||||
|
||||
/// Execute a transaction outside of the block execution function.
|
||||
/// This doesn't attempt to validate anything regarding the block.
|
||||
pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult {
|
||||
let extrinsic_index: u32 = storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX)
|
||||
.unwrap_or_default();
|
||||
let extrinsic_index: u32 =
|
||||
storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap_or_default();
|
||||
let result = execute_transaction_backend(&utx, extrinsic_index);
|
||||
ExtrinsicData::insert(extrinsic_index, utx.encode());
|
||||
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1));
|
||||
@@ -215,8 +211,8 @@ pub fn finalize_block() -> Header {
|
||||
|
||||
// This MUST come after all changes to storage are done. Otherwise we will fail the
|
||||
// “Storage root does not match that calculated” assertion.
|
||||
let storage_root = Hash::decode(&mut &storage_root()[..])
|
||||
.expect("`storage_root` is a valid hash");
|
||||
let storage_root =
|
||||
Hash::decode(&mut &storage_root()[..]).expect("`storage_root` is a valid hash");
|
||||
let storage_changes_root = storage_changes_root(&parent_hash.encode())
|
||||
.map(|r| Hash::decode(&mut &r[..]).expect("`storage_changes_root` is a valid hash"));
|
||||
|
||||
@@ -231,17 +227,11 @@ pub fn finalize_block() -> Header {
|
||||
|
||||
if let Some(new_config) = new_changes_trie_config {
|
||||
digest.push(generic::DigestItem::ChangesTrieSignal(
|
||||
generic::ChangesTrieSignal::NewConfiguration(new_config)
|
||||
generic::ChangesTrieSignal::NewConfiguration(new_config),
|
||||
));
|
||||
}
|
||||
|
||||
Header {
|
||||
number,
|
||||
extrinsics_root,
|
||||
state_root: storage_root,
|
||||
parent_hash,
|
||||
digest,
|
||||
}
|
||||
Header { number, extrinsics_root, state_root: storage_root, parent_hash, digest }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -253,12 +243,11 @@ fn check_signature(utx: &Extrinsic) -> Result<(), TransactionValidityError> {
|
||||
fn execute_transaction_backend(utx: &Extrinsic, extrinsic_index: u32) -> ApplyExtrinsicResult {
|
||||
check_signature(utx)?;
|
||||
match utx {
|
||||
Extrinsic::Transfer { exhaust_resources_when_not_first: true, .. } if extrinsic_index != 0 =>
|
||||
Extrinsic::Transfer { exhaust_resources_when_not_first: true, .. }
|
||||
if extrinsic_index != 0 =>
|
||||
Err(InvalidTransaction::ExhaustsResources.into()),
|
||||
Extrinsic::Transfer { ref transfer, .. } =>
|
||||
execute_transfer_backend(transfer),
|
||||
Extrinsic::AuthoritiesChange(ref new_auth) =>
|
||||
execute_new_authorities_backend(new_auth),
|
||||
Extrinsic::Transfer { ref transfer, .. } => execute_transfer_backend(transfer),
|
||||
Extrinsic::AuthoritiesChange(ref new_auth) => execute_new_authorities_backend(new_auth),
|
||||
Extrinsic::IncludeData(_) => Ok(Ok(())),
|
||||
Extrinsic::StorageChange(key, value) =>
|
||||
execute_storage_change(key, value.as_ref().map(|v| &**v)),
|
||||
@@ -271,9 +260,8 @@ fn execute_transaction_backend(utx: &Extrinsic, extrinsic_index: u32) -> ApplyEx
|
||||
Extrinsic::OffchainIndexClear(key) => {
|
||||
sp_io::offchain_index::clear(&key);
|
||||
Ok(Ok(()))
|
||||
}
|
||||
Extrinsic::Store(data) =>
|
||||
execute_store(data.clone()),
|
||||
},
|
||||
Extrinsic::Store(data) => execute_store(data.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +270,7 @@ fn execute_transfer_backend(tx: &Transfer) -> ApplyExtrinsicResult {
|
||||
let nonce_key = tx.from.to_keyed_vec(NONCE_OF);
|
||||
let expected_nonce: u64 = storage::hashed::get_or(&blake2_256, &nonce_key, 0);
|
||||
if !(tx.nonce == expected_nonce) {
|
||||
return Err(InvalidTransaction::Stale.into());
|
||||
return Err(InvalidTransaction::Stale.into())
|
||||
}
|
||||
|
||||
// increment nonce in storage
|
||||
@@ -294,7 +282,7 @@ fn execute_transfer_backend(tx: &Transfer) -> ApplyExtrinsicResult {
|
||||
|
||||
// enact transfer
|
||||
if !(tx.amount <= from_balance) {
|
||||
return Err(InvalidTransaction::Payment.into());
|
||||
return Err(InvalidTransaction::Payment.into())
|
||||
}
|
||||
let to_balance_key = tx.to.to_keyed_vec(BALANCE_OF);
|
||||
let to_balance: u64 = storage::hashed::get_or(&blake2_256, &to_balance_key, 0);
|
||||
@@ -323,12 +311,12 @@ fn execute_storage_change(key: &[u8], value: Option<&[u8]>) -> ApplyExtrinsicRes
|
||||
Ok(Ok(()))
|
||||
}
|
||||
|
||||
fn execute_changes_trie_config_update(new_config: Option<ChangesTrieConfiguration>) -> ApplyExtrinsicResult {
|
||||
fn execute_changes_trie_config_update(
|
||||
new_config: Option<ChangesTrieConfiguration>,
|
||||
) -> ApplyExtrinsicResult {
|
||||
match new_config.clone() {
|
||||
Some(new_config) => storage::unhashed::put_raw(
|
||||
well_known_keys::CHANGES_TRIE_CONFIG,
|
||||
&new_config.encode(),
|
||||
),
|
||||
Some(new_config) =>
|
||||
storage::unhashed::put_raw(well_known_keys::CHANGES_TRIE_CONFIG, &new_config.encode()),
|
||||
None => storage::unhashed::kill(well_known_keys::CHANGES_TRIE_CONFIG),
|
||||
}
|
||||
<NewChangesTrieConfig>::put(new_config);
|
||||
@@ -360,19 +348,18 @@ fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use sp_io::TestExternalities;
|
||||
use crate::{wasm_binary_unwrap, Header, Transfer};
|
||||
use sc_executor::{native_executor_instance, NativeExecutor, WasmExecutionMethod};
|
||||
use sp_core::{
|
||||
map,
|
||||
traits::{CodeExecutor, RuntimeCode},
|
||||
NeverNativeValue,
|
||||
};
|
||||
use sp_io::{hashing::twox_128, TestExternalities};
|
||||
use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring};
|
||||
use crate::{Header, Transfer, wasm_binary_unwrap};
|
||||
use sp_core::{NeverNativeValue, map, traits::{CodeExecutor, RuntimeCode}};
|
||||
use sc_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance};
|
||||
use sp_io::hashing::twox_128;
|
||||
|
||||
// Declare an instance of the native executor dispatch for the test runtime.
|
||||
native_executor_instance!(
|
||||
NativeDispatch,
|
||||
crate::api::dispatch,
|
||||
crate::native_version
|
||||
);
|
||||
native_executor_instance!(NativeDispatch, crate::api::dispatch, crate::native_version);
|
||||
|
||||
fn executor() -> NativeExecutor<NativeDispatch> {
|
||||
NativeExecutor::new(WasmExecutionMethod::Interpreted, None, 8)
|
||||
@@ -382,7 +369,7 @@ mod tests {
|
||||
let authorities = vec![
|
||||
Sr25519Keyring::Alice.to_raw_public(),
|
||||
Sr25519Keyring::Bob.to_raw_public(),
|
||||
Sr25519Keyring::Charlie.to_raw_public()
|
||||
Sr25519Keyring::Charlie.to_raw_public(),
|
||||
];
|
||||
TestExternalities::new_with_code(
|
||||
wasm_binary_unwrap(),
|
||||
@@ -399,7 +386,10 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
fn block_import_works<F>(block_executor: F) where F: Fn(Block, &mut TestExternalities) {
|
||||
fn block_import_works<F>(block_executor: F)
|
||||
where
|
||||
F: Fn(Block, &mut TestExternalities),
|
||||
{
|
||||
let h = Header {
|
||||
parent_hash: [69u8; 32].into(),
|
||||
number: 1,
|
||||
@@ -407,10 +397,7 @@ mod tests {
|
||||
extrinsics_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
};
|
||||
let mut b = Block {
|
||||
header: h,
|
||||
extrinsics: vec![],
|
||||
};
|
||||
let mut b = Block { header: h, extrinsics: vec![] };
|
||||
|
||||
new_test_ext().execute_with(|| polish_block(&mut b));
|
||||
|
||||
@@ -419,7 +406,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn block_import_works_native() {
|
||||
block_import_works(|b, ext| ext.execute_with(|| { execute_block(b); }));
|
||||
block_import_works(|b, ext| {
|
||||
ext.execute_with(|| {
|
||||
execute_block(b);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -432,19 +423,23 @@ mod tests {
|
||||
heap_pages: None,
|
||||
};
|
||||
|
||||
executor().call::<NeverNativeValue, fn() -> _>(
|
||||
&mut ext,
|
||||
&runtime_code,
|
||||
"Core_execute_block",
|
||||
&b.encode(),
|
||||
false,
|
||||
None,
|
||||
).0.unwrap();
|
||||
executor()
|
||||
.call::<NeverNativeValue, fn() -> _>(
|
||||
&mut ext,
|
||||
&runtime_code,
|
||||
"Core_execute_block",
|
||||
&b.encode(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
fn block_import_with_transaction_works<F>(block_executor: F)
|
||||
where F: Fn(Block, &mut TestExternalities)
|
||||
where
|
||||
F: Fn(Block, &mut TestExternalities),
|
||||
{
|
||||
let mut b1 = Block {
|
||||
header: Header {
|
||||
@@ -454,14 +449,13 @@ mod tests {
|
||||
extrinsics_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
},
|
||||
extrinsics: vec![
|
||||
Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
amount: 69,
|
||||
nonce: 0,
|
||||
}.into_signed_tx()
|
||||
],
|
||||
extrinsics: vec![Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
amount: 69,
|
||||
nonce: 0,
|
||||
}
|
||||
.into_signed_tx()],
|
||||
};
|
||||
|
||||
let mut dummy_ext = new_test_ext();
|
||||
@@ -481,13 +475,15 @@ mod tests {
|
||||
to: AccountKeyring::Alice.into(),
|
||||
amount: 27,
|
||||
nonce: 0,
|
||||
}.into_signed_tx(),
|
||||
}
|
||||
.into_signed_tx(),
|
||||
Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Charlie.into(),
|
||||
amount: 69,
|
||||
nonce: 1,
|
||||
}.into_signed_tx(),
|
||||
}
|
||||
.into_signed_tx(),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -519,7 +515,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn block_import_with_transaction_works_native() {
|
||||
block_import_with_transaction_works(|b, ext| ext.execute_with(|| { execute_block(b); }));
|
||||
block_import_with_transaction_works(|b, ext| {
|
||||
ext.execute_with(|| {
|
||||
execute_block(b);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -532,14 +532,17 @@ mod tests {
|
||||
heap_pages: None,
|
||||
};
|
||||
|
||||
executor().call::<NeverNativeValue, fn() -> _>(
|
||||
&mut ext,
|
||||
&runtime_code,
|
||||
"Core_execute_block",
|
||||
&b.encode(),
|
||||
false,
|
||||
None,
|
||||
).0.unwrap();
|
||||
executor()
|
||||
.call::<NeverNativeValue, fn() -> _>(
|
||||
&mut ext,
|
||||
&runtime_code,
|
||||
"Core_execute_block",
|
||||
&b.encode(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,22 +20,22 @@
|
||||
//! See [`TestApi`] for more information.
|
||||
|
||||
use codec::Encode;
|
||||
use futures::future::ready;
|
||||
use parking_lot::RwLock;
|
||||
use sp_blockchain::CachedHeaderMetadata;
|
||||
use sp_runtime::{
|
||||
generic::{self, BlockId},
|
||||
traits::{BlakeTwo256, Hash as HashT, Block as BlockT, Header as _},
|
||||
traits::{BlakeTwo256, Block as BlockT, Hash as HashT, Header as _},
|
||||
transaction_validity::{
|
||||
TransactionValidity, ValidTransaction, TransactionValidityError, InvalidTransaction,
|
||||
TransactionSource,
|
||||
InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
|
||||
ValidTransaction,
|
||||
},
|
||||
};
|
||||
use std::collections::{HashSet, HashMap, BTreeMap};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::{Index, AccountId, Block, BlockNumber, Extrinsic, Hash, Header, Transfer},
|
||||
runtime::{AccountId, Block, BlockNumber, Extrinsic, Hash, Header, Index, Transfer},
|
||||
AccountKeyring::{self, *},
|
||||
};
|
||||
use sp_blockchain::CachedHeaderMetadata;
|
||||
use futures::future::ready;
|
||||
|
||||
/// Error type used by [`TestApi`].
|
||||
#[derive(Debug, derive_more::From, derive_more::Display)]
|
||||
@@ -130,12 +130,9 @@ impl TestApi {
|
||||
block_number
|
||||
.checked_sub(1)
|
||||
.and_then(|num| {
|
||||
chain.block_by_number
|
||||
.get(&num)
|
||||
.map(|blocks| {
|
||||
blocks[0].0.header.hash()
|
||||
})
|
||||
}).unwrap_or_default()
|
||||
chain.block_by_number.get(&num).map(|blocks| blocks[0].0.header.hash())
|
||||
})
|
||||
.unwrap_or_default()
|
||||
};
|
||||
|
||||
self.push_block_with_parent(parent_hash, xts, is_best_block)
|
||||
@@ -154,7 +151,9 @@ impl TestApi {
|
||||
let block_number = if parent == Hash::default() {
|
||||
0
|
||||
} else {
|
||||
*self.chain.read()
|
||||
*self
|
||||
.chain
|
||||
.read()
|
||||
.block_by_hash
|
||||
.get(&parent)
|
||||
.expect("`parent` exists")
|
||||
@@ -182,7 +181,11 @@ impl TestApi {
|
||||
|
||||
let mut chain = self.chain.write();
|
||||
chain.block_by_hash.insert(hash, block.clone());
|
||||
chain.block_by_number.entry(block_number).or_default().push((block, is_best_block.into()));
|
||||
chain
|
||||
.block_by_number
|
||||
.entry(block_number)
|
||||
.or_default()
|
||||
.push((block, is_best_block.into()));
|
||||
}
|
||||
|
||||
fn hash_and_length_inner(ex: &Extrinsic) -> (Hash, usize) {
|
||||
@@ -195,9 +198,7 @@ impl TestApi {
|
||||
/// Next time transaction pool will try to validate this
|
||||
/// extrinsic, api will return invalid result.
|
||||
pub fn add_invalid(&self, xts: &Extrinsic) {
|
||||
self.chain.write().invalid_hashes.insert(
|
||||
Self::hash_and_length_inner(xts).0
|
||||
);
|
||||
self.chain.write().invalid_hashes.insert(Self::hash_and_length_inner(xts).0);
|
||||
}
|
||||
|
||||
/// Query validation requests received.
|
||||
@@ -242,7 +243,8 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
|
||||
match self.block_id_to_number(at) {
|
||||
Ok(Some(number)) => {
|
||||
let found_best = self.chain
|
||||
let found_best = self
|
||||
.chain
|
||||
.read()
|
||||
.block_by_number
|
||||
.get(&number)
|
||||
@@ -253,24 +255,24 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
// the transaction. (This is not required for this test function, but in real
|
||||
// environment it would fail because of this).
|
||||
if !found_best {
|
||||
return ready(Ok(
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(1)).into())
|
||||
))
|
||||
return ready(Ok(Err(TransactionValidityError::Invalid(
|
||||
InvalidTransaction::Custom(1),
|
||||
)
|
||||
.into())))
|
||||
}
|
||||
},
|
||||
Ok(None) => return ready(Ok(
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(2)).into())
|
||||
)),
|
||||
Ok(None) =>
|
||||
return ready(Ok(Err(TransactionValidityError::Invalid(
|
||||
InvalidTransaction::Custom(2),
|
||||
)
|
||||
.into()))),
|
||||
Err(e) => return ready(Err(e)),
|
||||
}
|
||||
|
||||
let (requires, provides) = if let Some(transfer) = uxt.try_transfer() {
|
||||
let chain_nonce = self.chain.read().nonces.get(&transfer.from).cloned().unwrap_or(0);
|
||||
let requires = if chain_nonce == transfer.nonce {
|
||||
vec![]
|
||||
} else {
|
||||
vec![vec![chain_nonce as u8]]
|
||||
};
|
||||
let requires =
|
||||
if chain_nonce == transfer.nonce { vec![] } else { vec![vec![chain_nonce as u8]] };
|
||||
let provides = vec![vec![transfer.nonce as u8]];
|
||||
|
||||
(requires, provides)
|
||||
@@ -279,18 +281,13 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
};
|
||||
|
||||
if self.chain.read().invalid_hashes.contains(&self.hash_and_length(&uxt).0) {
|
||||
return ready(Ok(
|
||||
Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into())
|
||||
))
|
||||
return ready(Ok(Err(
|
||||
TransactionValidityError::Invalid(InvalidTransaction::Custom(0)).into()
|
||||
)))
|
||||
}
|
||||
|
||||
let mut validity = ValidTransaction {
|
||||
priority: 1,
|
||||
requires,
|
||||
provides,
|
||||
longevity: 64,
|
||||
propagate: true,
|
||||
};
|
||||
let mut validity =
|
||||
ValidTransaction { priority: 1, requires, provides, longevity: 64, propagate: true };
|
||||
|
||||
(self.valid_modifier.read())(&mut validity);
|
||||
|
||||
@@ -302,11 +299,8 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> Result<Option<sc_transaction_pool::test_helpers::NumberFor<Self>>, Error> {
|
||||
Ok(match at {
|
||||
generic::BlockId::Hash(x) => self.chain
|
||||
.read()
|
||||
.block_by_hash
|
||||
.get(x)
|
||||
.map(|b| *b.header.number()),
|
||||
generic::BlockId::Hash(x) =>
|
||||
self.chain.read().block_by_hash.get(x).map(|b| *b.header.number()),
|
||||
generic::BlockId::Number(num) => Some(*num),
|
||||
})
|
||||
}
|
||||
@@ -317,11 +311,10 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
) -> Result<Option<sc_transaction_pool::test_helpers::BlockHash<Self>>, Error> {
|
||||
Ok(match at {
|
||||
generic::BlockId::Hash(x) => Some(x.clone()),
|
||||
generic::BlockId::Number(num) => self.chain
|
||||
.read()
|
||||
.block_by_number
|
||||
.get(num)
|
||||
.and_then(|blocks| blocks.iter().find(|b| b.1.is_best()).map(|b| b.0.header().hash())),
|
||||
generic::BlockId::Number(num) =>
|
||||
self.chain.read().block_by_number.get(num).and_then(|blocks| {
|
||||
blocks.iter().find(|b| b.1.is_best()).map(|b| b.0.header().hash())
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -334,16 +327,10 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
|
||||
fn block_body(&self, id: &BlockId<Self::Block>) -> Self::BodyFuture {
|
||||
futures::future::ready(Ok(match id {
|
||||
BlockId::Number(num) => self.chain
|
||||
.read()
|
||||
.block_by_number
|
||||
.get(num)
|
||||
.map(|b| b[0].0.extrinsics().to_vec()),
|
||||
BlockId::Hash(hash) => self.chain
|
||||
.read()
|
||||
.block_by_hash
|
||||
.get(hash)
|
||||
.map(|b| b.extrinsics().to_vec()),
|
||||
BlockId::Number(num) =>
|
||||
self.chain.read().block_by_number.get(num).map(|b| b[0].0.extrinsics().to_vec()),
|
||||
BlockId::Hash(hash) =>
|
||||
self.chain.read().block_by_hash.get(hash).map(|b| b.extrinsics().to_vec()),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -352,16 +339,10 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
at: &BlockId<Self::Block>,
|
||||
) -> Result<Option<<Self::Block as BlockT>::Header>, Self::Error> {
|
||||
Ok(match at {
|
||||
BlockId::Number(num) => self.chain
|
||||
.read()
|
||||
.block_by_number
|
||||
.get(num)
|
||||
.map(|b| b[0].0.header().clone()),
|
||||
BlockId::Hash(hash) => self.chain
|
||||
.read()
|
||||
.block_by_hash
|
||||
.get(hash)
|
||||
.map(|b| b.header().clone()),
|
||||
BlockId::Number(num) =>
|
||||
self.chain.read().block_by_number.get(num).map(|b| b[0].0.header().clone()),
|
||||
BlockId::Hash(hash) =>
|
||||
self.chain.read().block_by_hash.get(hash).map(|b| b.header().clone()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -369,21 +350,14 @@ impl sc_transaction_pool::test_helpers::ChainApi for TestApi {
|
||||
impl sp_blockchain::HeaderMetadata<Block> for TestApi {
|
||||
type Error = Error;
|
||||
|
||||
fn header_metadata(
|
||||
&self,
|
||||
hash: Hash,
|
||||
) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
|
||||
fn header_metadata(&self, hash: Hash) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
|
||||
let chain = self.chain.read();
|
||||
let block = chain.block_by_hash.get(&hash).expect("Hash exists");
|
||||
|
||||
Ok(block.header().into())
|
||||
}
|
||||
|
||||
fn insert_header_metadata(
|
||||
&self,
|
||||
_: Hash,
|
||||
_: CachedHeaderMetadata<Block>,
|
||||
) {
|
||||
fn insert_header_metadata(&self, _: Hash, _: CachedHeaderMetadata<Block>) {
|
||||
unimplemented!("Not implemented for tests")
|
||||
}
|
||||
|
||||
@@ -396,12 +370,7 @@ impl sp_blockchain::HeaderMetadata<Block> for TestApi {
|
||||
///
|
||||
/// Part of the test api.
|
||||
pub fn uxt(who: AccountKeyring, nonce: Index) -> Extrinsic {
|
||||
let transfer = Transfer {
|
||||
from: who.into(),
|
||||
to: AccountId::default(),
|
||||
nonce,
|
||||
amount: 1,
|
||||
};
|
||||
let transfer = Transfer { from: who.into(), to: AccountId::default(), nonce, amount: 1 };
|
||||
let signature = transfer.using_encoded(|e| who.sign(e)).into();
|
||||
Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user