mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 08:51:09 +00:00
substrate-test-runtime migrated to "pure" frame runtime (#13737)
* substrate-test-runtime migrated to pure-frame based * test block builder: helpers added * simple renaming * basic_authorship test adjusted * block_building storage_proof test adjusted * babe: tests: should_panic expected added * babe: tests adjusted ConsensusLog::NextEpochData is now added by pallet_babe as pallet_babe::SameAuthoritiesForever trigger is used in runtime config. * beefy: tests adjusted test-substrate-runtime is now using frame::executive to finalize the block. during finalization the digests stored during block execution are checked against header digests: https://github.com/paritytech/substrate/blob/91bb2d29ca905599098a5b35eaf24867c4fbd60a/frame/executive/src/lib.rs#L585-L591 It makes impossible to directly manipulate header's digets, w/o depositing logs into system pallet storage `Digest<T: Config>`. Instead of this dedicated extrinsic allowing to store logs items (MmrRoot / AuthoritiesChange) is used. * grandpa: tests adjusted test-substrate-runtime is now using frame::executive to finalize the block. during finalization the digest logs stored during block execution are checked against header digest logs: https://github.com/paritytech/substrate/blob/91bb2d29ca905599098a5b35eaf24867c4fbd60a/frame/executive/src/lib.rs#L585-L591 It makes impossible to directly manipulate header's digets, w/o depositing logs into system pallet storage `Digest<T: Config>`. Instead of this dedicated extrinsic allowing to store logs items (ScheduledChange / ForcedChange and DigestItem::Other) is used. * network:bitswap: test adjusted The size of unchecked extrinsic was increased. The pattern used in test will be placed at the end of scale-encoded buffer. * runtime apis versions adjusted * storage keys used in runtime adjusted * wasm vs native tests removed * rpc tests: adjusted Transfer transaction processing was slightly improved, test was adjusted. * tests: sizes adjusted Runtime extrinsic size was increased. Size of data read during block execution was also increased due to usage of new pallets in runtime. Sizes were adjusted in tests. * cargo.lock update cargo update -p substrate-test-runtime -p substrate-test-runtime-client * warnings fixed * builders cleanup: includes / std * extrinsic validation cleanup * txpool: benches performance fixed * fmt * spelling * Apply suggestions from code review Co-authored-by: Davide Galassi <davxy@datawok.net> * Apply code review suggestions * Apply code review suggestions * get rid of 1063 const * renaming: UncheckedExtrinsic -> Extrinsic * test-utils-runtime: further step to pure-frame * basic-authorship: tests OK * CheckSubstrateCall added + tests fixes * test::Transfer call removed * priority / propagate / no sudo+root-testing * fixing warnings + format * cleanup: build2/nonce + format * final tests fixes all tests are passing * logs/comments removal * should_not_accept_old_signatures test removed * make txpool benches work again * Cargo.lock reset * format * sudo hack removed * txpool benches fix+cleanup * .gitignore reverted * rebase fixing + unsigned cleanup * Cargo.toml/Cargo.lock cleanup * force-debug feature removed * mmr tests fixed * make cargo-clippy happy * network sync test uses unsigned extrinsic * cleanup * ".git/.scripts/commands/fmt/fmt.sh" * push_storage_change signed call remove * GenesisConfig cleanup * fix * fix * GenesisConfig simplified * storage_keys_works: reworked * storage_keys_works: expected keys in vec * storage keys list moved to substrate-test-runtime * substrate-test: some sanity tests + GenesisConfigBuilder rework * Apply suggestions from code review Co-authored-by: Bastian Köcher <git@kchr.de> * Apply suggestions from code review * Review suggestions * fix * fix * beefy: generate_blocks_and_sync block_num sync with actaul value * Apply suggestions from code review Co-authored-by: Davide Galassi <davxy@datawok.net> * Update test-utils/runtime/src/genesismap.rs Co-authored-by: Davide Galassi <davxy@datawok.net> * cargo update -p sc-rpc -p sc-transaction-pool * Review suggestions * fix * doc added * slot_duration adjusted for Babe::slot_duration * small doc fixes * array_bytes::hex used instead of hex * tiny -> medium name fix * Apply suggestions from code review Co-authored-by: Sebastian Kunert <skunert49@gmail.com> * TransferData::try_from_unchecked_extrinsic -> try_from * Update Cargo.lock --------- Co-authored-by: parity-processbot <> Co-authored-by: Davide Galassi <davxy@datawok.net> Co-authored-by: Bastian Köcher <git@kchr.de> Co-authored-by: Sebastian Kunert <skunert49@gmail.com>
This commit is contained in:
committed by
GitHub
parent
3a90728de0
commit
6a295e7c28
Generated
+46
-34
@@ -291,6 +291,12 @@ version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6"
|
||||
|
||||
[[package]]
|
||||
name = "array-bytes"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
@@ -597,7 +603,7 @@ dependencies = [
|
||||
name = "binary-merkle-tree"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"env_logger 0.9.3",
|
||||
"hash-db",
|
||||
"log",
|
||||
@@ -2327,7 +2333,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||
name = "frame-benchmarking"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"frame-support",
|
||||
"frame-support-procedural",
|
||||
"frame-system",
|
||||
@@ -2355,7 +2361,7 @@ name = "frame-benchmarking-cli"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"chrono",
|
||||
"clap 4.2.5",
|
||||
"comfy-table",
|
||||
@@ -2465,7 +2471,7 @@ dependencies = [
|
||||
name = "frame-executive"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"frame-try-runtime",
|
||||
@@ -5043,7 +5049,7 @@ dependencies = [
|
||||
name = "node-bench"
|
||||
version = "0.9.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"clap 4.2.5",
|
||||
"derive_more",
|
||||
"fs_extra",
|
||||
@@ -5079,7 +5085,7 @@ dependencies = [
|
||||
name = "node-cli"
|
||||
version = "3.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_cmd",
|
||||
"clap 4.2.5",
|
||||
"clap_complete",
|
||||
@@ -5641,7 +5647,7 @@ dependencies = [
|
||||
name = "pallet-alliance"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
@@ -5898,7 +5904,7 @@ dependencies = [
|
||||
name = "pallet-beefy-mmr"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"binary-merkle-tree",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
@@ -5975,7 +5981,7 @@ dependencies = [
|
||||
name = "pallet-contracts"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_matches",
|
||||
"bitflags",
|
||||
"env_logger 0.9.3",
|
||||
@@ -6420,7 +6426,7 @@ dependencies = [
|
||||
name = "pallet-mmr"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"env_logger 0.9.3",
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
@@ -7128,7 +7134,7 @@ dependencies = [
|
||||
name = "pallet-transaction-storage"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
@@ -8584,7 +8590,7 @@ dependencies = [
|
||||
name = "sc-cli"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"chrono",
|
||||
"clap 4.2.5",
|
||||
"fdlimit",
|
||||
@@ -8655,7 +8661,7 @@ dependencies = [
|
||||
name = "sc-client-db"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"criterion",
|
||||
"hash-db",
|
||||
"kitchensink-runtime",
|
||||
@@ -8822,7 +8828,7 @@ dependencies = [
|
||||
name = "sc-consensus-beefy"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"async-trait",
|
||||
"fnv",
|
||||
"futures",
|
||||
@@ -8899,7 +8905,7 @@ name = "sc-consensus-grandpa"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_matches",
|
||||
"async-trait",
|
||||
"dyn-clone",
|
||||
@@ -9053,7 +9059,7 @@ dependencies = [
|
||||
name = "sc-executor"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_matches",
|
||||
"criterion",
|
||||
"env_logger 0.9.3",
|
||||
@@ -9156,7 +9162,7 @@ dependencies = [
|
||||
name = "sc-keystore"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"async-trait",
|
||||
"parking_lot 0.12.1",
|
||||
"serde_json",
|
||||
@@ -9171,7 +9177,7 @@ dependencies = [
|
||||
name = "sc-network"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_matches",
|
||||
"async-channel",
|
||||
"async-trait",
|
||||
@@ -9253,7 +9259,7 @@ dependencies = [
|
||||
name = "sc-network-common"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"async-trait",
|
||||
"bitflags",
|
||||
"bytes",
|
||||
@@ -9302,7 +9308,7 @@ dependencies = [
|
||||
name = "sc-network-light"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"futures",
|
||||
"libp2p",
|
||||
"log",
|
||||
@@ -9323,7 +9329,7 @@ dependencies = [
|
||||
name = "sc-network-statement"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"async-channel",
|
||||
"futures",
|
||||
"libp2p",
|
||||
@@ -9343,7 +9349,7 @@ dependencies = [
|
||||
name = "sc-network-sync"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"async-trait",
|
||||
"fork-tree",
|
||||
"futures",
|
||||
@@ -9413,7 +9419,7 @@ dependencies = [
|
||||
name = "sc-network-transactions"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"futures",
|
||||
"libp2p",
|
||||
"log",
|
||||
@@ -9432,7 +9438,7 @@ dependencies = [
|
||||
name = "sc-offchain"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures",
|
||||
@@ -9562,7 +9568,7 @@ dependencies = [
|
||||
name = "sc-rpc-spec-v2"
|
||||
version = "0.10.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_matches",
|
||||
"futures",
|
||||
"futures-util",
|
||||
@@ -9676,7 +9682,7 @@ dependencies = [
|
||||
name = "sc-service-test"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"async-channel",
|
||||
"fdlimit",
|
||||
"futures",
|
||||
@@ -9858,7 +9864,7 @@ dependencies = [
|
||||
name = "sc-transaction-pool"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_matches",
|
||||
"async-trait",
|
||||
"criterion",
|
||||
@@ -10585,7 +10591,7 @@ dependencies = [
|
||||
name = "sp-consensus-beefy"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"lazy_static",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
@@ -10644,7 +10650,7 @@ dependencies = [
|
||||
name = "sp-core"
|
||||
version = "7.0.0"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"bitflags",
|
||||
"blake2",
|
||||
"bounded-collections",
|
||||
@@ -10824,7 +10830,7 @@ dependencies = [
|
||||
name = "sp-mmr-primitives"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"ckb-merkle-mountain-range",
|
||||
"log",
|
||||
"parity-scale-codec",
|
||||
@@ -11031,7 +11037,7 @@ dependencies = [
|
||||
name = "sp-state-machine"
|
||||
version = "0.13.0"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"assert_matches",
|
||||
"hash-db",
|
||||
"log",
|
||||
@@ -11149,7 +11155,7 @@ name = "sp-trie"
|
||||
version = "7.0.0"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"criterion",
|
||||
"hash-db",
|
||||
"hashbrown 0.13.2",
|
||||
@@ -11501,7 +11507,7 @@ dependencies = [
|
||||
name = "substrate-test-client"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"array-bytes 4.2.0",
|
||||
"async-trait",
|
||||
"futures",
|
||||
"parity-scale-codec",
|
||||
@@ -11526,7 +11532,8 @@ dependencies = [
|
||||
name = "substrate-test-runtime"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"array-bytes 6.1.0",
|
||||
"frame-executive",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"frame-system-rpc-runtime-api",
|
||||
@@ -11534,7 +11541,10 @@ dependencies = [
|
||||
"log",
|
||||
"memory-db",
|
||||
"pallet-babe",
|
||||
"pallet-balances",
|
||||
"pallet-beefy-mmr",
|
||||
"pallet-root-testing",
|
||||
"pallet-sudo",
|
||||
"pallet-timestamp",
|
||||
"parity-scale-codec",
|
||||
"sc-block-builder",
|
||||
@@ -11551,6 +11561,7 @@ dependencies = [
|
||||
"sp-consensus-beefy",
|
||||
"sp-consensus-grandpa",
|
||||
"sp-core",
|
||||
"sp-debug-derive",
|
||||
"sp-externalities",
|
||||
"sp-inherents",
|
||||
"sp-io",
|
||||
@@ -11561,6 +11572,7 @@ dependencies = [
|
||||
"sp-session",
|
||||
"sp-state-machine",
|
||||
"sp-std",
|
||||
"sp-tracing",
|
||||
"sp-transaction-pool",
|
||||
"sp-trie",
|
||||
"sp-version",
|
||||
|
||||
@@ -547,37 +547,29 @@ mod tests {
|
||||
use sp_api::Core;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_consensus::{BlockOrigin, Environment, Proposer};
|
||||
use sp_core::Pair;
|
||||
use sp_runtime::{generic::BlockId, traits::NumberFor};
|
||||
use sp_runtime::{generic::BlockId, traits::NumberFor, Perbill};
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
runtime::{Extrinsic, Transfer},
|
||||
runtime::{Block as TestBlock, Extrinsic, ExtrinsicBuilder, Transfer},
|
||||
TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
fn extrinsic(nonce: u64) -> Extrinsic {
|
||||
Transfer {
|
||||
amount: Default::default(),
|
||||
nonce,
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
}
|
||||
.into_signed_tx()
|
||||
}
|
||||
// Note:
|
||||
// Maximum normal extrinsic size for `substrate_test_runtime` is ~65% of max_block (refer to
|
||||
// `substrate_test_runtime::RuntimeBlockWeights` for details).
|
||||
// This extrinsic sizing allows for:
|
||||
// - one huge xts + a lot of tiny dust
|
||||
// - one huge, no medium,
|
||||
// - two medium xts
|
||||
// This is widely exploited in following tests.
|
||||
const HUGE: u32 = 649000000;
|
||||
const MEDIUM: u32 = 250000000;
|
||||
const TINY: u32 = 1000;
|
||||
|
||||
fn exhausts_resources_extrinsic_from(who: usize) -> Extrinsic {
|
||||
let pair = AccountKeyring::numeric(who);
|
||||
let transfer = Transfer {
|
||||
// increase the amount to bump priority
|
||||
amount: 1,
|
||||
nonce: 0,
|
||||
from: pair.public(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
};
|
||||
let signature = pair.sign(&transfer.encode()).into();
|
||||
Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: true }
|
||||
fn extrinsic(nonce: u64) -> Extrinsic {
|
||||
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY)).nonce(nonce).build()
|
||||
}
|
||||
|
||||
fn chain_event<B: BlockT>(header: B::Header) -> ChainEvent<B>
|
||||
@@ -738,7 +730,7 @@ mod tests {
|
||||
#[test]
|
||||
fn should_not_remove_invalid_transactions_from_the_same_sender_after_one_was_invalid() {
|
||||
// given
|
||||
let mut client = Arc::new(substrate_test_runtime_client::new());
|
||||
let client = Arc::new(substrate_test_runtime_client::new());
|
||||
let spawner = sp_core::testing::TaskExecutor::new();
|
||||
let txpool = BasicPool::new_full(
|
||||
Default::default(),
|
||||
@@ -748,38 +740,29 @@ mod tests {
|
||||
client.clone(),
|
||||
);
|
||||
|
||||
let medium = |nonce| {
|
||||
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(MEDIUM))
|
||||
.nonce(nonce)
|
||||
.build()
|
||||
};
|
||||
let huge = |nonce| {
|
||||
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(HUGE)).nonce(nonce).build()
|
||||
};
|
||||
|
||||
block_on(txpool.submit_at(
|
||||
&BlockId::number(0),
|
||||
SOURCE,
|
||||
vec![
|
||||
extrinsic(0),
|
||||
extrinsic(1),
|
||||
Transfer {
|
||||
amount: Default::default(),
|
||||
nonce: 2,
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
}.into_resources_exhausting_tx(),
|
||||
extrinsic(3),
|
||||
Transfer {
|
||||
amount: Default::default(),
|
||||
nonce: 4,
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
}.into_resources_exhausting_tx(),
|
||||
extrinsic(5),
|
||||
extrinsic(6),
|
||||
],
|
||||
vec![medium(0), medium(1), huge(2), medium(3), huge(4), medium(5), medium(6)],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let mut proposer_factory =
|
||||
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||
let mut propose_block = |client: &TestClient,
|
||||
number,
|
||||
parent_number,
|
||||
expected_block_extrinsics,
|
||||
expected_pool_transactions| {
|
||||
let hash = client.expect_block_hash_from_id(&BlockId::Number(number)).unwrap();
|
||||
let hash = client.expect_block_hash_from_id(&BlockId::Number(parent_number)).unwrap();
|
||||
let proposer = proposer_factory.init_with_now(
|
||||
&client.expect_header(hash).unwrap(),
|
||||
Box::new(move || time::Instant::now()),
|
||||
@@ -794,12 +777,30 @@ mod tests {
|
||||
|
||||
// then
|
||||
// block should have some extrinsics although we have some more in the pool.
|
||||
assert_eq!(txpool.ready().count(), expected_pool_transactions);
|
||||
assert_eq!(block.extrinsics().len(), expected_block_extrinsics);
|
||||
assert_eq!(
|
||||
txpool.ready().count(),
|
||||
expected_pool_transactions,
|
||||
"at block: {}",
|
||||
block.header.number
|
||||
);
|
||||
assert_eq!(
|
||||
block.extrinsics().len(),
|
||||
expected_block_extrinsics,
|
||||
"at block: {}",
|
||||
block.header.number
|
||||
);
|
||||
|
||||
block
|
||||
};
|
||||
|
||||
let import_and_maintain = |mut client: Arc<TestClient>, block: TestBlock| {
|
||||
let hash = block.hash();
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
block_on(txpool.maintain(chain_event(
|
||||
client.expect_header(hash).expect("there should be header"),
|
||||
)));
|
||||
};
|
||||
|
||||
block_on(
|
||||
txpool.maintain(chain_event(
|
||||
client
|
||||
@@ -811,19 +812,28 @@ mod tests {
|
||||
|
||||
// let's create one block and import it
|
||||
let block = propose_block(&client, 0, 2, 7);
|
||||
let hashof1 = block.hash();
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
|
||||
block_on(
|
||||
txpool.maintain(chain_event(
|
||||
client.expect_header(hashof1).expect("there should be header"),
|
||||
)),
|
||||
);
|
||||
import_and_maintain(client.clone(), block);
|
||||
assert_eq!(txpool.ready().count(), 5);
|
||||
|
||||
// now let's make sure that we can still make some progress
|
||||
let block = propose_block(&client, 1, 2, 5);
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
let block = propose_block(&client, 1, 1, 5);
|
||||
import_and_maintain(client.clone(), block);
|
||||
assert_eq!(txpool.ready().count(), 4);
|
||||
|
||||
// again let's make sure that we can still make some progress
|
||||
let block = propose_block(&client, 2, 1, 4);
|
||||
import_and_maintain(client.clone(), block);
|
||||
assert_eq!(txpool.ready().count(), 3);
|
||||
|
||||
// again let's make sure that we can still make some progress
|
||||
let block = propose_block(&client, 3, 1, 3);
|
||||
import_and_maintain(client.clone(), block);
|
||||
assert_eq!(txpool.ready().count(), 2);
|
||||
|
||||
// again let's make sure that we can still make some progress
|
||||
let block = propose_block(&client, 4, 2, 2);
|
||||
import_and_maintain(client.clone(), block);
|
||||
assert_eq!(txpool.ready().count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -849,9 +859,9 @@ mod tests {
|
||||
amount: 100,
|
||||
nonce: 0,
|
||||
}
|
||||
.into_signed_tx(),
|
||||
.into_unchecked_extrinsic(),
|
||||
)
|
||||
.chain((0..extrinsics_num - 1).map(|v| Extrinsic::IncludeData(vec![v as u8; 10])))
|
||||
.chain((1..extrinsics_num as u64).map(extrinsic))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let block_limit = genesis_header.encoded_size() +
|
||||
@@ -862,7 +872,7 @@ mod tests {
|
||||
.sum::<usize>() +
|
||||
Vec::<Extrinsic>::new().encoded_size();
|
||||
|
||||
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics)).unwrap();
|
||||
block_on(txpool.submit_at(&BlockId::number(0), SOURCE, extrinsics.clone())).unwrap();
|
||||
|
||||
block_on(txpool.maintain(chain_event(genesis_header.clone())));
|
||||
|
||||
@@ -905,7 +915,13 @@ mod tests {
|
||||
|
||||
let proposer = block_on(proposer_factory.init(&genesis_header)).unwrap();
|
||||
|
||||
// Give it enough time
|
||||
// Exact block_limit, which includes:
|
||||
// 99 (header_size) + 718 (proof@initialize_block) + 246 (one Transfer extrinsic)
|
||||
let block_limit = {
|
||||
let builder =
|
||||
client.new_block_at(genesis_header.hash(), Default::default(), true).unwrap();
|
||||
builder.estimate_block_size(true) + extrinsics[0].encoded_size()
|
||||
};
|
||||
let block = block_on(proposer.propose(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
@@ -915,7 +931,7 @@ mod tests {
|
||||
.map(|r| r.block)
|
||||
.unwrap();
|
||||
|
||||
// The block limit didn't changed, but we now include the proof in the estimation of the
|
||||
// The block limit was increased, but we now include the proof in the estimation of the
|
||||
// block size and thus, only the `Transfer` will fit into the block. It reads more data
|
||||
// than we have reserved in the block limit.
|
||||
assert_eq!(block.extrinsics().len(), 1);
|
||||
@@ -934,6 +950,15 @@ mod tests {
|
||||
client.clone(),
|
||||
);
|
||||
|
||||
let tiny = |nonce| {
|
||||
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY)).nonce(nonce).build()
|
||||
};
|
||||
let huge = |who| {
|
||||
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(HUGE))
|
||||
.signer(AccountKeyring::numeric(who))
|
||||
.build()
|
||||
};
|
||||
|
||||
block_on(
|
||||
txpool.submit_at(
|
||||
&BlockId::number(0),
|
||||
@@ -941,9 +966,9 @@ mod tests {
|
||||
// add 2 * MAX_SKIPPED_TRANSACTIONS that exhaust resources
|
||||
(0..MAX_SKIPPED_TRANSACTIONS * 2)
|
||||
.into_iter()
|
||||
.map(|i| exhausts_resources_extrinsic_from(i))
|
||||
.map(huge)
|
||||
// and some transactions that are okay.
|
||||
.chain((0..MAX_SKIPPED_TRANSACTIONS).into_iter().map(|i| extrinsic(i as _)))
|
||||
.chain((0..MAX_SKIPPED_TRANSACTIONS as u64).into_iter().map(tiny))
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
@@ -997,15 +1022,27 @@ mod tests {
|
||||
client.clone(),
|
||||
);
|
||||
|
||||
let tiny = |who| {
|
||||
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(TINY))
|
||||
.signer(AccountKeyring::numeric(who))
|
||||
.nonce(1)
|
||||
.build()
|
||||
};
|
||||
let huge = |who| {
|
||||
ExtrinsicBuilder::new_fill_block(Perbill::from_parts(HUGE))
|
||||
.signer(AccountKeyring::numeric(who))
|
||||
.build()
|
||||
};
|
||||
|
||||
block_on(
|
||||
txpool.submit_at(
|
||||
&BlockId::number(0),
|
||||
SOURCE,
|
||||
(0..MAX_SKIPPED_TRANSACTIONS + 2)
|
||||
.into_iter()
|
||||
.map(|i| exhausts_resources_extrinsic_from(i))
|
||||
.map(huge)
|
||||
// and some transactions that are okay.
|
||||
.chain((0..MAX_SKIPPED_TRANSACTIONS).into_iter().map(|i| extrinsic(i as _)))
|
||||
.chain((0..MAX_SKIPPED_TRANSACTIONS + 2).into_iter().map(tiny))
|
||||
.collect(),
|
||||
),
|
||||
)
|
||||
@@ -1018,7 +1055,7 @@ mod tests {
|
||||
.expect("there should be header"),
|
||||
)),
|
||||
);
|
||||
assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 2 + 2);
|
||||
assert_eq!(txpool.ready().count(), MAX_SKIPPED_TRANSACTIONS * 2 + 4);
|
||||
|
||||
let mut proposer_factory =
|
||||
ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None);
|
||||
@@ -1049,8 +1086,13 @@ mod tests {
|
||||
.map(|r| r.block)
|
||||
.unwrap();
|
||||
|
||||
// then the block should have no transactions despite some in the pool
|
||||
assert_eq!(block.extrinsics().len(), 1);
|
||||
// then the block should have one or two transactions. This maybe random as they are
|
||||
// processed in parallel. The same signer and consecutive nonces for huge and tiny
|
||||
// transactions guarantees that max two transactions will get to the block.
|
||||
assert!(
|
||||
(1..3).contains(&block.extrinsics().len()),
|
||||
"Block shall contain one or two extrinsics."
|
||||
);
|
||||
assert!(
|
||||
cell2.lock().0 > MAX_SKIPPED_TRANSACTIONS,
|
||||
"Not enough calls to current time, which indicates the test might have ended because of deadline, not soft deadline"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
//! # use sp_runtime::generic::BlockId;
|
||||
//! # use std::{sync::Arc, time::Duration};
|
||||
//! # use substrate_test_runtime_client::{
|
||||
//! # runtime::{Extrinsic, Transfer}, AccountKeyring,
|
||||
//! # runtime::Transfer, AccountKeyring,
|
||||
//! # DefaultTestClientBuilderExt, TestClientBuilderExt,
|
||||
//! # };
|
||||
//! # use sc_transaction_pool::{BasicPool, FullChainApi};
|
||||
|
||||
@@ -313,7 +313,7 @@ mod tests {
|
||||
use sp_core::Blake2Hasher;
|
||||
use sp_state_machine::Backend;
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::Extrinsic, DefaultTestClientBuilderExt, TestClientBuilderExt,
|
||||
runtime::ExtrinsicBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -322,9 +322,11 @@ mod tests {
|
||||
let backend = builder.backend();
|
||||
let client = builder.build();
|
||||
|
||||
let genesis_hash = client.info().best_hash;
|
||||
|
||||
let block = BlockBuilder::new(
|
||||
&client,
|
||||
client.info().best_hash,
|
||||
genesis_hash,
|
||||
client.info().best_number,
|
||||
RecordProof::Yes,
|
||||
Default::default(),
|
||||
@@ -335,12 +337,11 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let proof = block.proof.expect("Proof is build on request");
|
||||
let genesis_state_root = client.header(genesis_hash).unwrap().unwrap().state_root;
|
||||
|
||||
let backend = sp_state_machine::create_proof_check_backend::<Blake2Hasher>(
|
||||
block.storage_changes.transaction_storage_root,
|
||||
proof,
|
||||
)
|
||||
.unwrap();
|
||||
let backend =
|
||||
sp_state_machine::create_proof_check_backend::<Blake2Hasher>(genesis_state_root, proof)
|
||||
.unwrap();
|
||||
|
||||
assert!(backend
|
||||
.storage(&sp_core::storage::well_known_keys::CODE)
|
||||
@@ -364,7 +365,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
block_builder.push(Extrinsic::ReadAndPanic(8)).unwrap_err();
|
||||
block_builder.push(ExtrinsicBuilder::new_read_and_panic(8).build()).unwrap_err();
|
||||
|
||||
let block = block_builder.build().unwrap();
|
||||
|
||||
@@ -380,7 +381,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
block_builder.push(Extrinsic::Read(8)).unwrap();
|
||||
block_builder.push(ExtrinsicBuilder::new_read(8).build()).unwrap();
|
||||
|
||||
let block = block_builder.build().unwrap();
|
||||
|
||||
|
||||
@@ -71,15 +71,12 @@ const SLOT_DURATION_MS: u64 = 1000;
|
||||
struct DummyFactory {
|
||||
client: Arc<TestClient>,
|
||||
epoch_changes: SharedEpochChanges<TestBlock, Epoch>,
|
||||
config: BabeConfiguration,
|
||||
mutator: Mutator,
|
||||
}
|
||||
|
||||
struct DummyProposer {
|
||||
factory: DummyFactory,
|
||||
parent_hash: Hash,
|
||||
parent_number: u64,
|
||||
parent_slot: Slot,
|
||||
}
|
||||
|
||||
impl Environment<TestBlock> for DummyFactory {
|
||||
@@ -88,15 +85,9 @@ impl Environment<TestBlock> for DummyFactory {
|
||||
type Error = Error;
|
||||
|
||||
fn init(&mut self, parent_header: &<TestBlock as BlockT>::Header) -> Self::CreateProposer {
|
||||
let parent_slot = crate::find_pre_digest::<TestBlock>(parent_header)
|
||||
.expect("parent header has a pre-digest")
|
||||
.slot();
|
||||
|
||||
future::ready(Ok(DummyProposer {
|
||||
factory: self.clone(),
|
||||
parent_hash: parent_header.hash(),
|
||||
parent_number: *parent_header.number(),
|
||||
parent_slot,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -123,39 +114,6 @@ impl DummyProposer {
|
||||
Err(e) => return future::ready(Err(e)),
|
||||
};
|
||||
|
||||
let this_slot = crate::find_pre_digest::<TestBlock>(block.header())
|
||||
.expect("baked block has valid pre-digest")
|
||||
.slot();
|
||||
|
||||
// figure out if we should add a consensus digest, since the test runtime
|
||||
// doesn't.
|
||||
let epoch_changes = self.factory.epoch_changes.shared_data();
|
||||
let epoch = epoch_changes
|
||||
.epoch_data_for_child_of(
|
||||
descendent_query(&*self.factory.client),
|
||||
&self.parent_hash,
|
||||
self.parent_number,
|
||||
this_slot,
|
||||
|slot| Epoch::genesis(&self.factory.config, slot),
|
||||
)
|
||||
.expect("client has data to find epoch")
|
||||
.expect("can compute epoch for baked block");
|
||||
|
||||
let first_in_epoch = self.parent_slot < epoch.start_slot;
|
||||
if first_in_epoch {
|
||||
// push a `Consensus` digest signalling next change.
|
||||
// we just reuse the same randomness and authorities as the prior
|
||||
// epoch. this will break when we add light client support, since
|
||||
// that will re-check the randomness logic off-chain.
|
||||
let digest_data = ConsensusLog::NextEpochData(NextEpochDescriptor {
|
||||
authorities: epoch.authorities.clone(),
|
||||
randomness: epoch.randomness,
|
||||
})
|
||||
.encode();
|
||||
let digest = DigestItem::Consensus(BABE_ENGINE_ID, digest_data);
|
||||
block.header.digest_mut().push(digest)
|
||||
}
|
||||
|
||||
// mutate the block header according to the mutator.
|
||||
(self.factory.mutator)(&mut block.header, Stage::PreSeal);
|
||||
|
||||
@@ -351,7 +309,7 @@ impl TestNetFactory for BabeTestNet {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "No BABE pre-runtime digest found")]
|
||||
async fn rejects_empty_block() {
|
||||
sp_tracing::try_init_simple();
|
||||
let mut net = BabeTestNet::new(3);
|
||||
@@ -398,7 +356,6 @@ async fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + '
|
||||
|
||||
let environ = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: mutator.clone(),
|
||||
};
|
||||
@@ -483,7 +440,7 @@ async fn authoring_blocks() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "valid babe headers must contain a predigest")]
|
||||
async fn rejects_missing_inherent_digest() {
|
||||
run_one_test(|header: &mut TestHeader, stage| {
|
||||
let v = std::mem::take(&mut header.digest_mut().logs);
|
||||
@@ -496,7 +453,7 @@ async fn rejects_missing_inherent_digest() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "has a bad seal")]
|
||||
async fn rejects_missing_seals() {
|
||||
run_one_test(|header: &mut TestHeader, stage| {
|
||||
let v = std::mem::take(&mut header.digest_mut().logs);
|
||||
@@ -509,7 +466,7 @@ async fn rejects_missing_seals() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "Expected epoch change to happen")]
|
||||
async fn rejects_missing_consensus_digests() {
|
||||
run_one_test(|header: &mut TestHeader, stage| {
|
||||
let v = std::mem::take(&mut header.digest_mut().logs);
|
||||
@@ -770,7 +727,6 @@ async fn importing_block_one_sets_genesis_epoch() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
@@ -814,7 +770,6 @@ async fn revert_prunes_epoch_changes_and_removes_weights() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
@@ -902,7 +857,6 @@ async fn revert_not_allowed_for_finalized() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
@@ -943,7 +897,6 @@ async fn importing_epoch_change_block_prunes_tree() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
@@ -1030,7 +983,7 @@ async fn importing_epoch_change_block_prunes_tree() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[should_panic]
|
||||
#[should_panic(expected = "Slot number must increase: parent slot: 999, this slot: 999")]
|
||||
async fn verify_slots_are_strictly_increasing() {
|
||||
let mut net = BabeTestNet::new(1);
|
||||
|
||||
@@ -1042,7 +995,6 @@ async fn verify_slots_are_strictly_increasing() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
@@ -1082,7 +1034,6 @@ async fn obsolete_blocks_aux_data_cleanup() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
@@ -1168,7 +1119,6 @@ async fn allows_skipping_epochs() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
@@ -1298,7 +1248,6 @@ async fn allows_skipping_epochs_on_some_forks() {
|
||||
|
||||
let mut proposer_factory = DummyFactory {
|
||||
client: client.clone(),
|
||||
config: data.link.config.clone(),
|
||||
epoch_changes: data.link.epoch_changes.clone(),
|
||||
mutator: Arc::new(|_, _| ()),
|
||||
};
|
||||
|
||||
@@ -66,7 +66,7 @@ use sp_runtime::{
|
||||
BuildStorage, DigestItem, EncodedJustification, Justifications, Storage,
|
||||
};
|
||||
use std::{marker::PhantomData, sync::Arc, task::Poll};
|
||||
use substrate_test_runtime_client::{runtime::Header, ClientExt};
|
||||
use substrate_test_runtime_client::{BlockBuilderExt, ClientExt};
|
||||
use tokio::time::Duration;
|
||||
|
||||
const GENESIS_HASH: H256 = H256::zero();
|
||||
@@ -165,20 +165,22 @@ impl BeefyTestNet {
|
||||
// push genesis to make indexing human readable (index equals to block number)
|
||||
all_hashes.push(self.peer(0).client().info().genesis_hash);
|
||||
|
||||
let built_hashes = self.peer(0).generate_blocks(count, BlockOrigin::File, |builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
|
||||
let mut block_num: NumberFor<Block> = self.peer(0).client().info().best_number;
|
||||
let built_hashes = self.peer(0).generate_blocks(count, BlockOrigin::File, |mut builder| {
|
||||
block_num = block_num.saturating_add(1).try_into().unwrap();
|
||||
if include_mmr_digest {
|
||||
let block_num = *block.header.number();
|
||||
let num_byte = block_num.to_le_bytes().into_iter().next().unwrap();
|
||||
let mmr_root = MmrRootHash::repeat_byte(num_byte);
|
||||
add_mmr_digest(&mut block.header, mmr_root);
|
||||
add_mmr_digest(&mut builder, mmr_root);
|
||||
}
|
||||
|
||||
if *block.header.number() % session_length == 0 {
|
||||
add_auth_change_digest(&mut block.header, validator_set.clone());
|
||||
if block_num % session_length == 0 {
|
||||
add_auth_change_digest(&mut builder, validator_set.clone());
|
||||
}
|
||||
|
||||
let block = builder.build().unwrap().block;
|
||||
assert_eq!(block.header.number, block_num);
|
||||
|
||||
block
|
||||
});
|
||||
all_hashes.extend(built_hashes);
|
||||
@@ -325,18 +327,22 @@ sp_api::mock_impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_mmr_digest(header: &mut Header, mmr_hash: MmrRootHash) {
|
||||
header.digest_mut().push(DigestItem::Consensus(
|
||||
BEEFY_ENGINE_ID,
|
||||
ConsensusLog::<AuthorityId>::MmrRoot(mmr_hash).encode(),
|
||||
));
|
||||
fn add_mmr_digest(builder: &mut impl BlockBuilderExt, mmr_hash: MmrRootHash) {
|
||||
builder
|
||||
.push_deposit_log_digest_item(DigestItem::Consensus(
|
||||
BEEFY_ENGINE_ID,
|
||||
ConsensusLog::<AuthorityId>::MmrRoot(mmr_hash).encode(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn add_auth_change_digest(header: &mut Header, new_auth_set: BeefyValidatorSet) {
|
||||
header.digest_mut().push(DigestItem::Consensus(
|
||||
BEEFY_ENGINE_ID,
|
||||
ConsensusLog::<AuthorityId>::AuthoritiesChange(new_auth_set).encode(),
|
||||
));
|
||||
fn add_auth_change_digest(builder: &mut impl BlockBuilderExt, new_auth_set: BeefyValidatorSet) {
|
||||
builder
|
||||
.push_deposit_log_digest_item(DigestItem::Consensus(
|
||||
BEEFY_ENGINE_ID,
|
||||
ConsensusLog::<AuthorityId>::AuthoritiesChange(new_auth_set).encode(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec<AuthorityId> {
|
||||
|
||||
@@ -48,7 +48,7 @@ use sp_runtime::{
|
||||
Justifications,
|
||||
};
|
||||
use std::{collections::HashSet, pin::Pin};
|
||||
use substrate_test_runtime_client::runtime::BlockNumber;
|
||||
use substrate_test_runtime_client::{runtime::BlockNumber, BlockBuilderExt};
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
use authorities::AuthoritySet;
|
||||
@@ -399,22 +399,27 @@ async fn run_to_completion(
|
||||
run_to_completion_with(blocks, net, peers, |_| None).await
|
||||
}
|
||||
|
||||
fn add_scheduled_change(block: &mut Block, change: ScheduledChange<BlockNumber>) {
|
||||
block.header.digest_mut().push(DigestItem::Consensus(
|
||||
GRANDPA_ENGINE_ID,
|
||||
sp_consensus_grandpa::ConsensusLog::ScheduledChange(change).encode(),
|
||||
));
|
||||
fn add_scheduled_change(builder: &mut impl BlockBuilderExt, change: ScheduledChange<BlockNumber>) {
|
||||
builder
|
||||
.push_deposit_log_digest_item(DigestItem::Consensus(
|
||||
GRANDPA_ENGINE_ID,
|
||||
sp_consensus_grandpa::ConsensusLog::ScheduledChange(change).encode(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn add_forced_change(
|
||||
block: &mut Block,
|
||||
builder: &mut impl BlockBuilderExt,
|
||||
median_last_finalized: BlockNumber,
|
||||
change: ScheduledChange<BlockNumber>,
|
||||
) {
|
||||
block.header.digest_mut().push(DigestItem::Consensus(
|
||||
GRANDPA_ENGINE_ID,
|
||||
sp_consensus_grandpa::ConsensusLog::ForcedChange(median_last_finalized, change).encode(),
|
||||
));
|
||||
builder
|
||||
.push_deposit_log_digest_item(DigestItem::Consensus(
|
||||
GRANDPA_ENGINE_ID,
|
||||
sp_consensus_grandpa::ConsensusLog::ForcedChange(median_last_finalized, change)
|
||||
.encode(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -605,28 +610,24 @@ async fn transition_3_voters_twice_1_full_observer() {
|
||||
},
|
||||
14 => {
|
||||
// generate transition at block 15, applied at 20.
|
||||
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |mut builder| {
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(peers_b), delay: 4 },
|
||||
);
|
||||
|
||||
block
|
||||
builder.build().unwrap().block
|
||||
});
|
||||
net.lock().peer(0).push_blocks(5, false);
|
||||
},
|
||||
20 => {
|
||||
// at block 21 we do another transition, but this time instant.
|
||||
// add more until we have 30.
|
||||
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |mut builder| {
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(&peers_c), delay: 0 },
|
||||
);
|
||||
|
||||
block
|
||||
builder.build().unwrap().block
|
||||
});
|
||||
net.lock().peer(0).push_blocks(9, false);
|
||||
},
|
||||
@@ -708,13 +709,12 @@ async fn sync_justifications_on_change_blocks() {
|
||||
// at block 21 we do add a transition which is instant
|
||||
let hashof21 = net
|
||||
.peer(0)
|
||||
.generate_blocks(1, BlockOrigin::File, |builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
.generate_blocks(1, BlockOrigin::File, |mut builder| {
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
|
||||
);
|
||||
block
|
||||
builder.build().unwrap().block
|
||||
})
|
||||
.pop()
|
||||
.unwrap();
|
||||
@@ -778,26 +778,24 @@ async fn finalizes_multiple_pending_changes_in_order() {
|
||||
net.peer(0).push_blocks(20, false);
|
||||
|
||||
// at block 21 we do add a transition which is instant
|
||||
net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
net.peer(0).generate_blocks(1, BlockOrigin::File, |mut builder| {
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
|
||||
);
|
||||
block
|
||||
builder.build().unwrap().block
|
||||
});
|
||||
|
||||
// add more blocks on top of it (until we have 25)
|
||||
net.peer(0).push_blocks(4, false);
|
||||
|
||||
// at block 26 we add another which is enacted at block 30
|
||||
net.peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
net.peer(0).generate_blocks(1, BlockOrigin::File, |mut builder| {
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(peers_c), delay: 4 },
|
||||
);
|
||||
block
|
||||
builder.build().unwrap().block
|
||||
});
|
||||
|
||||
// add more blocks on top of it (until we have 30)
|
||||
@@ -833,23 +831,21 @@ async fn force_change_to_new_set() {
|
||||
let voters_future = initialize_grandpa(&mut net, peers_a);
|
||||
let net = Arc::new(Mutex::new(net));
|
||||
|
||||
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
|
||||
net.lock().peer(0).generate_blocks(1, BlockOrigin::File, |mut builder| {
|
||||
// add a forced transition at block 12.
|
||||
add_forced_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
0,
|
||||
ScheduledChange { next_authorities: voters.clone(), delay: 10 },
|
||||
);
|
||||
|
||||
// add a normal transition too to ensure that forced changes take priority.
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(genesis_authorities), delay: 5 },
|
||||
);
|
||||
|
||||
block
|
||||
builder.build().unwrap().block
|
||||
});
|
||||
|
||||
net.lock().peer(0).push_blocks(25, false);
|
||||
@@ -885,14 +881,15 @@ async fn allows_reimporting_change_blocks() {
|
||||
let (mut block_import, ..) = net.make_block_import(client.clone());
|
||||
|
||||
let full_client = client.as_client();
|
||||
let builder = full_client
|
||||
let mut builder = full_client
|
||||
.new_block_at(full_client.chain_info().genesis_hash, Default::default(), false)
|
||||
.unwrap();
|
||||
let mut block = builder.build().unwrap().block;
|
||||
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
|
||||
);
|
||||
let block = builder.build().unwrap().block;
|
||||
|
||||
let block = || {
|
||||
let block = block.clone();
|
||||
@@ -929,16 +926,17 @@ async fn test_bad_justification() {
|
||||
let (mut block_import, ..) = net.make_block_import(client.clone());
|
||||
|
||||
let full_client = client.as_client();
|
||||
let builder = full_client
|
||||
let mut builder = full_client
|
||||
.new_block_at(full_client.chain_info().genesis_hash, Default::default(), false)
|
||||
.unwrap();
|
||||
let mut block = builder.build().unwrap().block;
|
||||
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(peers_b), delay: 0 },
|
||||
);
|
||||
|
||||
let block = builder.build().unwrap().block;
|
||||
|
||||
let block = || {
|
||||
let block = block.clone();
|
||||
let mut import = BlockImportParams::new(BlockOrigin::File, block.header);
|
||||
@@ -1629,6 +1627,7 @@ async fn grandpa_environment_passes_actual_best_block_to_voting_rules() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_target() {
|
||||
sp_tracing::try_init_simple();
|
||||
use finality_grandpa::voter::Environment;
|
||||
|
||||
let peers = &[Ed25519Keyring::Alice];
|
||||
@@ -1662,10 +1661,9 @@ async fn grandpa_environment_checks_if_best_block_is_descendent_of_finality_targ
|
||||
BlockId::Number(4),
|
||||
6,
|
||||
BlockOrigin::File,
|
||||
|builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
block.header.digest_mut().push(DigestItem::Other(vec![1]));
|
||||
block
|
||||
|mut builder| {
|
||||
builder.push_deposit_log_digest_item(DigestItem::Other(vec![1])).unwrap();
|
||||
builder.build().unwrap().block
|
||||
},
|
||||
false,
|
||||
false,
|
||||
@@ -1999,13 +1997,12 @@ async fn revert_prunes_authority_changes() {
|
||||
|
||||
type TestBlockBuilder<'a> =
|
||||
BlockBuilder<'a, Block, PeersFullClient, substrate_test_runtime_client::Backend>;
|
||||
let edit_block = |builder: TestBlockBuilder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
let edit_block = |mut builder: TestBlockBuilder| {
|
||||
add_scheduled_change(
|
||||
&mut block,
|
||||
&mut builder,
|
||||
ScheduledChange { next_authorities: make_ids(peers), delay: 0 },
|
||||
);
|
||||
block
|
||||
builder.build().unwrap().block
|
||||
};
|
||||
|
||||
let api = TestApi::new(make_ids(peers));
|
||||
@@ -2047,10 +2044,9 @@ async fn revert_prunes_authority_changes() {
|
||||
BlockId::Number(23),
|
||||
3,
|
||||
BlockOrigin::File,
|
||||
|builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
block.header.digest_mut().push(DigestItem::Other(vec![1]));
|
||||
block
|
||||
|mut builder| {
|
||||
builder.push_deposit_log_digest_item(DigestItem::Other(vec![1])).unwrap();
|
||||
builder.build().unwrap().block
|
||||
},
|
||||
false,
|
||||
false,
|
||||
@@ -2079,10 +2075,9 @@ async fn revert_prunes_authority_changes() {
|
||||
BlockId::Number(25),
|
||||
3,
|
||||
BlockOrigin::File,
|
||||
|builder| {
|
||||
let mut block = builder.build().unwrap().block;
|
||||
block.header.digest_mut().push(DigestItem::Other(vec![2]));
|
||||
block
|
||||
|mut builder| {
|
||||
builder.push_deposit_log_digest_item(DigestItem::Other(vec![2])).unwrap();
|
||||
builder.build().unwrap().block
|
||||
},
|
||||
false,
|
||||
false,
|
||||
|
||||
@@ -326,11 +326,10 @@ mod tests {
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_consensus_grandpa::GRANDPA_ENGINE_ID;
|
||||
use sp_keyring::Ed25519Keyring;
|
||||
use sp_runtime::traits::Header as _;
|
||||
use std::sync::Arc;
|
||||
use substrate_test_runtime_client::{
|
||||
ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt, TestClientBuilder,
|
||||
TestClientBuilderExt,
|
||||
BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt,
|
||||
TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -348,8 +347,7 @@ mod tests {
|
||||
let mut authority_set_changes = Vec::new();
|
||||
|
||||
for n in 1..=100 {
|
||||
let mut block = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
let mut new_authorities = None;
|
||||
|
||||
// we will trigger an authority set change every 10 blocks
|
||||
@@ -376,9 +374,11 @@ mod tests {
|
||||
.encode(),
|
||||
);
|
||||
|
||||
block.header.digest_mut().logs.push(digest);
|
||||
builder.push_deposit_log_digest_item(digest).unwrap();
|
||||
}
|
||||
|
||||
let block = builder.build().unwrap().block;
|
||||
|
||||
futures::executor::block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
|
||||
if let Some(new_authorities) = new_authorities {
|
||||
|
||||
@@ -297,7 +297,7 @@ mod tests {
|
||||
};
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_runtime::codec::Encode;
|
||||
use substrate_test_runtime::Extrinsic;
|
||||
use substrate_test_runtime::ExtrinsicBuilder;
|
||||
use substrate_test_runtime_client::{self, prelude::*, TestClientBuilder};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -470,7 +470,9 @@ mod tests {
|
||||
let mut client = TestClientBuilder::with_tx_storage(u32::MAX).build();
|
||||
let mut block_builder = client.new_block(Default::default()).unwrap();
|
||||
|
||||
let ext = Extrinsic::Store(vec![0x13, 0x37, 0x13, 0x38]);
|
||||
// encoded extrinsic: [161, .. , 2, 6, 16, 19, 55, 19, 56]
|
||||
let ext = ExtrinsicBuilder::new_indexed_call(vec![0x13, 0x37, 0x13, 0x38]).build();
|
||||
let pattern_index = ext.encoded_size() - 4;
|
||||
|
||||
block_builder.push(ext.clone()).unwrap();
|
||||
let block = block_builder.build().unwrap().block;
|
||||
@@ -494,7 +496,7 @@ mod tests {
|
||||
0x70,
|
||||
cid::multihash::Multihash::wrap(
|
||||
u64::from(cid::multihash::Code::Blake2b256),
|
||||
&sp_core::hashing::blake2_256(&ext.encode()[2..]),
|
||||
&sp_core::hashing::blake2_256(&ext.encode()[pattern_index..]),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
|
||||
@@ -88,13 +88,11 @@ use sp_runtime::{
|
||||
};
|
||||
use substrate_test_runtime_client::AccountKeyring;
|
||||
pub use substrate_test_runtime_client::{
|
||||
runtime::{Block, Extrinsic, Hash, Header, Transfer},
|
||||
runtime::{Block, ExtrinsicBuilder, Hash, Header, Transfer},
|
||||
TestClient, TestClientBuilder, TestClientBuilderExt,
|
||||
};
|
||||
use tokio::time::timeout;
|
||||
|
||||
type AuthorityId = sp_consensus_babe::AuthorityId;
|
||||
|
||||
/// A Verifier that accepts all blocks and passes them on with the configured
|
||||
/// finality to be imported.
|
||||
#[derive(Clone)]
|
||||
@@ -474,7 +472,7 @@ where
|
||||
amount: 1,
|
||||
nonce,
|
||||
};
|
||||
builder.push(transfer.into_signed_tx()).unwrap();
|
||||
builder.push(transfer.into_unchecked_extrinsic()).unwrap();
|
||||
nonce += 1;
|
||||
builder.build().unwrap().block
|
||||
},
|
||||
@@ -497,16 +495,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_authorities_change_block(
|
||||
&mut self,
|
||||
new_authorities: Vec<AuthorityId>,
|
||||
) -> Vec<H256> {
|
||||
self.generate_blocks(1, BlockOrigin::File, |mut builder| {
|
||||
builder.push(Extrinsic::AuthoritiesChange(new_authorities.clone())).unwrap();
|
||||
builder.build().unwrap().block
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a reference to the client.
|
||||
pub fn client(&self) -> &PeersClient {
|
||||
&self.client
|
||||
|
||||
@@ -1183,7 +1183,7 @@ async fn syncs_indexed_blocks() {
|
||||
64,
|
||||
BlockOrigin::Own,
|
||||
|mut builder| {
|
||||
let ex = Extrinsic::Store(n.to_le_bytes().to_vec());
|
||||
let ex = ExtrinsicBuilder::new_indexed_call(n.to_le_bytes().to_vec()).nonce(n).build();
|
||||
n += 1;
|
||||
builder.push(ex).unwrap();
|
||||
builder.build().unwrap().block
|
||||
@@ -1305,11 +1305,13 @@ async fn syncs_huge_blocks() {
|
||||
builder.build().unwrap().block
|
||||
});
|
||||
|
||||
let mut nonce = 0;
|
||||
net.peer(0).generate_blocks(32, BlockOrigin::Own, |mut builder| {
|
||||
// Add 32 extrinsics 32k each = 1MiB total
|
||||
for _ in 0..32 {
|
||||
let ex = Extrinsic::IncludeData([42u8; 32 * 1024].to_vec());
|
||||
for _ in 0..32u64 {
|
||||
let ex = ExtrinsicBuilder::new_include_data(vec![42u8; 32 * 1024]).nonce(nonce).build();
|
||||
builder.push(ex).unwrap();
|
||||
nonce += 1;
|
||||
}
|
||||
builder.build().unwrap().block
|
||||
});
|
||||
|
||||
@@ -254,8 +254,10 @@ mod tests {
|
||||
use sp_runtime::generic::BlockId;
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::Block, ClientBlockImportExt, DefaultTestClientBuilderExt, TestClient,
|
||||
TestClientBuilderExt,
|
||||
runtime::{
|
||||
substrate_test_pallet::pallet::Call as PalletCall, Block, ExtrinsicBuilder, RuntimeCall,
|
||||
},
|
||||
ClientBlockImportExt, DefaultTestClientBuilderExt, TestClient, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
struct TestNetwork();
|
||||
@@ -385,7 +387,10 @@ mod tests {
|
||||
|
||||
// then
|
||||
assert_eq!(pool.0.status().ready, 1);
|
||||
assert_eq!(pool.0.ready().next().unwrap().is_propagable(), false);
|
||||
assert!(matches!(
|
||||
pool.0.ready().next().unwrap().data().function,
|
||||
RuntimeCall::SubstrateTest(PalletCall::storage_change { .. })
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -403,12 +408,8 @@ mod tests {
|
||||
let key = &b"hello"[..];
|
||||
let value = &b"world"[..];
|
||||
let mut block_builder = client.new_block(Default::default()).unwrap();
|
||||
block_builder
|
||||
.push(substrate_test_runtime_client::runtime::Extrinsic::OffchainIndexSet(
|
||||
key.to_vec(),
|
||||
value.to_vec(),
|
||||
))
|
||||
.unwrap();
|
||||
let ext = ExtrinsicBuilder::new_offchain_index_set(key.to_vec(), value.to_vec()).build();
|
||||
block_builder.push(ext).unwrap();
|
||||
|
||||
let block = block_builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
@@ -416,11 +417,8 @@ mod tests {
|
||||
assert_eq!(value, &offchain_db.get(sp_offchain::STORAGE_PREFIX, &key).unwrap());
|
||||
|
||||
let mut block_builder = client.new_block(Default::default()).unwrap();
|
||||
block_builder
|
||||
.push(substrate_test_runtime_client::runtime::Extrinsic::OffchainIndexClear(
|
||||
key.to_vec(),
|
||||
))
|
||||
.unwrap();
|
||||
let ext = ExtrinsicBuilder::new_offchain_index_clear(key.to_vec()).nonce(1).build();
|
||||
block_builder.push(ext).unwrap();
|
||||
|
||||
let block = block_builder.build().unwrap().block;
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
|
||||
@@ -184,12 +184,13 @@ async fn follow_with_runtime() {
|
||||
// Initialized must always be reported first.
|
||||
let event: FollowEvent<String> = get_next_event(&mut sub).await;
|
||||
|
||||
// it is basically json-encoded substrate_test_runtime_client::runtime::VERSION
|
||||
let runtime_str = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
|
||||
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\
|
||||
[\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\
|
||||
[\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\
|
||||
[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\
|
||||
\"transactionVersion\":1,\"stateVersion\":1}";
|
||||
[\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\
|
||||
[\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\
|
||||
[\"0xed99c5acb25eedf5\",3]],\"transactionVersion\":1,\"stateVersion\":1}";
|
||||
let runtime: RuntimeVersion = serde_json::from_str(runtime_str).unwrap();
|
||||
|
||||
let finalized_block_runtime =
|
||||
|
||||
@@ -37,10 +37,11 @@ use sp_core::{
|
||||
H256,
|
||||
};
|
||||
use sp_keystore::{testing::MemoryKeystore, Keystore};
|
||||
use sp_runtime::Perbill;
|
||||
use std::sync::Arc;
|
||||
use substrate_test_runtime_client::{
|
||||
self,
|
||||
runtime::{Block, Extrinsic, SessionKeys, Transfer},
|
||||
runtime::{Block, Extrinsic, ExtrinsicBuilder, SessionKeys, Transfer},
|
||||
AccountKeyring, Backend, Client, DefaultTestClientBuilderExt, TestClientBuilderExt,
|
||||
};
|
||||
|
||||
@@ -51,7 +52,7 @@ fn uxt(sender: AccountKeyring, nonce: u64) -> Extrinsic {
|
||||
from: sender.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
};
|
||||
tx.into_signed_tx()
|
||||
ExtrinsicBuilder::new_transfer(tx).build()
|
||||
}
|
||||
|
||||
type FullTransactionPool = BasicPool<FullChainApi<Client<Backend>, Block>, Block>;
|
||||
@@ -111,7 +112,13 @@ async fn author_submit_transaction_should_not_cause_error() {
|
||||
#[tokio::test]
|
||||
async fn author_should_watch_extrinsic() {
|
||||
let api = TestSetup::into_rpc();
|
||||
let xt = to_hex(&uxt(AccountKeyring::Alice, 0).encode(), true);
|
||||
let xt = to_hex(
|
||||
&ExtrinsicBuilder::new_call_with_priority(0)
|
||||
.signer(AccountKeyring::Alice.into())
|
||||
.build()
|
||||
.encode(),
|
||||
true,
|
||||
);
|
||||
|
||||
let mut sub = api.subscribe("author_submitAndWatchExtrinsic", [xt]).await.unwrap();
|
||||
let (tx, sub_id) = timeout_secs(10, sub.next::<TransactionStatus<H256, Block>>())
|
||||
@@ -125,15 +132,11 @@ async fn author_should_watch_extrinsic() {
|
||||
|
||||
// Replace the extrinsic and observe the subscription is notified.
|
||||
let (xt_replacement, xt_hash) = {
|
||||
let tx = Transfer {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
};
|
||||
let tx = tx.into_signed_tx().encode();
|
||||
let tx = ExtrinsicBuilder::new_call_with_priority(1)
|
||||
.signer(AccountKeyring::Alice.into())
|
||||
.build()
|
||||
.encode();
|
||||
let hash = blake2_256(&tx);
|
||||
|
||||
(to_hex(&tx, true), hash)
|
||||
};
|
||||
|
||||
@@ -152,10 +155,10 @@ async fn author_should_watch_extrinsic() {
|
||||
async fn author_should_return_watch_validation_error() {
|
||||
const METHOD: &'static str = "author_submitAndWatchExtrinsic";
|
||||
|
||||
let invalid_xt = ExtrinsicBuilder::new_fill_block(Perbill::from_percent(100)).build();
|
||||
|
||||
let api = TestSetup::into_rpc();
|
||||
let failed_sub = api
|
||||
.subscribe(METHOD, [to_hex(&uxt(AccountKeyring::Alice, 179).encode(), true)])
|
||||
.await;
|
||||
let failed_sub = api.subscribe(METHOD, [to_hex(&invalid_xt.encode(), true)]).await;
|
||||
|
||||
assert_matches!(
|
||||
failed_sub,
|
||||
|
||||
@@ -28,6 +28,22 @@ async fn block_stats_work() {
|
||||
let api = <Dev<Block, _>>::new(client.clone(), DenyUnsafe::No).into_rpc();
|
||||
|
||||
let block = client.new_block(Default::default()).unwrap().build().unwrap().block;
|
||||
|
||||
let (expected_witness_len, expected_witness_compact_len, expected_block_len) = {
|
||||
let genesis_hash = client.chain_info().genesis_hash;
|
||||
let mut runtime_api = client.runtime_api();
|
||||
runtime_api.record_proof();
|
||||
runtime_api.execute_block(genesis_hash, block.clone()).unwrap();
|
||||
let witness = runtime_api.extract_proof().unwrap();
|
||||
let pre_root = *client.header(genesis_hash).unwrap().unwrap().state_root();
|
||||
|
||||
(
|
||||
witness.clone().encoded_size() as u64,
|
||||
witness.into_compact_proof::<HasherOf<Block>>(pre_root).unwrap().encoded_size() as u64,
|
||||
block.encoded_size() as u64,
|
||||
)
|
||||
};
|
||||
|
||||
client.import(BlockOrigin::Own, block).await.unwrap();
|
||||
|
||||
// Can't gather stats for a block without a parent.
|
||||
@@ -43,9 +59,9 @@ async fn block_stats_work() {
|
||||
.await
|
||||
.unwrap(),
|
||||
Some(BlockStats {
|
||||
witness_len: 630,
|
||||
witness_compact_len: 534,
|
||||
block_len: 99,
|
||||
witness_len: expected_witness_len,
|
||||
witness_compact_len: expected_witness_compact_len,
|
||||
block_len: expected_block_len,
|
||||
num_extrinsics: 0,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -29,9 +29,11 @@ use sc_block_builder::BlockBuilderProvider;
|
||||
use sc_rpc_api::DenyUnsafe;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use sp_core::{hash::H256, storage::ChildInfo};
|
||||
use sp_io::hashing::blake2_256;
|
||||
use std::sync::Arc;
|
||||
use substrate_test_runtime_client::{prelude::*, runtime};
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
runtime::{ExtrinsicBuilder, Transfer},
|
||||
};
|
||||
|
||||
const STORAGE_KEY: &[u8] = b"child";
|
||||
|
||||
@@ -218,7 +220,7 @@ async fn should_notify_about_storage_changes() {
|
||||
// Cause a change:
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
builder
|
||||
.push_transfer(runtime::Transfer {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 42,
|
||||
@@ -244,18 +246,26 @@ async fn should_send_initial_storage_changes_and_notifications() {
|
||||
let mut client = Arc::new(substrate_test_runtime_client::new());
|
||||
let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No);
|
||||
|
||||
let alice_balance_key =
|
||||
blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into()));
|
||||
let alice_balance_key = [
|
||||
sp_core::hashing::twox_128(b"System"),
|
||||
sp_core::hashing::twox_128(b"Account"),
|
||||
sp_core::hashing::blake2_128(&AccountKeyring::Alice.public()),
|
||||
]
|
||||
.concat()
|
||||
.iter()
|
||||
.chain(AccountKeyring::Alice.public().0.iter())
|
||||
.cloned()
|
||||
.collect::<Vec<u8>>();
|
||||
|
||||
let api_rpc = api.into_rpc();
|
||||
let sub = api_rpc
|
||||
.subscribe("state_subscribeStorage", [[StorageKey(alice_balance_key.to_vec())]])
|
||||
.subscribe("state_subscribeStorage", [[StorageKey(alice_balance_key)]])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
builder
|
||||
.push_transfer(runtime::Transfer {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 42,
|
||||
@@ -280,22 +290,42 @@ async fn should_query_storage() {
|
||||
async fn run_tests(mut client: Arc<TestClient>) {
|
||||
let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No);
|
||||
|
||||
let mut add_block = |nonce| {
|
||||
let mut add_block = |index| {
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
// fake change: None -> None -> None
|
||||
builder.push_storage_change(vec![1], None).unwrap();
|
||||
builder
|
||||
.push(ExtrinsicBuilder::new_storage_change(vec![1], None).build())
|
||||
.unwrap();
|
||||
// fake change: None -> Some(value) -> Some(value)
|
||||
builder.push_storage_change(vec![2], Some(vec![2])).unwrap();
|
||||
builder
|
||||
.push(ExtrinsicBuilder::new_storage_change(vec![2], Some(vec![2])).build())
|
||||
.unwrap();
|
||||
// actual change: None -> Some(value) -> None
|
||||
builder
|
||||
.push_storage_change(vec![3], if nonce == 0 { Some(vec![3]) } else { None })
|
||||
.push(
|
||||
ExtrinsicBuilder::new_storage_change(
|
||||
vec![3],
|
||||
if index == 0 { Some(vec![3]) } else { None },
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
.unwrap();
|
||||
// actual change: None -> Some(value)
|
||||
builder
|
||||
.push_storage_change(vec![4], if nonce == 0 { None } else { Some(vec![4]) })
|
||||
.push(
|
||||
ExtrinsicBuilder::new_storage_change(
|
||||
vec![4],
|
||||
if index == 0 { None } else { Some(vec![4]) },
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
.unwrap();
|
||||
// actual change: Some(value1) -> Some(value2)
|
||||
builder.push_storage_change(vec![5], Some(vec![nonce as u8])).unwrap();
|
||||
builder
|
||||
.push(
|
||||
ExtrinsicBuilder::new_storage_change(vec![5], Some(vec![index as u8])).build(),
|
||||
)
|
||||
.unwrap();
|
||||
let block = builder.build().unwrap().block;
|
||||
let hash = block.header.hash();
|
||||
executor::block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
@@ -482,12 +512,13 @@ async fn should_return_runtime_version() {
|
||||
let client = Arc::new(substrate_test_runtime_client::new());
|
||||
let (api, _child) = new_full(client.clone(), test_executor(), DenyUnsafe::No);
|
||||
|
||||
// it is basically json-encoded substrate_test_runtime_client::runtime::VERSION
|
||||
let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
|
||||
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",4],\
|
||||
[\"0x37e397fc7c91f5e4\",2],[\"0xd2bc9897eed08f15\",3],[\"0x40fe3ad401f8959a\",6],\
|
||||
[\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\
|
||||
[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\
|
||||
\"transactionVersion\":1,\"stateVersion\":1}";
|
||||
[\"0xbc9d89904f5b923f\",1],[\"0xc6e9a76309f39b09\",2],[\"0xdd718d5cc53262d4\",1],\
|
||||
[\"0xcbca25e39f142387\",2],[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],\
|
||||
[\"0xed99c5acb25eedf5\",3]],\"transactionVersion\":1,\"stateVersion\":1}";
|
||||
|
||||
let runtime_version = api.runtime_version(None.into()).unwrap();
|
||||
let serialized = serde_json::to_string(&runtime_version).unwrap();
|
||||
|
||||
@@ -520,10 +520,9 @@ mod tests {
|
||||
use futures::executor::block_on;
|
||||
use sc_transaction_pool::BasicPool;
|
||||
use sp_consensus::SelectChain;
|
||||
use sp_runtime::traits::BlindCheckable;
|
||||
use substrate_test_runtime_client::{
|
||||
prelude::*,
|
||||
runtime::{Extrinsic, Transfer},
|
||||
runtime::{ExtrinsicBuilder, Transfer, TransferData},
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -542,13 +541,13 @@ mod tests {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
}
|
||||
.into_signed_tx();
|
||||
.into_unchecked_extrinsic();
|
||||
block_on(pool.submit_one(&BlockId::hash(best.hash()), source, transaction.clone()))
|
||||
.unwrap();
|
||||
block_on(pool.submit_one(
|
||||
&BlockId::hash(best.hash()),
|
||||
source,
|
||||
Extrinsic::IncludeData(vec![1]),
|
||||
ExtrinsicBuilder::new_call_do_not_propagate().nonce(1).build(),
|
||||
))
|
||||
.unwrap();
|
||||
assert_eq!(pool.status().ready, 2);
|
||||
@@ -558,8 +557,6 @@ mod tests {
|
||||
|
||||
// then
|
||||
assert_eq!(transactions.len(), 1);
|
||||
assert!(transactions[0].1.clone().check().is_ok());
|
||||
// this should not panic
|
||||
let _ = transactions[0].1.transfer();
|
||||
assert!(TransferData::try_from(&transactions[0].1).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ use substrate_test_runtime_client::{
|
||||
new_native_or_wasm_executor,
|
||||
prelude::*,
|
||||
runtime::{
|
||||
genesismap::{insert_genesis_block, GenesisConfig},
|
||||
currency::DOLLARS,
|
||||
genesismap::{insert_genesis_block, GenesisStorageBuilder},
|
||||
Block, BlockNumber, Digest, Hash, Header, RuntimeApi, Transfer,
|
||||
},
|
||||
AccountKeyring, BlockBuilderExt, ClientBlockImportExt, ClientExt, DefaultTestClientBuilderExt,
|
||||
@@ -66,7 +67,7 @@ fn construct_block(
|
||||
state_root: Hash,
|
||||
txs: Vec<Transfer>,
|
||||
) -> (Vec<u8>, Hash) {
|
||||
let transactions = txs.into_iter().map(|tx| tx.into_signed_tx()).collect::<Vec<_>>();
|
||||
let transactions = txs.into_iter().map(|tx| tx.into_unchecked_extrinsic()).collect::<Vec<_>>();
|
||||
|
||||
let iter = transactions.iter().map(Encode::encode);
|
||||
let extrinsics_root = LayoutV0::<BlakeTwo256>::ordered_trie_root(iter).into();
|
||||
@@ -137,9 +138,9 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend<BlakeTwo256>) -> (Vec<u8
|
||||
"25e5b37074063ab75c889326246640729b40d0c86932edc527bc80db0e04fe5c",
|
||||
),
|
||||
vec![Transfer {
|
||||
from: AccountKeyring::One.into(),
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Two.into(),
|
||||
amount: 69,
|
||||
amount: 69 * DOLLARS,
|
||||
nonce: 0,
|
||||
}],
|
||||
)
|
||||
@@ -167,14 +168,12 @@ fn finality_notification_check(
|
||||
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_native() {
|
||||
let mut storage = GenesisConfig::new(
|
||||
let mut storage = GenesisStorageBuilder::new(
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
1000,
|
||||
None,
|
||||
Default::default(),
|
||||
1000 * DOLLARS,
|
||||
)
|
||||
.genesis_map();
|
||||
.build_storage();
|
||||
let genesis_hash = insert_genesis_block(&mut storage);
|
||||
|
||||
let backend = InMemoryBackend::from((storage, StateVersion::default()));
|
||||
@@ -200,14 +199,12 @@ fn construct_genesis_should_work_with_native() {
|
||||
|
||||
#[test]
|
||||
fn construct_genesis_should_work_with_wasm() {
|
||||
let mut storage = GenesisConfig::new(
|
||||
let mut storage = GenesisStorageBuilder::new(
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
1000,
|
||||
None,
|
||||
Default::default(),
|
||||
1000 * DOLLARS,
|
||||
)
|
||||
.genesis_map();
|
||||
.build_storage();
|
||||
let genesis_hash = insert_genesis_block(&mut storage);
|
||||
|
||||
let backend = InMemoryBackend::from((storage, StateVersion::default()));
|
||||
@@ -231,39 +228,6 @@ fn construct_genesis_should_work_with_wasm() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn construct_genesis_with_bad_transaction_should_panic() {
|
||||
let mut storage = GenesisConfig::new(
|
||||
vec![Sr25519Keyring::One.public().into(), Sr25519Keyring::Two.public().into()],
|
||||
vec![AccountKeyring::One.into(), AccountKeyring::Two.into()],
|
||||
68,
|
||||
None,
|
||||
Default::default(),
|
||||
)
|
||||
.genesis_map();
|
||||
let genesis_hash = insert_genesis_block(&mut storage);
|
||||
|
||||
let backend = InMemoryBackend::from((storage, StateVersion::default()));
|
||||
let (b1data, _b1hash) = block1(genesis_hash, &backend);
|
||||
let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend);
|
||||
let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend");
|
||||
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
|
||||
let r = StateMachine::new(
|
||||
&backend,
|
||||
&mut overlay,
|
||||
&new_native_or_wasm_executor(),
|
||||
"Core_execute_block",
|
||||
&b1data,
|
||||
Default::default(),
|
||||
&runtime_code,
|
||||
CallContext::Onchain,
|
||||
)
|
||||
.execute(ExecutionStrategy::NativeElseWasm);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_initializes_from_genesis_ok() {
|
||||
let client = substrate_test_runtime_client::new();
|
||||
@@ -273,14 +237,14 @@ fn client_initializes_from_genesis_ok() {
|
||||
.runtime_api()
|
||||
.balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into())
|
||||
.unwrap(),
|
||||
1000
|
||||
1000 * DOLLARS
|
||||
);
|
||||
assert_eq!(
|
||||
client
|
||||
.runtime_api()
|
||||
.balance_of(client.chain_info().best_hash, AccountKeyring::Ferdie.into())
|
||||
.unwrap(),
|
||||
0
|
||||
0 * DOLLARS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -305,7 +269,7 @@ fn block_builder_works_with_transactions() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 42,
|
||||
amount: 42 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -340,42 +304,43 @@ fn block_builder_works_with_transactions() {
|
||||
.runtime_api()
|
||||
.balance_of(client.chain_info().best_hash, AccountKeyring::Alice.into())
|
||||
.unwrap(),
|
||||
958
|
||||
958 * DOLLARS
|
||||
);
|
||||
assert_eq!(
|
||||
client
|
||||
.runtime_api()
|
||||
.balance_of(client.chain_info().best_hash, AccountKeyring::Ferdie.into())
|
||||
.unwrap(),
|
||||
42
|
||||
42 * DOLLARS
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_builder_does_not_include_invalid() {
|
||||
let mut client = substrate_test_runtime_client::new();
|
||||
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
|
||||
builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 42,
|
||||
amount: 42 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert!(builder
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Eve.into(),
|
||||
to: AccountKeyring::Alice.into(),
|
||||
amount: 42,
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 30 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.is_err());
|
||||
|
||||
let block = builder.build().unwrap().block;
|
||||
//transfer from Eve should not be included
|
||||
assert_eq!(block.extrinsics.len(), 1);
|
||||
block_on(client.import(BlockOrigin::Own, block)).unwrap();
|
||||
|
||||
let hashof0 = client
|
||||
@@ -491,7 +456,7 @@ fn uncles_with_multiple_forks() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
amount: 41 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -523,7 +488,7 @@ fn uncles_with_multiple_forks() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 1,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -537,7 +502,7 @@ fn uncles_with_multiple_forks() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -646,7 +611,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
amount: 41 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -678,7 +643,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 1,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -692,7 +657,7 @@ fn finality_target_on_longest_chain_with_multiple_forks() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -868,7 +833,7 @@ fn finality_target_with_best_not_on_longest_chain() {
|
||||
.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 41,
|
||||
amount: 41 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -993,7 +958,7 @@ fn importing_diverged_finalized_block_should_trigger_reorg() {
|
||||
b1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1048,7 +1013,7 @@ fn finalizing_diverged_block_should_trigger_reorg() {
|
||||
b1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1166,7 +1131,7 @@ fn finality_notifications_content() {
|
||||
c1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 2,
|
||||
amount: 2 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1178,7 +1143,7 @@ fn finality_notifications_content() {
|
||||
d3.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 2,
|
||||
amount: 2 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1252,7 +1217,7 @@ fn state_reverted_on_reorg() {
|
||||
a1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
amount: 10,
|
||||
amount: 10 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1265,7 +1230,7 @@ fn state_reverted_on_reorg() {
|
||||
b1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 50,
|
||||
amount: 50 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1273,19 +1238,19 @@ fn state_reverted_on_reorg() {
|
||||
// Reorg to B1
|
||||
block_on(client.import_as_best(BlockOrigin::Own, b1.clone())).unwrap();
|
||||
|
||||
assert_eq!(950, current_balance(&client));
|
||||
assert_eq!(950 * DOLLARS, current_balance(&client));
|
||||
let mut a2 = client.new_block_at(a1.hash(), Default::default(), false).unwrap();
|
||||
a2.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Charlie.into(),
|
||||
amount: 10,
|
||||
amount: 10 * DOLLARS,
|
||||
nonce: 1,
|
||||
})
|
||||
.unwrap();
|
||||
let a2 = a2.build().unwrap().block;
|
||||
// Re-org to A2
|
||||
block_on(client.import_as_best(BlockOrigin::Own, a2)).unwrap();
|
||||
assert_eq!(980, current_balance(&client));
|
||||
assert_eq!(980 * DOLLARS, current_balance(&client));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1342,7 +1307,7 @@ fn doesnt_import_blocks_that_revert_finality() {
|
||||
b1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1386,7 +1351,7 @@ fn doesnt_import_blocks_that_revert_finality() {
|
||||
c1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 2,
|
||||
amount: 2 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1579,7 +1544,7 @@ fn returns_status_for_pruned_blocks() {
|
||||
b1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
@@ -1718,8 +1683,9 @@ fn storage_keys_prefix_and_start_key_works() {
|
||||
res,
|
||||
[
|
||||
child_root.clone(),
|
||||
array_bytes::hex2bytes_unchecked("3a636f6465"),
|
||||
array_bytes::hex2bytes_unchecked("3a686561707061676573"),
|
||||
array_bytes::hex2bytes_unchecked("3a636f6465"), //":code"
|
||||
array_bytes::hex2bytes_unchecked("3a65787472696e7369635f696e646578"), //":extrinsic_index"
|
||||
array_bytes::hex2bytes_unchecked("3a686561707061676573"), //":heappages"
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1732,7 +1698,13 @@ fn storage_keys_prefix_and_start_key_works() {
|
||||
.unwrap()
|
||||
.map(|x| x.0)
|
||||
.collect();
|
||||
assert_eq!(res, [array_bytes::hex2bytes_unchecked("3a686561707061676573")]);
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
array_bytes::hex2bytes_unchecked("3a65787472696e7369635f696e646578"),
|
||||
array_bytes::hex2bytes_unchecked("3a686561707061676573")
|
||||
]
|
||||
);
|
||||
|
||||
let res: Vec<_> = client
|
||||
.storage_keys(
|
||||
@@ -1762,54 +1734,32 @@ fn storage_keys_prefix_and_start_key_works() {
|
||||
|
||||
#[test]
|
||||
fn storage_keys_works() {
|
||||
sp_tracing::try_init_simple();
|
||||
|
||||
let expected_keys =
|
||||
substrate_test_runtime::storage_key_generator::get_expected_storage_hashed_keys();
|
||||
|
||||
let client = substrate_test_runtime_client::new();
|
||||
|
||||
let block_hash = client.info().best_hash;
|
||||
|
||||
let prefix = StorageKey(array_bytes::hex2bytes_unchecked(""));
|
||||
|
||||
let res: Vec<_> = client
|
||||
.storage_keys(block_hash, Some(&prefix), None)
|
||||
.unwrap()
|
||||
.take(9)
|
||||
.take(19)
|
||||
.map(|x| array_bytes::bytes2hex("", &x.0))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
"00c232cf4e70a5e343317016dc805bf80a6a8cd8ad39958d56f99891b07851e0",
|
||||
"085b2407916e53a86efeb8b72dbe338c4b341dab135252f96b6ed8022209b6cb",
|
||||
"0befda6e1ca4ef40219d588a727f1271",
|
||||
"1a560ecfd2a62c2b8521ef149d0804eb621050e3988ed97dca55f0d7c3e6aa34",
|
||||
"1d66850d32002979d67dd29dc583af5b2ae2a1f71c1f35ad90fff122be7a3824",
|
||||
"237498b98d8803334286e9f0483ef513098dd3c1c22ca21c4dc155b4ef6cc204",
|
||||
"26aa394eea5630e07c48ae0c9558cef75e0621c4869aa60c02be9adcc98a0d1d",
|
||||
"29b9db10ec5bf7907d8f74b5e60aa8140c4fbdd8127a1ee5600cb98e5ec01729",
|
||||
"3a636f6465",
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(res, expected_keys[0..19],);
|
||||
|
||||
// Starting at an empty key nothing gets skipped.
|
||||
let res: Vec<_> = client
|
||||
.storage_keys(block_hash, Some(&prefix), Some(&StorageKey("".into())))
|
||||
.unwrap()
|
||||
.take(9)
|
||||
.take(19)
|
||||
.map(|x| array_bytes::bytes2hex("", &x.0))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
"00c232cf4e70a5e343317016dc805bf80a6a8cd8ad39958d56f99891b07851e0",
|
||||
"085b2407916e53a86efeb8b72dbe338c4b341dab135252f96b6ed8022209b6cb",
|
||||
"0befda6e1ca4ef40219d588a727f1271",
|
||||
"1a560ecfd2a62c2b8521ef149d0804eb621050e3988ed97dca55f0d7c3e6aa34",
|
||||
"1d66850d32002979d67dd29dc583af5b2ae2a1f71c1f35ad90fff122be7a3824",
|
||||
"237498b98d8803334286e9f0483ef513098dd3c1c22ca21c4dc155b4ef6cc204",
|
||||
"26aa394eea5630e07c48ae0c9558cef75e0621c4869aa60c02be9adcc98a0d1d",
|
||||
"29b9db10ec5bf7907d8f74b5e60aa8140c4fbdd8127a1ee5600cb98e5ec01729",
|
||||
"3a636f6465",
|
||||
]
|
||||
);
|
||||
assert_eq!(res, expected_keys[0..19],);
|
||||
|
||||
// Starting at an incomplete key nothing gets skipped.
|
||||
let res: Vec<_> = client
|
||||
@@ -1824,16 +1774,12 @@ fn storage_keys_works() {
|
||||
.collect();
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
"3a636f6465",
|
||||
"3a686561707061676573",
|
||||
"52008686cc27f6e5ed83a216929942f8bcd32a396f09664a5698f81371934b56",
|
||||
"5348d72ac6cc66e5d8cbecc27b0e0677503b845fe2382d819f83001781788fd5",
|
||||
"5c2d5fda66373dabf970e4fb13d277ce91c5233473321129d32b5a8085fa8133",
|
||||
"6644b9b8bc315888ac8e41a7968dc2b4141a5403c58acdf70b7e8f7e07bf5081",
|
||||
"66484000ed3f75c95fc7b03f39c20ca1e1011e5999278247d3b2f5e3c3273808",
|
||||
"7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa",
|
||||
]
|
||||
expected_keys
|
||||
.iter()
|
||||
.filter(|&i| i > &"3a636f64".to_string())
|
||||
.take(8)
|
||||
.cloned()
|
||||
.collect::<Vec<String>>()
|
||||
);
|
||||
|
||||
// Starting at a complete key the first key is skipped.
|
||||
@@ -1849,38 +1795,33 @@ fn storage_keys_works() {
|
||||
.collect();
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
"3a686561707061676573",
|
||||
"52008686cc27f6e5ed83a216929942f8bcd32a396f09664a5698f81371934b56",
|
||||
"5348d72ac6cc66e5d8cbecc27b0e0677503b845fe2382d819f83001781788fd5",
|
||||
"5c2d5fda66373dabf970e4fb13d277ce91c5233473321129d32b5a8085fa8133",
|
||||
"6644b9b8bc315888ac8e41a7968dc2b4141a5403c58acdf70b7e8f7e07bf5081",
|
||||
"66484000ed3f75c95fc7b03f39c20ca1e1011e5999278247d3b2f5e3c3273808",
|
||||
"7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa",
|
||||
]
|
||||
expected_keys
|
||||
.iter()
|
||||
.filter(|&i| i > &"3a636f6465".to_string())
|
||||
.take(8)
|
||||
.cloned()
|
||||
.collect::<Vec<String>>()
|
||||
);
|
||||
|
||||
const SOME_BALANCE_KEY : &str = "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e2c1dc507e2035edbbd8776c440d870460c57f0008067cc01c5ff9eb2e2f9b3a94299a915a91198bd1021a6c55596f57";
|
||||
let res: Vec<_> = client
|
||||
.storage_keys(
|
||||
block_hash,
|
||||
Some(&prefix),
|
||||
Some(&StorageKey(array_bytes::hex2bytes_unchecked(
|
||||
"7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa",
|
||||
))),
|
||||
Some(&StorageKey(array_bytes::hex2bytes_unchecked(SOME_BALANCE_KEY))),
|
||||
)
|
||||
.unwrap()
|
||||
.take(5)
|
||||
.take(8)
|
||||
.map(|x| array_bytes::bytes2hex("", &x.0))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
res,
|
||||
[
|
||||
"811ecfaadcf5f2ee1d67393247e2f71a1662d433e8ce7ff89fb0d4aa9561820b",
|
||||
"a93d74caa7ec34ea1b04ce1e5c090245f867d333f0f88278a451e45299654dc5",
|
||||
"a9ee1403384afbfc13f13be91ff70bfac057436212e53b9733914382ac942892",
|
||||
"cf722c0832b5231d35e29f319ff27389f5032bfc7bfc3ba5ed7839f2042fb99f",
|
||||
"e3b47b6c84c0493481f97c5197d2554f",
|
||||
]
|
||||
expected_keys
|
||||
.iter()
|
||||
.filter(|&i| i > &SOME_BALANCE_KEY.to_string())
|
||||
.take(8)
|
||||
.cloned()
|
||||
.collect::<Vec<String>>()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1999,7 +1940,7 @@ fn reorg_triggers_a_notification_even_for_sources_that_should_not_trigger_notifi
|
||||
b1.push_transfer(Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Ferdie.into(),
|
||||
amount: 1,
|
||||
amount: 1 * DOLLARS,
|
||||
nonce: 0,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use codec::Encode;
|
||||
use futures::{
|
||||
executor::block_on,
|
||||
future::{ready, Ready},
|
||||
@@ -33,7 +33,7 @@ use sp_runtime::{
|
||||
ValidTransaction,
|
||||
},
|
||||
};
|
||||
use substrate_test_runtime::{AccountId, Block, Extrinsic, Transfer, H256};
|
||||
use substrate_test_runtime::{AccountId, Block, Extrinsic, ExtrinsicBuilder, TransferData, H256};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct TestApi {
|
||||
@@ -65,8 +65,10 @@ impl ChainApi for TestApi {
|
||||
_source: TransactionSource,
|
||||
uxt: <Self::Block as BlockT>::Extrinsic,
|
||||
) -> Self::ValidationFuture {
|
||||
let nonce = uxt.transfer().nonce;
|
||||
let from = uxt.transfer().from;
|
||||
let transfer = TransferData::try_from(&uxt)
|
||||
.expect("uxt is expected to be bench_call (carrying TransferData)");
|
||||
let nonce = transfer.nonce;
|
||||
let from = transfer.from;
|
||||
|
||||
match self.block_id_to_number(at) {
|
||||
Ok(Some(num)) if num > 5 => return ready(Ok(Err(InvalidTransaction::Stale.into()))),
|
||||
@@ -131,13 +133,8 @@ impl ChainApi for TestApi {
|
||||
}
|
||||
}
|
||||
|
||||
fn uxt(transfer: Transfer) -> Extrinsic {
|
||||
Extrinsic::Transfer {
|
||||
transfer,
|
||||
signature: Decode::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes())
|
||||
.expect("infinite input; no dead input space; qed"),
|
||||
exhaust_resources_when_not_first: false,
|
||||
}
|
||||
fn uxt(transfer: TransferData) -> Extrinsic {
|
||||
ExtrinsicBuilder::new_bench_call(transfer).build()
|
||||
}
|
||||
|
||||
fn bench_configured(pool: Pool<TestApi>, number: u64) {
|
||||
@@ -146,7 +143,7 @@ fn bench_configured(pool: Pool<TestApi>, number: u64) {
|
||||
let mut tags = Vec::new();
|
||||
|
||||
for nonce in 1..=number {
|
||||
let xt = uxt(Transfer {
|
||||
let xt = uxt(TransferData {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
|
||||
@@ -463,7 +463,8 @@ mod tests {
|
||||
use sc_transaction_pool_api::TransactionStatus;
|
||||
use sp_runtime::transaction_validity::TransactionSource;
|
||||
use std::{collections::HashMap, time::Instant};
|
||||
use substrate_test_runtime::{AccountId, Extrinsic, Transfer, H256};
|
||||
use substrate_test_runtime::{AccountId, ExtrinsicBuilder, Transfer, H256};
|
||||
use substrate_test_runtime_client::AccountKeyring::{Alice, Bob};
|
||||
|
||||
const SOURCE: TransactionSource = TransactionSource::External;
|
||||
|
||||
@@ -477,7 +478,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -494,7 +495,7 @@ mod tests {
|
||||
// given
|
||||
let pool = pool();
|
||||
let uxt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -520,8 +521,8 @@ mod tests {
|
||||
TestApi::default().into(),
|
||||
);
|
||||
|
||||
// after validation `IncludeData` will be set to non-propagable
|
||||
let uxt = Extrinsic::IncludeData(vec![42]);
|
||||
// after validation `IncludeData` will be set to non-propagable (validate_transaction mock)
|
||||
let uxt = ExtrinsicBuilder::new_include_data(vec![42]).build();
|
||||
|
||||
// when
|
||||
let res = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, uxt));
|
||||
@@ -542,7 +543,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -553,7 +554,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
@@ -565,7 +566,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 3,
|
||||
@@ -594,7 +595,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -605,7 +606,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
@@ -616,7 +617,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 3,
|
||||
@@ -645,7 +646,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -659,27 +660,27 @@ mod tests {
|
||||
// then
|
||||
assert!(pool.validated_pool.is_banned(&hash1));
|
||||
}
|
||||
use codec::Encode;
|
||||
|
||||
#[test]
|
||||
fn should_limit_futures() {
|
||||
sp_tracing::try_init_simple();
|
||||
|
||||
let xt = uxt(Transfer {
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
});
|
||||
|
||||
// given
|
||||
let limit = Limit { count: 100, total_bytes: 200 };
|
||||
let limit = Limit { count: 100, total_bytes: xt.encoded_size() };
|
||||
|
||||
let options = Options { ready: limit.clone(), future: limit.clone(), ..Default::default() };
|
||||
|
||||
let pool = Pool::new(options, true.into(), TestApi::default().into());
|
||||
|
||||
let hash1 = block_on(pool.submit_one(
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
}),
|
||||
))
|
||||
.unwrap();
|
||||
let hash1 = block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
|
||||
// when
|
||||
@@ -687,7 +688,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
from: Bob.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 10,
|
||||
@@ -715,7 +716,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
@@ -738,7 +739,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: INVALID_NONCE,
|
||||
@@ -763,7 +764,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -795,7 +796,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -828,7 +829,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
@@ -843,7 +844,7 @@ mod tests {
|
||||
&BlockId::Number(0),
|
||||
SOURCE,
|
||||
uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -863,7 +864,7 @@ mod tests {
|
||||
// given
|
||||
let pool = pool();
|
||||
let uxt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -887,7 +888,7 @@ mod tests {
|
||||
// given
|
||||
let pool = pool();
|
||||
let uxt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -918,7 +919,7 @@ mod tests {
|
||||
let pool = Pool::new(options, true.into(), TestApi::default().into());
|
||||
|
||||
let xt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -928,7 +929,7 @@ mod tests {
|
||||
|
||||
// when
|
||||
let xt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
from: Bob.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
amount: 4,
|
||||
nonce: 1,
|
||||
@@ -952,13 +953,17 @@ mod tests {
|
||||
|
||||
let pool = Pool::new(options, true.into(), TestApi::default().into());
|
||||
|
||||
let xt = Extrinsic::IncludeData(Vec::new());
|
||||
// after validation `IncludeData` will have priority set to 9001
|
||||
// (validate_transaction mock)
|
||||
let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build();
|
||||
block_on(pool.submit_one(&BlockId::Number(0), SOURCE, xt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// then
|
||||
// after validation `Transfer` will have priority set to 4 (validate_transaction
|
||||
// mock)
|
||||
let xt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
from: Bob.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
amount: 4,
|
||||
nonce: 1,
|
||||
@@ -977,12 +982,16 @@ mod tests {
|
||||
|
||||
let pool = Pool::new(options, true.into(), TestApi::default().into());
|
||||
|
||||
let xt = Extrinsic::IncludeData(Vec::new());
|
||||
// after validation `IncludeData` will have priority set to 9001
|
||||
// (validate_transaction mock)
|
||||
let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build();
|
||||
block_on(pool.submit_and_watch(&BlockId::Number(0), SOURCE, xt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
|
||||
// after validation `Transfer` will have priority set to 4 (validate_transaction
|
||||
// mock)
|
||||
let xt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
@@ -992,7 +1001,9 @@ mod tests {
|
||||
assert_eq!(pool.validated_pool().status().ready, 2);
|
||||
|
||||
// when
|
||||
let xt = Extrinsic::Store(Vec::new());
|
||||
// after validation `Store` will have priority set to 9001 (validate_transaction
|
||||
// mock)
|
||||
let xt = ExtrinsicBuilder::new_indexed_call(Vec::new()).build();
|
||||
block_on(pool.submit_one(&BlockId::Number(1), SOURCE, xt)).unwrap();
|
||||
assert_eq!(pool.validated_pool().status().ready, 2);
|
||||
|
||||
@@ -1014,7 +1025,7 @@ mod tests {
|
||||
|
||||
// when
|
||||
let xt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 1,
|
||||
@@ -1030,7 +1041,7 @@ mod tests {
|
||||
// But now before the previous one is imported we import
|
||||
// the one that it depends on.
|
||||
let xt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 4,
|
||||
nonce: 0,
|
||||
|
||||
@@ -362,6 +362,7 @@ mod tests {
|
||||
use sc_transaction_pool_api::TransactionSource;
|
||||
use sp_runtime::generic::BlockId;
|
||||
use substrate_test_runtime::{AccountId, Transfer, H256};
|
||||
use substrate_test_runtime_client::AccountKeyring::Alice;
|
||||
|
||||
#[test]
|
||||
fn revalidation_queue_works() {
|
||||
@@ -370,7 +371,7 @@ mod tests {
|
||||
let queue = Arc::new(RevalidationQueue::new(api.clone(), pool.clone()));
|
||||
|
||||
let uxt = uxt(Transfer {
|
||||
from: AccountId::from_h256(H256::from_low_u64_be(1)),
|
||||
from: Alice.into(),
|
||||
to: AccountId::from_h256(H256::from_low_u64_be(2)),
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
|
||||
@@ -31,7 +31,10 @@ use sp_runtime::{
|
||||
},
|
||||
};
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
use substrate_test_runtime::{Block, Extrinsic, Hashing, Transfer, H256};
|
||||
use substrate_test_runtime::{
|
||||
substrate_test_pallet::pallet::Call as PalletCall, BalancesCall, Block, Extrinsic,
|
||||
ExtrinsicBuilder, Hashing, RuntimeCall, Transfer, TransferData, H256,
|
||||
};
|
||||
|
||||
pub(crate) const INVALID_NONCE: u64 = 254;
|
||||
|
||||
@@ -70,9 +73,11 @@ impl ChainApi for TestApi {
|
||||
let block_number = self.block_id_to_number(at).unwrap().unwrap();
|
||||
|
||||
let res = match uxt {
|
||||
Extrinsic::Transfer { transfer, .. } => {
|
||||
let nonce = transfer.nonce;
|
||||
|
||||
Extrinsic {
|
||||
function: RuntimeCall::Balances(BalancesCall::transfer_allow_death { .. }),
|
||||
..
|
||||
} => {
|
||||
let TransferData { nonce, .. } = (&uxt).try_into().unwrap();
|
||||
// This is used to control the test flow.
|
||||
if nonce > 0 {
|
||||
let opt = self.delay.lock().take();
|
||||
@@ -115,14 +120,20 @@ impl ChainApi for TestApi {
|
||||
Ok(transaction)
|
||||
}
|
||||
},
|
||||
Extrinsic::IncludeData(_) => Ok(ValidTransaction {
|
||||
Extrinsic {
|
||||
function: RuntimeCall::SubstrateTest(PalletCall::include_data { .. }),
|
||||
..
|
||||
} => Ok(ValidTransaction {
|
||||
priority: 9001,
|
||||
requires: vec![],
|
||||
provides: vec![vec![42]],
|
||||
longevity: 9001,
|
||||
propagate: false,
|
||||
}),
|
||||
Extrinsic::Store(_) => Ok(ValidTransaction {
|
||||
Extrinsic {
|
||||
function: RuntimeCall::SubstrateTest(PalletCall::indexed_call { .. }),
|
||||
..
|
||||
} => Ok(ValidTransaction {
|
||||
priority: 9001,
|
||||
requires: vec![],
|
||||
provides: vec![vec![43]],
|
||||
@@ -185,8 +196,7 @@ impl ChainApi for TestApi {
|
||||
}
|
||||
|
||||
pub(crate) fn uxt(transfer: Transfer) -> Extrinsic {
|
||||
let signature = TryFrom::try_from(&[0; 64][..]).unwrap();
|
||||
Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false }
|
||||
ExtrinsicBuilder::new_transfer(transfer).build()
|
||||
}
|
||||
|
||||
pub(crate) fn pool() -> Pool<TestApi> {
|
||||
|
||||
@@ -35,11 +35,11 @@ use sp_consensus::BlockOrigin;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
traits::Block as _,
|
||||
transaction_validity::{InvalidTransaction, TransactionSource, ValidTransaction},
|
||||
transaction_validity::{TransactionSource, ValidTransaction},
|
||||
};
|
||||
use std::{collections::BTreeSet, pin::Pin, sync::Arc};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::{Block, Extrinsic, Hash, Header, Index, Transfer},
|
||||
runtime::{Block, Extrinsic, ExtrinsicBuilder, Hash, Header, Index, Transfer, TransferData},
|
||||
AccountKeyring::*,
|
||||
ClientBlockImportExt,
|
||||
};
|
||||
@@ -86,7 +86,11 @@ fn submission_should_work() {
|
||||
let pool = pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, vec![209]);
|
||||
}
|
||||
|
||||
@@ -96,16 +100,25 @@ fn multiple_submission_should_work() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, vec![209, 210]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn early_nonce_should_be_culled() {
|
||||
sp_tracing::try_init_simple();
|
||||
let pool = pool();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 208))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, Vec::<Index>::new());
|
||||
}
|
||||
|
||||
@@ -114,11 +127,19 @@ fn late_nonce_should_be_queued() {
|
||||
let pool = pool();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, Vec::<Index>::new());
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, vec![209, 210]);
|
||||
}
|
||||
|
||||
@@ -128,14 +149,22 @@ fn prune_tags_should_work() {
|
||||
let hash209 = block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 209))).unwrap();
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt(Alice, 210))).unwrap();
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, vec![209, 210]);
|
||||
|
||||
pool.validated_pool().api().push_block(1, Vec::new(), true);
|
||||
block_on(pool.prune_tags(&BlockId::number(1), vec![vec![209]], vec![hash209]))
|
||||
.expect("Prune tags");
|
||||
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, vec![210]);
|
||||
}
|
||||
|
||||
@@ -148,7 +177,11 @@ fn should_ban_invalid_transactions() {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, uxt.clone())).unwrap_err();
|
||||
|
||||
// when
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, Vec::<Index>::new());
|
||||
|
||||
// then
|
||||
@@ -197,7 +230,11 @@ fn should_correctly_prune_transactions_providing_more_than_one_tag() {
|
||||
block_on(pool.submit_one(&BlockId::number(2), SOURCE, xt.clone())).expect("2. Imported");
|
||||
assert_eq!(pool.validated_pool().status().ready, 1);
|
||||
assert_eq!(pool.validated_pool().status().future, 1);
|
||||
let pending: Vec<_> = pool.validated_pool().ready().map(|a| a.data.transfer().nonce).collect();
|
||||
let pending: Vec<_> = pool
|
||||
.validated_pool()
|
||||
.ready()
|
||||
.map(|a| TransferData::try_from(&a.data).unwrap().nonce)
|
||||
.collect();
|
||||
assert_eq!(pending, vec![211]);
|
||||
|
||||
// prune it and make sure the pool is empty
|
||||
@@ -472,6 +509,7 @@ fn finalization() {
|
||||
|
||||
#[test]
|
||||
fn fork_aware_finalization() {
|
||||
sp_tracing::try_init_simple();
|
||||
let api = TestApi::empty();
|
||||
// starting block A1 (last finalized.)
|
||||
let a_header = api.push_block(1, vec![], true);
|
||||
@@ -888,48 +926,6 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_accept_old_signatures() {
|
||||
let client = Arc::new(substrate_test_runtime_client::new());
|
||||
let best_hash = client.info().best_hash;
|
||||
let finalized_hash = client.info().finalized_hash;
|
||||
let pool = Arc::new(
|
||||
BasicPool::new_test(
|
||||
Arc::new(FullChainApi::new(client, None, &sp_core::testing::TaskExecutor::new())),
|
||||
best_hash,
|
||||
finalized_hash,
|
||||
)
|
||||
.0,
|
||||
);
|
||||
|
||||
let transfer = Transfer { from: Alice.into(), to: Bob.into(), nonce: 0, amount: 1 };
|
||||
let _bytes: sp_core::sr25519::Signature = transfer.using_encoded(|e| Alice.sign(e)).into();
|
||||
|
||||
// generated with schnorrkel 0.1.1 from `_bytes`
|
||||
let old_singature = sp_core::sr25519::Signature::try_from(
|
||||
&array_bytes::hex2bytes(
|
||||
"c427eb672e8c441c86d31f1a81b22b43102058e9ce237cabe9897ea5099ffd426\
|
||||
cd1c6a1f4f2869c3df57901d36bedcb295657adb3a4355add86ed234eb83108",
|
||||
)
|
||||
.expect("hex invalid")[..],
|
||||
)
|
||||
.expect("signature construction failed");
|
||||
|
||||
let xt = Extrinsic::Transfer {
|
||||
transfer,
|
||||
signature: old_singature,
|
||||
exhaust_resources_when_not_first: false,
|
||||
};
|
||||
|
||||
assert_matches::assert_matches!(
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.clone())),
|
||||
Err(error::Error::Pool(sc_transaction_pool_api::error::Error::InvalidTransaction(
|
||||
InvalidTransaction::BadProof
|
||||
))),
|
||||
"Should be invalid transaction with bad proof",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_notification_to_pool_maintain_works() {
|
||||
let mut client = Arc::new(substrate_test_runtime_client::new());
|
||||
@@ -975,7 +971,7 @@ fn import_notification_to_pool_maintain_works() {
|
||||
fn pruning_a_transaction_should_remove_it_from_best_transaction() {
|
||||
let (pool, api, _guard) = maintained_pool();
|
||||
|
||||
let xt1 = Extrinsic::IncludeData(Vec::new());
|
||||
let xt1 = ExtrinsicBuilder::new_include_data(Vec::new()).build();
|
||||
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt1.clone())).expect("1. Imported");
|
||||
assert_eq!(pool.status().ready, 1);
|
||||
@@ -1001,7 +997,7 @@ fn stale_transactions_are_pruned() {
|
||||
let (pool, api, _guard) = maintained_pool();
|
||||
|
||||
xts.into_iter().for_each(|xt| {
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.into_signed_tx()))
|
||||
block_on(pool.submit_one(&BlockId::number(0), SOURCE, xt.into_unchecked_extrinsic()))
|
||||
.expect("1. Imported");
|
||||
});
|
||||
assert_eq!(pool.status().ready, 0);
|
||||
@@ -1010,9 +1006,12 @@ fn stale_transactions_are_pruned() {
|
||||
// Almost the same as our initial transactions, but with some different `amount`s to make them
|
||||
// generate a different hash
|
||||
let xts = vec![
|
||||
Transfer { from: Alice.into(), to: Bob.into(), nonce: 1, amount: 2 }.into_signed_tx(),
|
||||
Transfer { from: Alice.into(), to: Bob.into(), nonce: 2, amount: 2 }.into_signed_tx(),
|
||||
Transfer { from: Alice.into(), to: Bob.into(), nonce: 3, amount: 2 }.into_signed_tx(),
|
||||
Transfer { from: Alice.into(), to: Bob.into(), nonce: 1, amount: 2 }
|
||||
.into_unchecked_extrinsic(),
|
||||
Transfer { from: Alice.into(), to: Bob.into(), nonce: 2, amount: 2 }
|
||||
.into_unchecked_extrinsic(),
|
||||
Transfer { from: Alice.into(), to: Bob.into(), nonce: 3, amount: 2 }
|
||||
.into_unchecked_extrinsic(),
|
||||
];
|
||||
|
||||
// Import block
|
||||
|
||||
@@ -60,55 +60,6 @@ fn calling_native_runtime_signature_changed_function() {
|
||||
assert_eq!(runtime_api.function_signature_changed(best_hash).unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_wasm_runtime_signature_changed_old_function() {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
|
||||
#[allow(deprecated)]
|
||||
let res = runtime_api.function_signature_changed_before_version_2(best_hash).unwrap();
|
||||
assert_eq!(&res, &[1, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_with_both_strategy_and_fail_on_wasm_should_return_error() {
|
||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
assert!(runtime_api.fail_on_wasm(best_hash).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_with_both_strategy_and_fail_on_native_should_work() {
|
||||
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
assert_eq!(runtime_api.fail_on_native(best_hash).unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_with_native_else_wasm_and_fail_on_wasm_should_work() {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::NativeElseWasm)
|
||||
.build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
assert_eq!(runtime_api.fail_on_wasm(best_hash).unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calling_with_native_else_wasm_and_fail_on_native_should_work() {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::NativeElseWasm)
|
||||
.build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let best_hash = client.chain_info().best_hash;
|
||||
assert_eq!(runtime_api.fail_on_native(best_hash).unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn use_trie_function() {
|
||||
let client = TestClientBuilder::new()
|
||||
@@ -162,7 +113,7 @@ fn record_proof_works() {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
}
|
||||
.into_signed_tx();
|
||||
.into_unchecked_extrinsic();
|
||||
|
||||
// Build the block and record proof
|
||||
let mut builder = client
|
||||
|
||||
@@ -35,6 +35,10 @@ sp-session = { version = "4.0.0-dev", default-features = false, path = "../../pr
|
||||
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" }
|
||||
sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" }
|
||||
pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" }
|
||||
pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../frame/balances" }
|
||||
pallet-root-testing = { version = "1.0.0-dev", default-features = false, path = "../../frame/root-testing" }
|
||||
pallet-sudo = { version = "4.0.0-dev", default-features = false, path = "../../frame/sudo" }
|
||||
frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../frame/executive" }
|
||||
frame-system = { version = "4.0.0-dev", default-features = false, path = "../../frame/system" }
|
||||
frame-system-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../frame/system/rpc/runtime-api" }
|
||||
pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../../frame/timestamp" }
|
||||
@@ -45,18 +49,20 @@ trie-db = { version = "0.27.0", default-features = false }
|
||||
sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" }
|
||||
sp-state-machine = { version = "0.13.0", default-features = false, path = "../../primitives/state-machine" }
|
||||
sp-externalities = { version = "0.13.0", default-features = false, path = "../../primitives/externalities" }
|
||||
sp-debug-derive = { path = "../../primitives/debug-derive" }
|
||||
|
||||
# 3rd party
|
||||
cfg-if = "1.0"
|
||||
array-bytes = { version = "6.1", optional = true }
|
||||
log = { version = "0.4.17", default-features = false }
|
||||
serde = { version = "1.0.136", optional = true, features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
futures = "0.3.21"
|
||||
sc-block-builder = { version = "0.10.0-dev", path = "../../client/block-builder" }
|
||||
sc-executor = { version = "0.10.0-dev", path = "../../client/executor" }
|
||||
sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" }
|
||||
substrate-test-runtime-client = { version = "2.0.0", path = "./client" }
|
||||
futures = "0.3.21"
|
||||
sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" }
|
||||
|
||||
[build-dependencies]
|
||||
substrate-wasm-builder = { version = "5.0.0-dev", path = "../../utils/wasm-builder", optional = true }
|
||||
@@ -66,7 +72,7 @@ default = [
|
||||
"std",
|
||||
]
|
||||
std = [
|
||||
"pallet-beefy-mmr/std",
|
||||
"array-bytes",
|
||||
"sp-application-crypto/std",
|
||||
"sp-consensus-aura/std",
|
||||
"sp-consensus-babe/std",
|
||||
@@ -93,9 +99,13 @@ std = [
|
||||
"sp-externalities/std",
|
||||
"sp-state-machine/std",
|
||||
"pallet-babe/std",
|
||||
"pallet-beefy-mmr/std",
|
||||
"pallet-timestamp/std",
|
||||
"pallet-balances/std",
|
||||
"pallet-sudo/std",
|
||||
"pallet-root-testing/std",
|
||||
"frame-system-rpc-runtime-api/std",
|
||||
"frame-system/std",
|
||||
"pallet-timestamp/std",
|
||||
"sc-service",
|
||||
"sp-consensus-grandpa/std",
|
||||
"sp-trie/std",
|
||||
|
||||
@@ -21,6 +21,7 @@ use sc_client_api::backend;
|
||||
use sp_api::{ApiExt, ProvideRuntimeApi};
|
||||
|
||||
use sc_block_builder::BlockBuilderApi;
|
||||
use substrate_test_runtime::*;
|
||||
|
||||
/// Extension trait for test block builder.
|
||||
pub trait BlockBuilderExt {
|
||||
@@ -29,12 +30,19 @@ pub trait BlockBuilderExt {
|
||||
&mut self,
|
||||
transfer: substrate_test_runtime::Transfer,
|
||||
) -> Result<(), sp_blockchain::Error>;
|
||||
/// Add storage change extrinsic to the block.
|
||||
|
||||
/// 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, B> BlockBuilderExt
|
||||
@@ -52,7 +60,7 @@ where
|
||||
&mut self,
|
||||
transfer: substrate_test_runtime::Transfer,
|
||||
) -> Result<(), sp_blockchain::Error> {
|
||||
self.push(transfer.into_signed_tx())
|
||||
self.push(transfer.into_unchecked_extrinsic())
|
||||
}
|
||||
|
||||
fn push_storage_change(
|
||||
@@ -60,6 +68,13 @@ where
|
||||
key: Vec<u8>,
|
||||
value: Option<Vec<u8>>,
|
||||
) -> Result<(), sp_blockchain::Error> {
|
||||
self.push(substrate_test_runtime::Extrinsic::StorageChange(key, value))
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,16 +30,9 @@ pub use substrate_test_runtime as runtime;
|
||||
|
||||
pub use self::block_builder_ext::BlockBuilderExt;
|
||||
|
||||
use sc_chain_spec::construct_genesis_block;
|
||||
use sp_api::StateVersion;
|
||||
use sp_core::{
|
||||
sr25519,
|
||||
storage::{ChildInfo, Storage, StorageChild},
|
||||
Pair,
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT};
|
||||
use sp_core::storage::{ChildInfo, Storage, StorageChild};
|
||||
use substrate_test_client::sc_executor::WasmExecutor;
|
||||
use substrate_test_runtime::genesismap::{additional_storage_with_genesis, GenesisConfig};
|
||||
use substrate_test_runtime::genesismap::GenesisStorageBuilder;
|
||||
|
||||
/// A prelude to import in tests.
|
||||
pub mod prelude {
|
||||
@@ -92,28 +85,6 @@ pub struct GenesisParameters {
|
||||
}
|
||||
|
||||
impl GenesisParameters {
|
||||
fn genesis_config(&self) -> GenesisConfig {
|
||||
GenesisConfig::new(
|
||||
vec![
|
||||
sr25519::Public::from(Sr25519Keyring::Alice).into(),
|
||||
sr25519::Public::from(Sr25519Keyring::Bob).into(),
|
||||
sr25519::Public::from(Sr25519Keyring::Charlie).into(),
|
||||
],
|
||||
(0..16_usize)
|
||||
.into_iter()
|
||||
.map(|i| AccountKeyring::numeric(i).public())
|
||||
.chain(vec![
|
||||
AccountKeyring::Alice.into(),
|
||||
AccountKeyring::Bob.into(),
|
||||
AccountKeyring::Charlie.into(),
|
||||
])
|
||||
.collect(),
|
||||
1000,
|
||||
self.heap_pages_override,
|
||||
self.extra_storage.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
/// 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);
|
||||
@@ -127,34 +98,11 @@ impl GenesisParameters {
|
||||
|
||||
impl GenesisInit for GenesisParameters {
|
||||
fn genesis_storage(&self) -> Storage {
|
||||
use codec::Encode;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
let child_roots = storage.children_default.values().map(|child_content| {
|
||||
let state_root =
|
||||
<<<runtime::Block as BlockT>::Header as HeaderT>::Hashing as HashT>::trie_root(
|
||||
child_content.data.clone().into_iter().collect(),
|
||||
sp_runtime::StateVersion::V1,
|
||||
);
|
||||
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(),
|
||||
sp_runtime::StateVersion::V1,
|
||||
);
|
||||
let block: runtime::Block = construct_genesis_block(state_root, StateVersion::V1);
|
||||
storage.top.extend(additional_storage_with_genesis(&block));
|
||||
|
||||
storage
|
||||
GenesisStorageBuilder::default()
|
||||
.with_heap_pages(self.heap_pages_override)
|
||||
.with_wasm_code(&self.wasm_code)
|
||||
.with_extra_storage(self.extra_storage.clone())
|
||||
.build_storage()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
// 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.
|
||||
|
||||
//! Provides utils for building the `Extrinsic` instances used with `substrate-test-runtime`.
|
||||
|
||||
use crate::{
|
||||
substrate_test_pallet::pallet::Call as PalletCall, AccountId, Balance, BalancesCall,
|
||||
CheckSubstrateCall, Extrinsic, Index, Pair, RuntimeCall, SignedPayload, TransferData,
|
||||
};
|
||||
use codec::Encode;
|
||||
use frame_system::{CheckNonce, CheckWeight};
|
||||
use sp_core::crypto::Pair as TraitPair;
|
||||
use sp_keyring::AccountKeyring;
|
||||
use sp_runtime::{transaction_validity::TransactionPriority, Perbill};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// Transfer used in test substrate pallet. Extrinsic is created and signed using this data.
|
||||
#[derive(Clone)]
|
||||
pub struct Transfer {
|
||||
/// Transfer sender and signer of created extrinsic
|
||||
pub from: Pair,
|
||||
/// The recipient of the transfer
|
||||
pub to: AccountId,
|
||||
/// Amount of transfer
|
||||
pub amount: Balance,
|
||||
/// Sender's account nonce at which transfer is valid
|
||||
pub nonce: u64,
|
||||
}
|
||||
|
||||
impl Transfer {
|
||||
/// Convert into a signed unchecked extrinsic.
|
||||
pub fn into_unchecked_extrinsic(self) -> Extrinsic {
|
||||
ExtrinsicBuilder::new_transfer(self).build()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TransferData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Bob.into(),
|
||||
amount: 0,
|
||||
nonce: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If feasible converts given `Extrinsic` to `TransferData`
|
||||
impl TryFrom<&Extrinsic> for TransferData {
|
||||
type Error = ();
|
||||
fn try_from(uxt: &Extrinsic) -> Result<Self, Self::Error> {
|
||||
match uxt {
|
||||
Extrinsic {
|
||||
function: RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }),
|
||||
signature: Some((from, _, (CheckNonce(nonce), ..))),
|
||||
} => Ok(TransferData { from: *from, to: *dest, amount: *value, nonce: *nonce }),
|
||||
Extrinsic {
|
||||
function: RuntimeCall::SubstrateTest(PalletCall::bench_call { transfer }),
|
||||
signature: None,
|
||||
} => Ok(transfer.clone()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates `Extrinsic`
|
||||
pub struct ExtrinsicBuilder {
|
||||
function: RuntimeCall,
|
||||
signer: Option<Pair>,
|
||||
nonce: Option<Index>,
|
||||
}
|
||||
|
||||
impl ExtrinsicBuilder {
|
||||
/// Create builder for given `RuntimeCall`. By default `Extrinsic` will be signed by `Alice`.
|
||||
pub fn new(function: impl Into<RuntimeCall>) -> Self {
|
||||
Self { function: function.into(), signer: Some(AccountKeyring::Alice.pair()), nonce: None }
|
||||
}
|
||||
|
||||
/// Create builder for given `RuntimeCall`. `Extrinsic` will be unsigned.
|
||||
pub fn new_unsigned(function: impl Into<RuntimeCall>) -> Self {
|
||||
Self { function: function.into(), signer: None, nonce: None }
|
||||
}
|
||||
|
||||
/// Create builder for `pallet_call::bench_transfer` from given `TransferData`.
|
||||
pub fn new_bench_call(transfer: TransferData) -> Self {
|
||||
Self::new_unsigned(PalletCall::bench_call { transfer })
|
||||
}
|
||||
|
||||
/// Create builder for given `Transfer`. Transfer `nonce` will be used as `Extrinsic` nonce.
|
||||
/// Transfer `from` will be used as Extrinsic signer.
|
||||
pub fn new_transfer(transfer: Transfer) -> Self {
|
||||
Self {
|
||||
nonce: Some(transfer.nonce),
|
||||
signer: Some(transfer.from.clone()),
|
||||
..Self::new(BalancesCall::transfer_allow_death {
|
||||
dest: transfer.to,
|
||||
value: transfer.amount,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::include_data` call using given parameters
|
||||
pub fn new_include_data(data: Vec<u8>) -> Self {
|
||||
Self::new(PalletCall::include_data { data })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::storage_change` call using given parameters. Will
|
||||
/// create unsigned Extrinsic.
|
||||
pub fn new_storage_change(key: Vec<u8>, value: Option<Vec<u8>>) -> Self {
|
||||
Self::new_unsigned(PalletCall::storage_change { key, value })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::offchain_index_set` call using given parameters
|
||||
pub fn new_offchain_index_set(key: Vec<u8>, value: Vec<u8>) -> Self {
|
||||
Self::new(PalletCall::offchain_index_set { key, value })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::offchain_index_clear` call using given parameters
|
||||
pub fn new_offchain_index_clear(key: Vec<u8>) -> Self {
|
||||
Self::new(PalletCall::offchain_index_clear { key })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::indexed_call` call using given parameters
|
||||
pub fn new_indexed_call(data: Vec<u8>) -> Self {
|
||||
Self::new(PalletCall::indexed_call { data })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::new_deposit_log_digest_item` call using given `log`
|
||||
pub fn new_deposit_log_digest_item(log: sp_runtime::generic::DigestItem) -> Self {
|
||||
Self::new_unsigned(PalletCall::deposit_log_digest_item { log })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::Call::new_deposit_log_digest_item`
|
||||
pub fn new_fill_block(ratio: Perbill) -> Self {
|
||||
Self::new(PalletCall::fill_block { ratio })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::call_do_not_propagate` call using given parameters
|
||||
pub fn new_call_do_not_propagate() -> Self {
|
||||
Self::new(PalletCall::call_do_not_propagate {})
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::call_with_priority` call using given parameters
|
||||
pub fn new_call_with_priority(priority: TransactionPriority) -> Self {
|
||||
Self::new(PalletCall::call_with_priority { priority })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::read` call using given parameters
|
||||
pub fn new_read(count: u32) -> Self {
|
||||
Self::new_unsigned(PalletCall::read { count })
|
||||
}
|
||||
|
||||
/// Create builder for `PalletCall::read` call using given parameters
|
||||
pub fn new_read_and_panic(count: u32) -> Self {
|
||||
Self::new_unsigned(PalletCall::read_and_panic { count })
|
||||
}
|
||||
|
||||
/// Unsigned `Extrinsic` will be created
|
||||
pub fn unsigned(mut self) -> Self {
|
||||
self.signer = None;
|
||||
self
|
||||
}
|
||||
|
||||
/// Given `nonce` will be set in `Extrinsic`
|
||||
pub fn nonce(mut self, nonce: Index) -> Self {
|
||||
self.nonce = Some(nonce);
|
||||
self
|
||||
}
|
||||
|
||||
/// Extrinsic will be signed by `signer`
|
||||
pub fn signer(mut self, signer: Pair) -> Self {
|
||||
self.signer = Some(signer);
|
||||
self
|
||||
}
|
||||
|
||||
/// Build `Extrinsic` using embedded parameters
|
||||
pub fn build(self) -> Extrinsic {
|
||||
if let Some(signer) = self.signer {
|
||||
let extra = (
|
||||
CheckNonce::from(self.nonce.unwrap_or(0)),
|
||||
CheckWeight::new(),
|
||||
CheckSubstrateCall {},
|
||||
);
|
||||
let raw_payload =
|
||||
SignedPayload::from_raw(self.function.clone(), extra.clone(), ((), (), ()));
|
||||
let signature = raw_payload.using_encoded(|e| signer.sign(e));
|
||||
|
||||
Extrinsic::new_signed(self.function, signer.public(), signature, extra)
|
||||
} else {
|
||||
Extrinsic::new_unsigned(self.function)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,75 +17,119 @@
|
||||
|
||||
//! Tool for creating the genesis block.
|
||||
|
||||
use super::{system, wasm_binary_unwrap, AccountId, AuthorityId, Runtime};
|
||||
use codec::{Encode, Joiner, KeyedVec};
|
||||
use frame_support::traits::GenesisBuild;
|
||||
use super::{
|
||||
currency, substrate_test_pallet, wasm_binary_unwrap, AccountId, AuthorityId, Balance,
|
||||
GenesisConfig,
|
||||
};
|
||||
use codec::Encode;
|
||||
use sc_service::construct_genesis_block;
|
||||
use sp_core::{
|
||||
map,
|
||||
sr25519,
|
||||
storage::{well_known_keys, StateVersion, Storage},
|
||||
Pair,
|
||||
};
|
||||
use sp_keyring::{AccountKeyring, Sr25519Keyring};
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, Hash as HashT, Header as HeaderT},
|
||||
BuildStorage,
|
||||
};
|
||||
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 {
|
||||
/// Builder for generating storage from substrate-test-runtime genesis config. Default storage can
|
||||
/// be extended with additional key-value pairs.
|
||||
pub struct GenesisStorageBuilder {
|
||||
authorities: Vec<AuthorityId>,
|
||||
balances: Vec<(AccountId, u64)>,
|
||||
heap_pages_override: Option<u64>,
|
||||
/// Additional storage key pairs that will be added to the genesis map.
|
||||
extra_storage: Storage,
|
||||
wasm_code: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl GenesisConfig {
|
||||
impl Default for GenesisStorageBuilder {
|
||||
/// Creates a builder with default settings for `substrate_test_runtime`.
|
||||
fn default() -> Self {
|
||||
Self::new(
|
||||
vec![
|
||||
sr25519::Public::from(Sr25519Keyring::Alice).into(),
|
||||
sr25519::Public::from(Sr25519Keyring::Bob).into(),
|
||||
sr25519::Public::from(Sr25519Keyring::Charlie).into(),
|
||||
],
|
||||
(0..16_usize)
|
||||
.into_iter()
|
||||
.map(|i| AccountKeyring::numeric(i).public())
|
||||
.chain(vec![
|
||||
AccountKeyring::Alice.into(),
|
||||
AccountKeyring::Bob.into(),
|
||||
AccountKeyring::Charlie.into(),
|
||||
])
|
||||
.collect(),
|
||||
1000 * currency::DOLLARS,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl GenesisStorageBuilder {
|
||||
/// Creates a storage builder for genesis config. `substrage test runtime` `GenesisConfig` is
|
||||
/// initialized with provided `authorities`, `endowed_accounts` with given balance. Key-pairs
|
||||
/// from `extra_storage` will be injected into built storage. `HEAP_PAGES` key and value will
|
||||
/// also be placed into storage.
|
||||
pub fn new(
|
||||
authorities: Vec<AuthorityId>,
|
||||
endowed_accounts: Vec<AccountId>,
|
||||
balance: u64,
|
||||
heap_pages_override: Option<u64>,
|
||||
extra_storage: Storage,
|
||||
balance: Balance,
|
||||
) -> Self {
|
||||
GenesisConfig {
|
||||
GenesisStorageBuilder {
|
||||
authorities,
|
||||
balances: endowed_accounts.into_iter().map(|a| (a, balance)).collect(),
|
||||
heap_pages_override,
|
||||
extra_storage,
|
||||
heap_pages_override: None,
|
||||
extra_storage: Default::default(),
|
||||
wasm_code: None,
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
})
|
||||
.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_u64))),
|
||||
),
|
||||
]
|
||||
.into_iter(),
|
||||
)
|
||||
.collect();
|
||||
map.insert(twox_128(&b"sys:auth"[..])[..].to_vec(), self.authorities.encode());
|
||||
// Add the extra storage entries.
|
||||
map.extend(self.extra_storage.top.clone().into_iter());
|
||||
/// Override default wasm code to be placed into GenesisConfig.
|
||||
pub fn with_wasm_code(mut self, wasm_code: &Option<Vec<u8>>) -> Self {
|
||||
self.wasm_code = wasm_code.clone();
|
||||
self
|
||||
}
|
||||
|
||||
// Assimilate the system genesis config.
|
||||
let mut storage =
|
||||
Storage { top: map, children_default: self.extra_storage.children_default.clone() };
|
||||
<system::GenesisConfig as GenesisBuild<Runtime>>::assimilate_storage(
|
||||
&system::GenesisConfig { authorities: self.authorities.clone() },
|
||||
&mut storage,
|
||||
)
|
||||
.expect("Adding `system::GensisConfig` to the genesis");
|
||||
pub fn with_heap_pages(mut self, heap_pages_override: Option<u64>) -> Self {
|
||||
self.heap_pages_override = heap_pages_override;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_extra_storage(mut self, storage: Storage) -> Self {
|
||||
self.extra_storage = storage;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds the `GenesisConfig` and returns its storage.
|
||||
pub fn build_storage(&mut self) -> Storage {
|
||||
let genesis_config = GenesisConfig {
|
||||
system: frame_system::GenesisConfig {
|
||||
code: self.wasm_code.clone().unwrap_or(wasm_binary_unwrap().to_vec()),
|
||||
},
|
||||
babe: pallet_babe::GenesisConfig {
|
||||
authorities: self.authorities.clone().into_iter().map(|x| (x, 1)).collect(),
|
||||
epoch_config: Some(crate::TEST_RUNTIME_BABE_EPOCH_CONFIGURATION),
|
||||
},
|
||||
substrate_test: substrate_test_pallet::GenesisConfig {
|
||||
authorities: self.authorities.clone(),
|
||||
},
|
||||
balances: pallet_balances::GenesisConfig { balances: self.balances.clone() },
|
||||
};
|
||||
|
||||
let mut storage = genesis_config
|
||||
.build_storage()
|
||||
.expect("Build storage from substrate-test-runtime GenesisConfig");
|
||||
|
||||
storage.top.insert(
|
||||
well_known_keys::HEAP_PAGES.into(),
|
||||
self.heap_pages_override.unwrap_or(16_u64).encode(),
|
||||
);
|
||||
|
||||
storage.top.extend(self.extra_storage.top.clone());
|
||||
storage.children_default.extend(self.extra_storage.children_default.clone());
|
||||
|
||||
storage
|
||||
}
|
||||
@@ -108,12 +152,6 @@ pub fn insert_genesis_block(storage: &mut Storage) -> sp_core::hash::H256 {
|
||||
);
|
||||
let block: crate::Block = construct_genesis_block(state_root, StateVersion::V1);
|
||||
let genesis_hash = block.header.hash();
|
||||
storage.top.extend(additional_storage_with_genesis(&block));
|
||||
|
||||
genesis_hash
|
||||
}
|
||||
|
||||
pub fn additional_storage_with_genesis(genesis_block: &crate::Block) -> BTreeMap<Vec<u8>, Vec<u8>> {
|
||||
map![
|
||||
twox_128(&b"latest"[..]).to_vec() => genesis_block.hash().as_fixed_bytes().to_vec()
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,244 @@
|
||||
// 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.
|
||||
|
||||
//! # substrate-test pallet
|
||||
//!
|
||||
//! Provides functionality used in unit-tests of numerous modules across substrate that require
|
||||
//! functioning runtime. Some calls are allowed to be submitted as unsigned extrinsics, however most
|
||||
//! of them requires signing. Refer to `pallet::Call` for further details.
|
||||
|
||||
use crate::AuthorityId;
|
||||
use frame_support::{pallet_prelude::*, storage};
|
||||
use sp_runtime::transaction_validity::{
|
||||
InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
pub use self::pallet::*;
|
||||
|
||||
const LOG_TARGET: &str = "substrate_test_pallet";
|
||||
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use crate::TransferData;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use sp_core::storage::well_known_keys;
|
||||
use sp_runtime::{transaction_validity::TransactionPriority, Perbill};
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::without_storage_info]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn authorities)]
|
||||
pub type Authorities<T> = StorageValue<_, Vec<AuthorityId>, ValueQuery>;
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[cfg_attr(feature = "std", derive(Default))]
|
||||
pub struct GenesisConfig {
|
||||
pub authorities: Vec<AuthorityId>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> GenesisBuild<T> for GenesisConfig {
|
||||
fn build(&self) {
|
||||
<Authorities<T>>::put(self.authorities.clone());
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Legacy call used in transaction pool benchmarks.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn bench_call(_origin: OriginFor<T>, _transfer: TransferData) -> DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Implicitly fill a block body with some data.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn include_data(origin: OriginFor<T>, _data: Vec<u8>) -> DispatchResult {
|
||||
frame_system::ensure_signed(origin)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Put/delete some data from storage. Intended to use as an unsigned extrinsic.
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn storage_change(
|
||||
_origin: OriginFor<T>,
|
||||
key: Vec<u8>,
|
||||
value: Option<Vec<u8>>,
|
||||
) -> DispatchResult {
|
||||
match value {
|
||||
Some(value) => storage::unhashed::put_raw(&key, &value),
|
||||
None => storage::unhashed::kill(&key),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write a key value pair to the offchain database.
|
||||
#[pallet::call_index(3)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn offchain_index_set(
|
||||
origin: OriginFor<T>,
|
||||
key: Vec<u8>,
|
||||
value: Vec<u8>,
|
||||
) -> DispatchResult {
|
||||
frame_system::ensure_signed(origin)?;
|
||||
sp_io::offchain_index::set(&key, &value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove a key and an associated value from the offchain database.
|
||||
#[pallet::call_index(4)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn offchain_index_clear(origin: OriginFor<T>, key: Vec<u8>) -> DispatchResult {
|
||||
frame_system::ensure_signed(origin)?;
|
||||
sp_io::offchain_index::clear(&key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create an index for this call.
|
||||
#[pallet::call_index(5)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn indexed_call(origin: OriginFor<T>, data: Vec<u8>) -> DispatchResult {
|
||||
frame_system::ensure_signed(origin)?;
|
||||
let content_hash = sp_io::hashing::blake2_256(&data);
|
||||
let extrinsic_index: u32 =
|
||||
storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap();
|
||||
sp_io::transaction_index::index(extrinsic_index, data.len() as u32, content_hash);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deposit given digest items into the system storage. They will be included in a header
|
||||
/// during finalization.
|
||||
#[pallet::call_index(6)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn deposit_log_digest_item(
|
||||
_origin: OriginFor<T>,
|
||||
log: sp_runtime::generic::DigestItem,
|
||||
) -> DispatchResult {
|
||||
<frame_system::Pallet<T>>::deposit_log(log);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This call is validated as `ValidTransaction` with given priority.
|
||||
#[pallet::call_index(7)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn call_with_priority(
|
||||
_origin: OriginFor<T>,
|
||||
_priority: TransactionPriority,
|
||||
) -> DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This call is validated as non-propagable `ValidTransaction`.
|
||||
#[pallet::call_index(8)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn call_do_not_propagate(_origin: OriginFor<T>) -> DispatchResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fill the block weight up to the given ratio.
|
||||
#[pallet::call_index(9)]
|
||||
#[pallet::weight(*_ratio * T::BlockWeights::get().max_block)]
|
||||
pub fn fill_block(origin: OriginFor<T>, _ratio: Perbill) -> DispatchResult {
|
||||
ensure_signed(origin)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read X times from the state some data.
|
||||
///
|
||||
/// Panics if it can not read `X` times.
|
||||
#[pallet::call_index(10)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn read(_origin: OriginFor<T>, count: u32) -> DispatchResult {
|
||||
Self::execute_read(count, false)
|
||||
}
|
||||
|
||||
/// Read X times from the state some data and then panic!
|
||||
///
|
||||
/// Returns `Ok` if it didn't read anything.
|
||||
#[pallet::call_index(11)]
|
||||
#[pallet::weight(100)]
|
||||
pub fn read_and_panic(_origin: OriginFor<T>, count: u32) -> DispatchResult {
|
||||
Self::execute_read(count, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
fn execute_read(read: u32, panic_at_end: bool) -> DispatchResult {
|
||||
let mut next_key = vec![];
|
||||
for _ in 0..(read as usize) {
|
||||
if let Some(next) = sp_io::storage::next_key(&next_key) {
|
||||
// Read the value
|
||||
sp_io::storage::get(&next);
|
||||
|
||||
next_key = next;
|
||||
} else {
|
||||
if panic_at_end {
|
||||
return Ok(())
|
||||
} else {
|
||||
panic!("Could not read {read} times from the state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if panic_at_end {
|
||||
panic!("BYE")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::validate_unsigned]
|
||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
||||
type Call = Call<T>;
|
||||
|
||||
fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity {
|
||||
log::trace!(target: LOG_TARGET, "validate_unsigned {call:?}");
|
||||
match call {
|
||||
// Some tests do not need to be complicated with signer and nonce, some need
|
||||
// reproducible block hash (call signature can't be there).
|
||||
// Offchain testing requires storage_change.
|
||||
Call::deposit_log_digest_item { .. } |
|
||||
Call::storage_change { .. } |
|
||||
Call::read { .. } |
|
||||
Call::read_and_panic { .. } => Ok(Default::default()),
|
||||
_ => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_runtime_call<T: pallet::Config>(call: &pallet::Call<T>) -> TransactionValidity {
|
||||
log::trace!(target: LOG_TARGET, "validate_runtime_call {call:?}");
|
||||
match call {
|
||||
Call::call_do_not_propagate {} =>
|
||||
Ok(ValidTransaction { propagate: false, ..Default::default() }),
|
||||
Call::call_with_priority { priority } =>
|
||||
Ok(ValidTransaction { priority: *priority, ..Default::default() }),
|
||||
_ => Ok(Default::default()),
|
||||
}
|
||||
}
|
||||
@@ -1,587 +0,0 @@
|
||||
// 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.
|
||||
|
||||
//! System manager: Handles all of the top-level stuff; executing block/transaction, setting code
|
||||
//! and depositing logs.
|
||||
|
||||
use crate::{
|
||||
AccountId, AuthorityId, Block, BlockNumber, Digest, Extrinsic, Header, Runtime, Transfer,
|
||||
H256 as Hash,
|
||||
};
|
||||
use codec::{Decode, Encode, KeyedVec};
|
||||
use frame_support::storage;
|
||||
use sp_core::storage::well_known_keys;
|
||||
use sp_io::{hashing::blake2_256, storage::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:";
|
||||
|
||||
pub use self::pallet::*;
|
||||
|
||||
#[frame_support::pallet]
|
||||
mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::without_storage_info]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
#[pallet::storage]
|
||||
pub type ExtrinsicData<T> = StorageMap<_, Blake2_128Concat, u32, Vec<u8>, ValueQuery>;
|
||||
|
||||
// The current block number being processed. Set by `execute_block`.
|
||||
#[pallet::storage]
|
||||
pub type Number<T> = StorageValue<_, BlockNumber, OptionQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
pub type ParentHash<T> = StorageValue<_, Hash, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
pub type NewAuthorities<T> = StorageValue<_, Vec<AuthorityId>, OptionQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
pub type StorageDigest<T> = StorageValue<_, Digest, OptionQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
pub type Authorities<T> = StorageValue<_, Vec<AuthorityId>, ValueQuery>;
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[cfg_attr(feature = "std", derive(Default))]
|
||||
pub struct GenesisConfig {
|
||||
pub authorities: Vec<AuthorityId>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> GenesisBuild<T> for GenesisConfig {
|
||||
fn build(&self) {
|
||||
<Authorities<T>>::put(self.authorities.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn balance_of_key(who: AccountId) -> Vec<u8> {
|
||||
who.to_keyed_vec(BALANCE_OF)
|
||||
}
|
||||
|
||||
pub fn balance_of(who: AccountId) -> u64 {
|
||||
storage::hashed::get_or(&blake2_256, &balance_of_key(who), 0)
|
||||
}
|
||||
|
||||
pub fn nonce_of(who: AccountId) -> u64 {
|
||||
storage::hashed::get_or(&blake2_256, &who.to_keyed_vec(NONCE_OF), 0)
|
||||
}
|
||||
|
||||
pub fn initialize_block(header: &Header) {
|
||||
// populate environment.
|
||||
<Number<Runtime>>::put(&header.number);
|
||||
<ParentHash<Runtime>>::put(&header.parent_hash);
|
||||
<StorageDigest<Runtime>>::put(header.digest());
|
||||
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32);
|
||||
|
||||
// try to read something that depends on current header digest
|
||||
// so that it'll be included in execution proof
|
||||
if let Some(generic::DigestItem::Other(v)) = header.digest().logs().iter().next() {
|
||||
let _: Option<u32> = storage::unhashed::get(v);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn authorities() -> Vec<AuthorityId> {
|
||||
<Authorities<Runtime>>::get()
|
||||
}
|
||||
|
||||
pub fn get_block_number() -> Option<BlockNumber> {
|
||||
<Number<Runtime>>::get()
|
||||
}
|
||||
|
||||
pub fn take_block_number() -> Option<BlockNumber> {
|
||||
<Number<Runtime>>::take()
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Mode {
|
||||
Verify,
|
||||
Overwrite,
|
||||
}
|
||||
|
||||
/// Actually execute all transitioning for `block`.
|
||||
pub fn polish_block(block: &mut Block) {
|
||||
execute_block_with_state_root_handler(block, Mode::Overwrite);
|
||||
}
|
||||
|
||||
pub fn execute_block(mut block: Block) -> Header {
|
||||
execute_block_with_state_root_handler(&mut block, Mode::Verify)
|
||||
}
|
||||
|
||||
fn execute_block_with_state_root_handler(block: &mut Block, mode: Mode) -> Header {
|
||||
let header = &mut block.header;
|
||||
|
||||
initialize_block(header);
|
||||
|
||||
// execute transactions
|
||||
block.extrinsics.iter().for_each(|e| {
|
||||
let _ = execute_transaction(e.clone()).unwrap_or_else(|_| panic!("Invalid transaction"));
|
||||
});
|
||||
|
||||
let new_header = finalize_block();
|
||||
|
||||
if let Mode::Overwrite = mode {
|
||||
header.state_root = new_header.state_root;
|
||||
} else {
|
||||
info_expect_equal_hash(&new_header.state_root, &header.state_root);
|
||||
assert_eq!(
|
||||
new_header.state_root, header.state_root,
|
||||
"Storage root must match that calculated.",
|
||||
);
|
||||
}
|
||||
|
||||
if let Mode::Overwrite = mode {
|
||||
header.extrinsics_root = new_header.extrinsics_root;
|
||||
} else {
|
||||
info_expect_equal_hash(&new_header.extrinsics_root, &header.extrinsics_root);
|
||||
assert_eq!(
|
||||
new_header.extrinsics_root, header.extrinsics_root,
|
||||
"Transaction trie root must be valid.",
|
||||
);
|
||||
}
|
||||
|
||||
new_header
|
||||
}
|
||||
|
||||
/// The block executor.
|
||||
pub struct BlockExecutor;
|
||||
|
||||
impl frame_support::traits::ExecuteBlock<Block> for BlockExecutor {
|
||||
fn execute_block(block: Block) {
|
||||
execute_block(block);
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute a transaction outside of the block execution function.
|
||||
/// 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()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
if tx.nonce > expected_nonce + 64 {
|
||||
return InvalidTransaction::Future.into()
|
||||
}
|
||||
|
||||
let encode = |from: &AccountId, nonce: u64| (from, nonce).encode();
|
||||
let requires = if tx.nonce != expected_nonce && tx.nonce > 0 {
|
||||
vec![encode(&tx.from, tx.nonce - 1)]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let provides = vec![encode(&tx.from, tx.nonce)];
|
||||
|
||||
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 result = execute_transaction_backend(&utx, extrinsic_index);
|
||||
<ExtrinsicData<Runtime>>::insert(extrinsic_index, utx.encode());
|
||||
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1));
|
||||
result
|
||||
}
|
||||
|
||||
/// Finalize the block.
|
||||
pub fn finalize_block() -> Header {
|
||||
use sp_core::storage::StateVersion;
|
||||
let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap();
|
||||
let txs: Vec<_> = (0..extrinsic_index).map(<ExtrinsicData<Runtime>>::take).collect();
|
||||
let extrinsics_root = trie::blake2_256_ordered_root(txs, StateVersion::V0);
|
||||
let number = <Number<Runtime>>::take().expect("Number is set by `initialize_block`");
|
||||
let parent_hash = <ParentHash<Runtime>>::take();
|
||||
let mut digest =
|
||||
<StorageDigest<Runtime>>::take().expect("StorageDigest is set by `initialize_block`");
|
||||
|
||||
let o_new_authorities = <NewAuthorities<Runtime>>::take();
|
||||
|
||||
// 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(StateVersion::V1)[..])
|
||||
.expect("`storage_root` is a valid hash");
|
||||
|
||||
if let Some(new_authorities) = o_new_authorities {
|
||||
digest.push(generic::DigestItem::Consensus(*b"aura", new_authorities.encode()));
|
||||
digest.push(generic::DigestItem::Consensus(*b"babe", new_authorities.encode()));
|
||||
}
|
||||
|
||||
Header { number, extrinsics_root, state_root: storage_root, parent_hash, digest }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_signature(utx: &Extrinsic) -> Result<(), TransactionValidityError> {
|
||||
use sp_runtime::traits::BlindCheckable;
|
||||
utx.clone().check().map_err(|_| InvalidTransaction::BadProof.into()).map(|_| ())
|
||||
}
|
||||
|
||||
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 =>
|
||||
Err(InvalidTransaction::ExhaustsResources.into()),
|
||||
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)),
|
||||
Extrinsic::OffchainIndexSet(key, value) => {
|
||||
sp_io::offchain_index::set(key, value);
|
||||
Ok(Ok(()))
|
||||
},
|
||||
Extrinsic::OffchainIndexClear(key) => {
|
||||
sp_io::offchain_index::clear(key);
|
||||
Ok(Ok(()))
|
||||
},
|
||||
Extrinsic::Store(data) => execute_store(data.clone()),
|
||||
Extrinsic::ReadAndPanic(i) => execute_read(*i, true),
|
||||
Extrinsic::Read(i) => execute_read(*i, false),
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_read(read: u32, panic_at_end: bool) -> ApplyExtrinsicResult {
|
||||
let mut next_key = vec![];
|
||||
for _ in 0..(read as usize) {
|
||||
if let Some(next) = sp_io::storage::next_key(&next_key) {
|
||||
// Read the value
|
||||
sp_io::storage::get(&next);
|
||||
|
||||
next_key = next;
|
||||
} else {
|
||||
if panic_at_end {
|
||||
return Ok(Ok(()))
|
||||
} else {
|
||||
panic!("Could not read {read} times from the state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if panic_at_end {
|
||||
panic!("BYE")
|
||||
} else {
|
||||
Ok(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_transfer_backend(tx: &Transfer) -> ApplyExtrinsicResult {
|
||||
// check nonce
|
||||
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())
|
||||
}
|
||||
|
||||
// increment nonce in storage
|
||||
storage::hashed::put(&blake2_256, &nonce_key, &(expected_nonce + 1));
|
||||
|
||||
// check sender balance
|
||||
let from_balance_key = tx.from.to_keyed_vec(BALANCE_OF);
|
||||
let from_balance: u64 = storage::hashed::get_or(&blake2_256, &from_balance_key, 0);
|
||||
|
||||
// enact transfer
|
||||
if tx.amount > from_balance {
|
||||
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);
|
||||
storage::hashed::put(&blake2_256, &from_balance_key, &(from_balance - tx.amount));
|
||||
storage::hashed::put(&blake2_256, &to_balance_key, &(to_balance + tx.amount));
|
||||
Ok(Ok(()))
|
||||
}
|
||||
|
||||
fn execute_store(data: Vec<u8>) -> ApplyExtrinsicResult {
|
||||
let content_hash = sp_io::hashing::blake2_256(&data);
|
||||
let extrinsic_index: u32 = storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap();
|
||||
sp_io::transaction_index::index(extrinsic_index, data.len() as u32, content_hash);
|
||||
Ok(Ok(()))
|
||||
}
|
||||
|
||||
fn execute_new_authorities_backend(new_authorities: &[AuthorityId]) -> ApplyExtrinsicResult {
|
||||
<NewAuthorities<Runtime>>::put(new_authorities.to_vec());
|
||||
Ok(Ok(()))
|
||||
}
|
||||
|
||||
fn execute_storage_change(key: &[u8], value: Option<&[u8]>) -> ApplyExtrinsicResult {
|
||||
match value {
|
||||
Some(value) => storage::unhashed::put_raw(key, value),
|
||||
None => storage::unhashed::kill(key),
|
||||
}
|
||||
Ok(Ok(()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
|
||||
use sp_core::hexdisplay::HexDisplay;
|
||||
if given != expected {
|
||||
println!(
|
||||
"Hash: given={}, expected={}",
|
||||
HexDisplay::from(given.as_fixed_bytes()),
|
||||
HexDisplay::from(expected.as_fixed_bytes()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
|
||||
if given != expected {
|
||||
sp_runtime::print("Hash not equal");
|
||||
sp_runtime::print(given.as_bytes());
|
||||
sp_runtime::print(expected.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::{wasm_binary_unwrap, Header, Transfer};
|
||||
use sc_executor::{NativeElseWasmExecutor, WasmExecutor};
|
||||
use sp_core::{
|
||||
map,
|
||||
traits::{CallContext, CodeExecutor, RuntimeCode},
|
||||
};
|
||||
use sp_io::{hashing::twox_128, TestExternalities};
|
||||
use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring};
|
||||
|
||||
// Declare an instance of the native executor dispatch for the test runtime.
|
||||
pub struct NativeDispatch;
|
||||
|
||||
impl sc_executor::NativeExecutionDispatch for NativeDispatch {
|
||||
type ExtendHostFunctions = ();
|
||||
|
||||
fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
|
||||
crate::api::dispatch(method, data)
|
||||
}
|
||||
|
||||
fn native_version() -> sc_executor::NativeVersion {
|
||||
crate::native_version()
|
||||
}
|
||||
}
|
||||
|
||||
fn executor() -> NativeElseWasmExecutor<NativeDispatch> {
|
||||
NativeElseWasmExecutor::new_with_wasm_executor(WasmExecutor::builder().build())
|
||||
}
|
||||
|
||||
fn new_test_ext() -> TestExternalities {
|
||||
let authorities = vec![
|
||||
Sr25519Keyring::Alice.to_raw_public(),
|
||||
Sr25519Keyring::Bob.to_raw_public(),
|
||||
Sr25519Keyring::Charlie.to_raw_public(),
|
||||
];
|
||||
|
||||
TestExternalities::new_with_code(
|
||||
wasm_binary_unwrap(),
|
||||
sp_core::storage::Storage {
|
||||
top: map![
|
||||
twox_128(b"latest").to_vec() => vec![69u8; 32],
|
||||
twox_128(b"sys:auth").to_vec() => authorities.encode(),
|
||||
blake2_256(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => {
|
||||
vec![111u8, 0, 0, 0, 0, 0, 0, 0]
|
||||
},
|
||||
],
|
||||
children_default: map![],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn block_import_works<F>(block_executor: F)
|
||||
where
|
||||
F: Fn(Block, &mut TestExternalities),
|
||||
{
|
||||
let h = Header {
|
||||
parent_hash: [69u8; 32].into(),
|
||||
number: 1,
|
||||
state_root: Default::default(),
|
||||
extrinsics_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
};
|
||||
let mut b = Block { header: h, extrinsics: vec![] };
|
||||
|
||||
new_test_ext().execute_with(|| polish_block(&mut b));
|
||||
|
||||
block_executor(b, &mut new_test_ext());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_import_works_native() {
|
||||
block_import_works(|b, ext| {
|
||||
ext.execute_with(|| {
|
||||
execute_block(b);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_import_works_wasm() {
|
||||
block_import_works(|b, ext| {
|
||||
let mut ext = ext.ext();
|
||||
let runtime_code = RuntimeCode {
|
||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(wasm_binary_unwrap().into()),
|
||||
hash: Vec::new(),
|
||||
heap_pages: None,
|
||||
};
|
||||
|
||||
executor()
|
||||
.call(
|
||||
&mut ext,
|
||||
&runtime_code,
|
||||
"Core_execute_block",
|
||||
&b.encode(),
|
||||
false,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
fn block_import_with_transaction_works<F>(block_executor: F)
|
||||
where
|
||||
F: Fn(Block, &mut TestExternalities),
|
||||
{
|
||||
let mut b1 = Block {
|
||||
header: Header {
|
||||
parent_hash: [69u8; 32].into(),
|
||||
number: 1,
|
||||
state_root: Default::default(),
|
||||
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()],
|
||||
};
|
||||
|
||||
let mut dummy_ext = new_test_ext();
|
||||
dummy_ext.execute_with(|| polish_block(&mut b1));
|
||||
|
||||
let mut b2 = Block {
|
||||
header: Header {
|
||||
parent_hash: b1.header.hash(),
|
||||
number: 2,
|
||||
state_root: Default::default(),
|
||||
extrinsics_root: Default::default(),
|
||||
digest: Default::default(),
|
||||
},
|
||||
extrinsics: vec![
|
||||
Transfer {
|
||||
from: AccountKeyring::Bob.into(),
|
||||
to: AccountKeyring::Alice.into(),
|
||||
amount: 27,
|
||||
nonce: 0,
|
||||
}
|
||||
.into_signed_tx(),
|
||||
Transfer {
|
||||
from: AccountKeyring::Alice.into(),
|
||||
to: AccountKeyring::Charlie.into(),
|
||||
amount: 69,
|
||||
nonce: 1,
|
||||
}
|
||||
.into_signed_tx(),
|
||||
],
|
||||
};
|
||||
|
||||
dummy_ext.execute_with(|| polish_block(&mut b2));
|
||||
drop(dummy_ext);
|
||||
|
||||
let mut t = new_test_ext();
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(balance_of(AccountKeyring::Alice.into()), 111);
|
||||
assert_eq!(balance_of(AccountKeyring::Bob.into()), 0);
|
||||
});
|
||||
|
||||
block_executor(b1, &mut t);
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(balance_of(AccountKeyring::Alice.into()), 42);
|
||||
assert_eq!(balance_of(AccountKeyring::Bob.into()), 69);
|
||||
});
|
||||
|
||||
block_executor(b2, &mut t);
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(balance_of(AccountKeyring::Alice.into()), 0);
|
||||
assert_eq!(balance_of(AccountKeyring::Bob.into()), 42);
|
||||
assert_eq!(balance_of(AccountKeyring::Charlie.into()), 69);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_import_with_transaction_works_native() {
|
||||
block_import_with_transaction_works(|b, ext| {
|
||||
ext.execute_with(|| {
|
||||
execute_block(b);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_import_with_transaction_works_wasm() {
|
||||
block_import_with_transaction_works(|b, ext| {
|
||||
let mut ext = ext.ext();
|
||||
let runtime_code = RuntimeCode {
|
||||
code_fetcher: &sp_core::traits::WrappedRuntimeCode(wasm_binary_unwrap().into()),
|
||||
hash: Vec::new(),
|
||||
heap_pages: None,
|
||||
};
|
||||
|
||||
executor()
|
||||
.call(
|
||||
&mut ext,
|
||||
&runtime_code,
|
||||
"Core_execute_block",
|
||||
&b.encode(),
|
||||
false,
|
||||
CallContext::Offchain,
|
||||
)
|
||||
.0
|
||||
.unwrap();
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,10 @@ use sp_runtime::{
|
||||
};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use substrate_test_runtime_client::{
|
||||
runtime::{AccountId, Block, BlockNumber, Extrinsic, Hash, Header, Index, Transfer},
|
||||
runtime::{
|
||||
AccountId, Block, BlockNumber, Extrinsic, ExtrinsicBuilder, Hash, Header, Index, Transfer,
|
||||
TransferData,
|
||||
},
|
||||
AccountKeyring::{self, *},
|
||||
};
|
||||
|
||||
@@ -276,7 +279,7 @@ impl sc_transaction_pool::ChainApi for TestApi {
|
||||
Err(e) => return ready(Err(e)),
|
||||
}
|
||||
|
||||
let (requires, provides) = if let Some(transfer) = uxt.try_transfer() {
|
||||
let (requires, provides) = if let Ok(transfer) = TransferData::try_from(&uxt) {
|
||||
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]] };
|
||||
@@ -377,6 +380,5 @@ impl sp_blockchain::HeaderMetadata<Block> for TestApi {
|
||||
pub fn uxt(who: AccountKeyring, nonce: Index) -> Extrinsic {
|
||||
let dummy = codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap();
|
||||
let transfer = Transfer { from: who.into(), to: dummy, nonce, amount: 1 };
|
||||
let signature = transfer.using_encoded(|e| who.sign(e));
|
||||
Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first: false }
|
||||
ExtrinsicBuilder::new_transfer(transfer).build()
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce,
|
||||
};
|
||||
t.into_signed_tx()
|
||||
t.into_unchecked_extrinsic()
|
||||
};
|
||||
// Populate the pool
|
||||
let ext0 = new_transaction(0);
|
||||
@@ -297,7 +297,7 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 0,
|
||||
}
|
||||
.into_signed_tx();
|
||||
.into_unchecked_extrinsic();
|
||||
|
||||
// when
|
||||
let bytes = accounts.dry_run(tx.encode().into(), None).await.expect("Call is successful");
|
||||
@@ -325,13 +325,13 @@ mod tests {
|
||||
amount: 5,
|
||||
nonce: 100,
|
||||
}
|
||||
.into_signed_tx();
|
||||
.into_unchecked_extrinsic();
|
||||
|
||||
// when
|
||||
let bytes = accounts.dry_run(tx.encode().into(), None).await.expect("Call is successful");
|
||||
|
||||
// then
|
||||
let apply_res: ApplyExtrinsicResult = Decode::decode(&mut bytes.as_ref()).unwrap();
|
||||
assert_eq!(apply_res, Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)));
|
||||
assert_eq!(apply_res, Err(TransactionValidityError::Invalid(InvalidTransaction::Future)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user