diff --git a/Cargo.lock b/Cargo.lock index e65562a56b5fa..3f1fd0bd5802e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 795288d0a1da8..642900d2f35d8 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -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(header: B::Header) -> ChainEvent @@ -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, 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::>(); let block_limit = genesis_header.encoded_size() + @@ -862,7 +872,7 @@ mod tests { .sum::() + Vec::::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" diff --git a/client/basic-authorship/src/lib.rs b/client/basic-authorship/src/lib.rs index 23a2120ac6204..8f47c2ea00e6b 100644 --- a/client/basic-authorship/src/lib.rs +++ b/client/basic-authorship/src/lib.rs @@ -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}; diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index 21f8e6fdd3999..f055d4688822a 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -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::( - block.storage_changes.transaction_storage_root, - proof, - ) - .unwrap(); + let backend = + sp_state_machine::create_proof_check_backend::(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(); diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index aa3e32fa09d0a..59b4076e2fd01 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -71,15 +71,12 @@ const SLOT_DURATION_MS: u64 = 1000; struct DummyFactory { client: Arc, epoch_changes: SharedEpochChanges, - config: BabeConfiguration, mutator: Mutator, } struct DummyProposer { factory: DummyFactory, parent_hash: Hash, - parent_number: u64, - parent_slot: Slot, } impl Environment for DummyFactory { @@ -88,15 +85,9 @@ impl Environment for DummyFactory { type Error = Error; fn init(&mut self, parent_header: &::Header) -> Self::CreateProposer { - let parent_slot = crate::find_pre_digest::(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::(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(|_, _| ()), }; diff --git a/client/consensus/beefy/src/tests.rs b/client/consensus/beefy/src/tests.rs index 48ecebdac3581..288a9fde5b817 100644 --- a/client/consensus/beefy/src/tests.rs +++ b/client/consensus/beefy/src/tests.rs @@ -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 = 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::::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::::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::::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::::AuthoritiesChange(new_auth_set).encode(), + )) + .unwrap(); } pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { diff --git a/client/consensus/grandpa/src/tests.rs b/client/consensus/grandpa/src/tests.rs index 7a3f862d3602b..c46e249be485c 100644 --- a/client/consensus/grandpa/src/tests.rs +++ b/client/consensus/grandpa/src/tests.rs @@ -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) { - 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) { + 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, ) { - 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, diff --git a/client/consensus/grandpa/src/warp_proof.rs b/client/consensus/grandpa/src/warp_proof.rs index cd4fedf96b4c4..ec2d25c328bf8 100644 --- a/client/consensus/grandpa/src/warp_proof.rs +++ b/client/consensus/grandpa/src/warp_proof.rs @@ -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 { diff --git a/client/network/bitswap/src/lib.rs b/client/network/bitswap/src/lib.rs index 5a7a7b51355c6..db73023bd3769 100644 --- a/client/network/bitswap/src/lib.rs +++ b/client/network/bitswap/src/lib.rs @@ -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(), ) diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index f85d6ed63c247..9e740d0856cfb 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -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, - ) -> Vec { - 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 diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index af46d15a2bacd..81707445dc9d3 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -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 }); diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 677d89267e3a6..f46fb637a92d3 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -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(); diff --git a/client/rpc-spec-v2/src/chain_head/tests.rs b/client/rpc-spec-v2/src/chain_head/tests.rs index 76644ccb472e8..d3d4fc649e3fe 100644 --- a/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/client/rpc-spec-v2/src/chain_head/tests.rs @@ -184,12 +184,13 @@ async fn follow_with_runtime() { // Initialized must always be reported first. let event: FollowEvent = 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 = diff --git a/client/rpc/src/author/tests.rs b/client/rpc/src/author/tests.rs index fbbd1a92fdaa7..1f688e8e85e05 100644 --- a/client/rpc/src/author/tests.rs +++ b/client/rpc/src/author/tests.rs @@ -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, 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::>()) @@ -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, diff --git a/client/rpc/src/dev/tests.rs b/client/rpc/src/dev/tests.rs index 9beb01182585a..db6a9a119da0a 100644 --- a/client/rpc/src/dev/tests.rs +++ b/client/rpc/src/dev/tests.rs @@ -28,6 +28,22 @@ async fn block_stats_work() { let api = >::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::>(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, }), ); diff --git a/client/rpc/src/state/tests.rs b/client/rpc/src/state/tests.rs index ae193e662b0e7..9e00a04abe386 100644 --- a/client/rpc/src/state/tests.rs +++ b/client/rpc/src/state/tests.rs @@ -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::>(); 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) { 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(); diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index a5667717055b5..b90eb71c1ea75 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -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()); } } diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 520a9b52feab0..a33bce50aa40f 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -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, ) -> (Vec, Hash) { - let transactions = txs.into_iter().map(|tx| tx.into_signed_tx()).collect::>(); + let transactions = txs.into_iter().map(|tx| tx.into_unchecked_extrinsic()).collect::>(); let iter = transactions.iter().map(Encode::encode); let extrinsics_root = LayoutV0::::ordered_trie_root(iter).into(); @@ -137,9 +138,9 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> (Vec = client .storage_keys( @@ -1762,54 +1734,32 @@ fn storage_keys_prefix_and_start_key_works() { #[test] fn storage_keys_works() { - let client = substrate_test_runtime_client::new(); + sp_tracing::try_init_simple(); - let block_hash = client.info().best_hash; + 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::>() ); // 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::>() ); + 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::>() ); } @@ -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(); diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index f7739ef73a971..d114acc343d50 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -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: ::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, number: u64) { @@ -146,7 +143,7 @@ fn bench_configured(pool: Pool, 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, diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 54534df820227..4d34737a7ba70 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -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, diff --git a/client/transaction-pool/src/revalidation.rs b/client/transaction-pool/src/revalidation.rs index bd8f3dd6498f3..b2c41be92eea3 100644 --- a/client/transaction-pool/src/revalidation.rs +++ b/client/transaction-pool/src/revalidation.rs @@ -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, diff --git a/client/transaction-pool/src/tests.rs b/client/transaction-pool/src/tests.rs index 3945c88d49c0a..62911d5cbb471 100644 --- a/client/transaction-pool/src/tests.rs +++ b/client/transaction-pool/src/tests.rs @@ -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 { diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 284c777a683db..ac029d71700da 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -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::::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::::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::::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 diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 956a6a25f1558..a591bc0b77938 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -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 diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 68267e91d62cf..2bcdafed96123 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -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", diff --git a/test-utils/runtime/client/src/block_builder_ext.rs b/test-utils/runtime/client/src/block_builder_ext.rs index 3c5e1122f0613..a9b0d49f3543e 100644 --- a/test-utils/runtime/client/src/block_builder_ext.rs +++ b/test-utils/runtime/client/src/block_builder_ext.rs @@ -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, value: Option>, ) -> 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, value: Option>, ) -> 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()) } } diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index 5e4b5d6a12dd9..b2c1e8f47b1af 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -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) { 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 = - <<::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 = - <<::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() } } diff --git a/test-utils/runtime/src/extrinsic.rs b/test-utils/runtime/src/extrinsic.rs new file mode 100644 index 0000000000000..a6e13226face0 --- /dev/null +++ b/test-utils/runtime/src/extrinsic.rs @@ -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 { + 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, + nonce: Option, +} + +impl ExtrinsicBuilder { + /// Create builder for given `RuntimeCall`. By default `Extrinsic` will be signed by `Alice`. + pub fn new(function: impl Into) -> 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) -> 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) -> 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, value: Option>) -> 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, value: Vec) -> 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) -> 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) -> 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) + } + } +} diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 9e00dd29999f8..62ce26c55e38b 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -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, balances: Vec<(AccountId, u64)>, heap_pages_override: Option, /// Additional storage key pairs that will be added to the genesis map. extra_storage: Storage, + wasm_code: Option>, +} + +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 GenesisConfig { +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, endowed_accounts: Vec, - balance: u64, - heap_pages_override: Option, - 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> = 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()); - - // Assimilate the system genesis config. - let mut storage = - Storage { top: map, children_default: self.extra_storage.children_default.clone() }; - >::assimilate_storage( - &system::GenesisConfig { authorities: self.authorities.clone() }, - &mut storage, - ) - .expect("Adding `system::GensisConfig` to the genesis"); + /// Override default wasm code to be placed into GenesisConfig. + pub fn with_wasm_code(mut self, wasm_code: &Option>) -> Self { + self.wasm_code = wasm_code.clone(); + self + } + + pub fn with_heap_pages(mut self, heap_pages_override: Option) -> 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> { - map![ - twox_128(&b"latest"[..]).to_vec() => genesis_block.hash().as_fixed_bytes().to_vec() - ] + genesis_hash } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index b5600843c2749..00db6a745b3f5 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -19,13 +19,29 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "std")] +pub mod extrinsic; #[cfg(feature = "std")] pub mod genesismap; -pub mod system; +pub mod substrate_test_pallet; -use codec::{Decode, Encode, Error, Input, MaxEncodedLen}; +use codec::{Decode, Encode}; +use frame_support::{ + construct_runtime, + dispatch::DispatchClass, + parameter_types, + traits::{ConstU32, ConstU64}, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, WEIGHT_REF_TIME_PER_SECOND}, + Weight, + }, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + CheckNonce, CheckWeight, +}; use scale_info::TypeInfo; -use sp_std::{marker::PhantomData, prelude::*}; +use sp_std::prelude::*; use sp_application_crypto::{ecdsa, ed25519, sr25519, RuntimeAppPublic}; use sp_core::{OpaqueMetadata, RuntimeDebug}; @@ -35,29 +51,13 @@ use sp_trie::{ }; use trie_db::{Trie, TrieMut}; -use cfg_if::cfg_if; -use frame_support::{ - dispatch::RawOrigin, - parameter_types, - traits::{CallerTrait, ConstU32, ConstU64, CrateVersion}, - weights::{RuntimeDbWeight, Weight}, -}; -use frame_system::limits::{BlockLength, BlockWeights}; use sp_api::{decl_runtime_apis, impl_runtime_apis}; pub use sp_core::hash::H256; use sp_inherents::{CheckInherentsResult, InherentData}; -#[cfg(feature = "std")] -use sp_runtime::traits::NumberFor; use sp_runtime::{ create_runtime_str, impl_opaque_keys, - traits::{ - BlakeTwo256, BlindCheckable, Block as BlockT, Extrinsic as ExtrinsicT, GetNodeBlockType, - GetRuntimeBlockType, IdentityLookup, Verify, - }, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, - ValidTransaction, - }, + traits::{BlakeTwo256, Block as BlockT, DispatchInfoOf, NumberFor, Verify}, + transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, Perbill, }; #[cfg(any(feature = "std", test))] @@ -65,10 +65,17 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; // Ensure Babe and Aura use the same crypto to simplify things a bit. -pub use sp_consensus_babe::{AllowedSlots, AuthorityId, Slot}; +pub use sp_consensus_babe::{AllowedSlots, AuthorityId, BabeEpochConfiguration, Slot}; + +pub use pallet_balances::Call as BalancesCall; pub type AuraId = sp_consensus_aura::sr25519::AuthorityId; +#[cfg(feature = "std")] +pub use extrinsic::{ExtrinsicBuilder, Transfer}; + +const LOG_TARGET: &str = "substrate-test-runtime"; + // Include the WASM binary #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); @@ -119,164 +126,31 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -/// Calls in transactions. +/// Transfer data extracted from Extrinsic containing `Balances::transfer_allow_death`. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct Transfer { +pub struct TransferData { pub from: AccountId, pub to: AccountId, - pub amount: u64, - pub nonce: u64, -} - -impl Transfer { - /// Convert into a signed extrinsic. - #[cfg(feature = "std")] - pub fn into_signed_tx(self) -> Extrinsic { - let signature = sp_keyring::AccountKeyring::from_public(&self.from) - .expect("Creates keyring from public key.") - .sign(&self.encode()); - Extrinsic::Transfer { transfer: self, signature, exhaust_resources_when_not_first: false } - } - - /// Convert into a signed extrinsic, which will only end up included in the block - /// if it's the first transaction. Otherwise it will cause `ResourceExhaustion` error - /// which should be considered as block being full. - #[cfg(feature = "std")] - pub fn into_resources_exhausting_tx(self) -> Extrinsic { - let signature = sp_keyring::AccountKeyring::from_public(&self.from) - .expect("Creates keyring from public key.") - .sign(&self.encode()); - Extrinsic::Transfer { transfer: self, signature, exhaust_resources_when_not_first: true } - } -} - -/// Extrinsic for test-runtime. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum Extrinsic { - AuthoritiesChange(Vec), - Transfer { - transfer: Transfer, - signature: AccountSignature, - exhaust_resources_when_not_first: bool, - }, - IncludeData(Vec), - StorageChange(Vec, Option>), - OffchainIndexSet(Vec, Vec), - OffchainIndexClear(Vec), - Store(Vec), - /// Read X times from the state some data and then panic! - /// - /// Returns `Ok` if it didn't read anything. - ReadAndPanic(u32), - /// Read X times from the state some data. - /// - /// Panics if it can not read `X` times. - Read(u32), + pub amount: Balance, + pub nonce: Index, } +/// The address format for describing accounts. +pub type Address = sp_core::sr25519::Public; +pub type Signature = sr25519::Signature; #[cfg(feature = "std")] -impl serde::Serialize for Extrinsic { - fn serialize(&self, seq: S) -> Result - where - S: serde::Serializer, - { - self.using_encoded(|bytes| seq.serialize_bytes(bytes)) - } -} +pub type Pair = sp_core::sr25519::Pair; -// rustc can't deduce this trait bound https://github.com/rust-lang/rust/issues/48214 -#[cfg(feature = "std")] -impl<'a> serde::Deserialize<'a> for Extrinsic { - fn deserialize(de: D) -> Result - where - D: serde::Deserializer<'a>, - { - let r = sp_core::bytes::deserialize(de)?; - Decode::decode(&mut &r[..]) - .map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e))) - } -} +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = (CheckNonce, CheckWeight, CheckSubstrateCall); +/// The payload being signed in transactions. +pub type SignedPayload = sp_runtime::generic::SignedPayload; +/// Unchecked extrinsic type as expected by this runtime. +pub type Extrinsic = + sp_runtime::generic::UncheckedExtrinsic; -impl BlindCheckable for Extrinsic { - type Checked = Self; - - fn check(self) -> Result { - match self { - Extrinsic::AuthoritiesChange(new_auth) => Ok(Extrinsic::AuthoritiesChange(new_auth)), - Extrinsic::Transfer { transfer, signature, exhaust_resources_when_not_first } => - if sp_runtime::verify_encoded_lazy(&signature, &transfer, &transfer.from) { - Ok(Extrinsic::Transfer { - transfer, - signature, - exhaust_resources_when_not_first, - }) - } else { - Err(InvalidTransaction::BadProof.into()) - }, - Extrinsic::IncludeData(v) => Ok(Extrinsic::IncludeData(v)), - Extrinsic::StorageChange(key, value) => Ok(Extrinsic::StorageChange(key, value)), - Extrinsic::OffchainIndexSet(key, value) => Ok(Extrinsic::OffchainIndexSet(key, value)), - Extrinsic::OffchainIndexClear(key) => Ok(Extrinsic::OffchainIndexClear(key)), - Extrinsic::Store(data) => Ok(Extrinsic::Store(data)), - Extrinsic::ReadAndPanic(i) => Ok(Extrinsic::ReadAndPanic(i)), - Extrinsic::Read(i) => Ok(Extrinsic::Read(i)), - } - } -} - -impl ExtrinsicT for Extrinsic { - type Call = Extrinsic; - type SignaturePayload = (); - - fn is_signed(&self) -> Option { - if let Extrinsic::IncludeData(_) = *self { - Some(false) - } else { - Some(true) - } - } - - fn new(call: Self::Call, _signature_payload: Option) -> Option { - Some(call) - } -} - -impl sp_runtime::traits::Dispatchable for Extrinsic { - type RuntimeOrigin = RuntimeOrigin; - type Config = (); - type Info = (); - type PostInfo = (); - fn dispatch( - self, - _origin: Self::RuntimeOrigin, - ) -> sp_runtime::DispatchResultWithInfo { - panic!("This implementation should not be used for actual dispatch."); - } -} - -impl Extrinsic { - /// Convert `&self` into `&Transfer`. - /// - /// Panics if this is no `Transfer` extrinsic. - pub fn transfer(&self) -> &Transfer { - self.try_transfer().expect("cannot convert to transfer ref") - } - - /// Try to convert `&self` into `&Transfer`. - /// - /// Returns `None` if this is no `Transfer` extrinsic. - pub fn try_transfer(&self) -> Option<&Transfer> { - match self { - Extrinsic::Transfer { ref transfer, .. } => Some(transfer), - _ => None, - } - } -} - -/// The signature type used by accounts/transactions. -pub type AccountSignature = sr25519::Signature; /// An identifier for an account on this system. -pub type AccountId = ::Signer; +pub type AccountId = ::Signer; /// A simple hash type for all our hashing. pub type Hash = H256; /// The hashing algorithm used. @@ -293,351 +167,200 @@ pub type Digest = sp_runtime::generic::Digest; pub type Block = sp_runtime::generic::Block; /// A test block's header. pub type Header = sp_runtime::generic::Header; - -/// Run whatever tests we have. -pub fn run_tests(mut input: &[u8]) -> Vec { - use sp_runtime::print; - - print("run_tests..."); - let block = Block::decode(&mut input).unwrap(); - print("deserialized block."); - let stxs = block.extrinsics.iter().map(Encode::encode); - print("reserialized transactions."); - [stxs.count() as u8].encode() -} - -/// A type that can not be decoded. -#[derive(PartialEq, TypeInfo)] -pub struct DecodeFails { - _phantom: PhantomData, -} - -impl Encode for DecodeFails { - fn encode(&self) -> Vec { - Vec::new() - } -} - -impl codec::EncodeLike for DecodeFails {} - -impl Default for DecodeFails { - /// Create a default instance. - fn default() -> DecodeFails { - DecodeFails { _phantom: Default::default() } - } -} - -impl Decode for DecodeFails { - fn decode(_: &mut I) -> Result { - Err("DecodeFails always fails".into()) - } -} - -cfg_if! { - if #[cfg(feature = "std")] { - decl_runtime_apis! { - #[api_version(2)] - pub trait TestAPI { - /// Return the balance of the given account id. - fn balance_of(id: AccountId) -> u64; - /// A benchmark function that adds one to the given value and returns the result. - fn benchmark_add_one(val: &u64) -> u64; - /// A benchmark function that adds one to each value in the given vector and returns the - /// result. - fn benchmark_vector_add_one(vec: &Vec) -> Vec; - /// A function that always fails to convert a parameter between runtime and node. - fn fail_convert_parameter(param: DecodeFails); - /// A function that always fails to convert its return value between runtime and node. - fn fail_convert_return_value() -> DecodeFails; - /// A function for that the signature changed in version `2`. - #[changed_in(2)] - fn function_signature_changed() -> Vec; - /// The new signature. - fn function_signature_changed() -> u64; - fn fail_on_native() -> u64; - fn fail_on_wasm() -> u64; - /// trie no_std testing - fn use_trie() -> u64; - fn benchmark_indirect_call() -> u64; - fn benchmark_direct_call() -> u64; - fn vec_with_capacity(size: u32) -> Vec; - /// Returns the initialized block number. - fn get_block_number() -> u64; - /// Takes and returns the initialized block number. - fn take_block_number() -> Option; - /// Test that `ed25519` crypto works in the runtime. - /// - /// Returns the signature generated for the message `ed25519` and the public key. - fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic); - /// Test that `sr25519` crypto works in the runtime. - /// - /// Returns the signature generated for the message `sr25519`. - fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic); - /// Test that `ecdsa` crypto works in the runtime. - /// - /// Returns the signature generated for the message `ecdsa`. - fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic); - /// Run various tests against storage. - fn test_storage(); - /// Check a witness. - fn test_witness(proof: StorageProof, root: crate::Hash); - /// Test that ensures that we can call a function that takes multiple - /// arguments. - fn test_multiple_arguments(data: Vec, other: Vec, num: u32); - /// Traces log "Hey I'm runtime." - fn do_trace_log(); - /// Verify the given signature, public & message bundle. - fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool; - } - } - } else { - decl_runtime_apis! { - pub trait TestAPI { - /// Return the balance of the given account id. - fn balance_of(id: AccountId) -> u64; - /// A benchmark function that adds one to the given value and returns the result. - fn benchmark_add_one(val: &u64) -> u64; - /// A benchmark function that adds one to each value in the given vector and returns the - /// result. - fn benchmark_vector_add_one(vec: &Vec) -> Vec; - /// A function that always fails to convert a parameter between runtime and node. - fn fail_convert_parameter(param: DecodeFails); - /// A function that always fails to convert its return value between runtime and node. - fn fail_convert_return_value() -> DecodeFails; - /// In wasm we just emulate the old behavior. - fn function_signature_changed() -> Vec; - fn fail_on_native() -> u64; - fn fail_on_wasm() -> u64; - /// trie no_std testing - fn use_trie() -> u64; - fn benchmark_indirect_call() -> u64; - fn benchmark_direct_call() -> u64; - fn vec_with_capacity(size: u32) -> Vec; - /// Returns the initialized block number. - fn get_block_number() -> u64; - /// Takes and returns the initialized block number. - fn take_block_number() -> Option; - /// Test that `ed25519` crypto works in the runtime. - /// - /// Returns the signature generated for the message `ed25519` and the public key. - fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic); - /// Test that `sr25519` crypto works in the runtime. - /// - /// Returns the signature generated for the message `sr25519`. - fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic); - /// Test that `ecdsa` crypto works in the runtime. - /// - /// Returns the signature generated for the message `ecdsa`. - fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic); - /// Run various tests against storage. - fn test_storage(); - /// Check a witness. - fn test_witness(proof: StorageProof, root: crate::Hash); - /// Test that ensures that we can call a function that takes multiple - /// arguments. - fn test_multiple_arguments(data: Vec, other: Vec, num: u32); - /// Traces log "Hey I'm runtime." - fn do_trace_log(); - /// Verify the given signature, public & message bundle. - fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool; - } - } - } -} - -#[derive(Clone, Eq, PartialEq, TypeInfo)] -pub struct Runtime; -impl GetNodeBlockType for Runtime { - type NodeBlock = Block; -} - -impl GetRuntimeBlockType for Runtime { - type RuntimeBlock = Block; -} - -#[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub struct RuntimeOrigin; - -impl From::AccountId>> for RuntimeOrigin { - fn from(_: RawOrigin<::AccountId>) -> Self { - unimplemented!("Not required in tests!") +/// Balance of an account. +pub type Balance = u64; + +decl_runtime_apis! { + #[api_version(2)] + pub trait TestAPI { + /// Return the balance of the given account id. + fn balance_of(id: AccountId) -> u64; + /// A benchmark function that adds one to the given value and returns the result. + fn benchmark_add_one(val: &u64) -> u64; + /// A benchmark function that adds one to each value in the given vector and returns the + /// result. + fn benchmark_vector_add_one(vec: &Vec) -> Vec; + /// A function for that the signature changed in version `2`. + #[changed_in(2)] + fn function_signature_changed() -> Vec; + /// The new signature. + fn function_signature_changed() -> u64; + /// trie no_std testing + fn use_trie() -> u64; + /// Calls function in the loop using never-inlined function pointer + fn benchmark_indirect_call() -> u64; + /// Calls function in the loop + fn benchmark_direct_call() -> u64; + /// Allocates vector with given capacity. + fn vec_with_capacity(size: u32) -> Vec; + /// Returns the initialized block number. + fn get_block_number() -> u64; + + /// Test that `ed25519` crypto works in the runtime. + /// + /// Returns the signature generated for the message `ed25519` and the public key. + fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic); + /// Test that `sr25519` crypto works in the runtime. + /// + /// Returns the signature generated for the message `sr25519`. + fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic); + /// Test that `ecdsa` crypto works in the runtime. + /// + /// Returns the signature generated for the message `ecdsa`. + fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic); + /// Run various tests against storage. + fn test_storage(); + /// Check a witness. + fn test_witness(proof: StorageProof, root: crate::Hash); + /// Test that ensures that we can call a function that takes multiple + /// arguments. + fn test_multiple_arguments(data: Vec, other: Vec, num: u32); + /// Traces log "Hey I'm runtime." + fn do_trace_log(); + /// Verify the given signature, public & message bundle. + fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool; } } -impl CallerTrait<::AccountId> for RuntimeOrigin { - fn into_system(self) -> Option::AccountId>> { - unimplemented!("Not required in tests!") - } +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; - fn as_system_ref(&self) -> Option<&RawOrigin<::AccountId>> { - unimplemented!("Not required in tests!") - } -} +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CheckSubstrateCall; -impl From for Result, RuntimeOrigin> { - fn from(_origin: RuntimeOrigin) -> Result, RuntimeOrigin> { - unimplemented!("Not required in tests!") +impl sp_runtime::traits::Printable for CheckSubstrateCall { + fn print(&self) { + "CheckSubstrateCall".print() } } -impl frame_support::traits::OriginTrait for RuntimeOrigin { - type Call = ::RuntimeCall; - type PalletsOrigin = RuntimeOrigin; - type AccountId = ::AccountId; - - fn add_filter(&mut self, _filter: impl Fn(&Self::Call) -> bool + 'static) { - unimplemented!("Not required in tests!") - } - - fn reset_filter(&mut self) { - unimplemented!("Not required in tests!") - } - - fn set_caller_from(&mut self, _other: impl Into) { - unimplemented!("Not required in tests!") - } - - fn filter_call(&self, _call: &Self::Call) -> bool { - unimplemented!("Not required in tests!") - } - - fn caller(&self) -> &Self::PalletsOrigin { - unimplemented!("Not required in tests!") - } +impl sp_runtime::traits::Dispatchable for CheckSubstrateCall { + type RuntimeOrigin = CheckSubstrateCall; + type Config = CheckSubstrateCall; + type Info = CheckSubstrateCall; + type PostInfo = CheckSubstrateCall; - fn into_caller(self) -> Self::PalletsOrigin { - unimplemented!("Not required in tests!") - } - - fn try_with_caller( + fn dispatch( self, - _f: impl FnOnce(Self::PalletsOrigin) -> Result, - ) -> Result { - unimplemented!("Not required in tests!") - } - - fn none() -> Self { - unimplemented!("Not required in tests!") - } - fn root() -> Self { - unimplemented!("Not required in tests!") - } - fn signed(_by: Self::AccountId) -> Self { - unimplemented!("Not required in tests!") - } - fn as_signed(self) -> Option { - unimplemented!("Not required in tests!") - } - fn as_system_ref(&self) -> Option<&RawOrigin> { - unimplemented!("Not required in tests!") + _origin: Self::RuntimeOrigin, + ) -> sp_runtime::DispatchResultWithInfo { + panic!("This implementation should not be used for actual dispatch."); } } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct RuntimeEvent; - -impl From> for RuntimeEvent { - fn from(_evt: frame_system::Event) -> Self { - unimplemented!("Not required in tests!") +impl sp_runtime::traits::SignedExtension for CheckSubstrateCall { + type AccountId = AccountId; + type Call = RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + const IDENTIFIER: &'static str = "CheckSubstrateCall"; + + fn additional_signed( + &self, + ) -> sp_std::result::Result { + Ok(()) } -} -impl frame_support::traits::PalletInfo for Runtime { - fn index() -> Option { - let type_id = sp_std::any::TypeId::of::

(); - if type_id == sp_std::any::TypeId::of::>() { - return Some(0) - } - if type_id == sp_std::any::TypeId::of::>() { - return Some(1) + fn validate( + &self, + _who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + log::trace!(target: LOG_TARGET, "validate"); + match call { + RuntimeCall::SubstrateTest(ref substrate_test_call) => + substrate_test_pallet::validate_runtime_call(substrate_test_call), + _ => Ok(Default::default()), } - if type_id == sp_std::any::TypeId::of::>() { - return Some(2) - } - - None } - fn name() -> Option<&'static str> { - let type_id = sp_std::any::TypeId::of::

(); - if type_id == sp_std::any::TypeId::of::>() { - return Some("System") - } - if type_id == sp_std::any::TypeId::of::>() { - return Some("Timestamp") - } - if type_id == sp_std::any::TypeId::of::>() { - return Some("Babe") - } - - None - } - fn module_name() -> Option<&'static str> { - let type_id = sp_std::any::TypeId::of::

(); - if type_id == sp_std::any::TypeId::of::>() { - return Some("system") - } - if type_id == sp_std::any::TypeId::of::>() { - return Some("pallet_timestamp") - } - if type_id == sp_std::any::TypeId::of::>() { - return Some("pallet_babe") - } - None + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &sp_runtime::traits::DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(drop) } - fn crate_version() -> Option { - use frame_support::traits::PalletInfoAccess as _; - let type_id = sp_std::any::TypeId::of::

(); - if type_id == sp_std::any::TypeId::of::>() { - return Some(system::Pallet::::crate_version()) - } - if type_id == sp_std::any::TypeId::of::>() { - return Some(pallet_timestamp::Pallet::::crate_version()) - } - if type_id == sp_std::any::TypeId::of::>() { - return Some(pallet_babe::Pallet::::crate_version()) - } +} - None +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = Extrinsic + { + System: frame_system, + Babe: pallet_babe, + SubstrateTest: substrate_test_pallet::pallet, + Balances: pallet_balances, } -} +); + +/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. +/// This is used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used +/// by Operational extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +/// Max weight, actual value does not matter for test runtime. +const MAXIMUM_BLOCK_WEIGHT: Weight = + Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX); parameter_types! { - pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 100, - write: 1000, - }; - pub RuntimeBlockLength: BlockLength = - BlockLength::max(4 * 1024 * 1024); - pub RuntimeBlockWeights: BlockWeights = - BlockWeights::with_sensible_defaults(Weight::from_parts(4 * 1024 * 1024, 0), Perbill::from_percent(75)); -} + pub const BlockHashCount: BlockNumber = 2400; + pub const Version: RuntimeVersion = VERSION; -impl From> for Extrinsic { - fn from(_: frame_system::Call) -> Self { - unimplemented!("Not required in tests!") - } + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); } impl frame_system::pallet::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; - type BlockLength = RuntimeBlockLength; + type BlockLength = (); type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = Extrinsic; - type Index = u64; - type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Index = Index; + type BlockNumber = BlockNumber; type Hash = H256; type Hashing = Hashing; - type AccountId = u64; - type Lookup = IdentityLookup; + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<2400>; type DbWeight = (); type Version = (); - type PalletInfo = Self; - type AccountData = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); @@ -646,14 +369,45 @@ impl frame_system::pallet::Config for Runtime { type MaxConsumers = ConstU32<16>; } -impl system::Config for Runtime {} +pub mod currency { + use crate::Balance; + const MILLICENTS: Balance = 1_000_000_000; + const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. + pub const DOLLARS: Balance = 100 * CENTS; +} +parameter_types! { + pub const ExistentialDeposit: Balance = 1 * currency::DOLLARS; + // For weight estimation, we assume that the most locks on an individual account will be 50. + // This number may need to be adjusted in the future if this assumption no longer holds true. + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type FreezeIdentifier = (); + type MaxFreezes = (); + type HoldIdentifier = (); + type MaxHolds = ConstU32<1>; +} + +impl substrate_test_pallet::Config for Runtime {} + +// Required for `pallet_babe::Config`. impl pallet_timestamp::Config for Runtime { - /// A timestamp: milliseconds since the unix epoch. type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = ConstU64<5>; - type WeightInfo = (); + type OnTimestampSet = Babe; + type MinimumPeriod = ConstU64<500>; + type WeightInfo = pallet_timestamp::weights::SubstrateWeight; } parameter_types! { @@ -663,15 +417,12 @@ parameter_types! { impl pallet_babe::Config for Runtime { type EpochDuration = EpochDuration; type ExpectedBlockTime = ConstU64<10_000>; - // there is no actual runtime in this test-runtime, so testing crates - // are manually adding the digests. normally in this situation you'd use - // pallet_babe::SameAuthoritiesForever. - type EpochChangeTrigger = pallet_babe::ExternalTrigger; + type EpochChangeTrigger = pallet_babe::SameAuthoritiesForever; type DisabledValidators = (); - type WeightInfo = (); - type MaxAuthorities = ConstU32<10>; type KeyOwnerProof = sp_core::Void; type EquivocationReportSystem = (); + type WeightInfo = (); + type MaxAuthorities = ConstU32<10>; } /// Adds one to the given input and returns the final result. @@ -680,11 +431,6 @@ fn benchmark_add_one(i: u64) -> u64 { i + 1 } -/// The `benchmark_add_one` function as function pointer. -#[cfg(not(feature = "std"))] -static BENCHMARK_ADD_ONE: sp_runtime_interface::wasm::ExchangeableFunction u64> = - sp_runtime_interface::wasm::ExchangeableFunction::new(benchmark_add_one); - fn code_using_trie() -> u64 { let pairs = [ (b"0103000000000000000464".to_vec(), b"0400000000".to_vec()), @@ -717,549 +463,257 @@ impl_opaque_keys! { } } -cfg_if! { - if #[cfg(feature = "std")] { - impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - version() - } - - fn execute_block(block: Block) { - system::execute_block(block); - } - - fn initialize_block(header: &::Header) { - system::initialize_block(header) - } - } +pub(crate) const TEST_RUNTIME_BABE_EPOCH_CONFIGURATION: BabeEpochConfiguration = + BabeEpochConfiguration { + c: (3, 10), + allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, + }; - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - unimplemented!() - } +impl_runtime_apis! { + impl sp_api::Core for Runtime { + fn version() -> RuntimeVersion { + version() + } - fn metadata_at_version(_version: u32) -> Option { - unimplemented!() - } + fn execute_block(block: Block) { + log::trace!(target: LOG_TARGET, "execute_block: {block:#?}"); + Executive::execute_block(block); + } - fn metadata_versions() -> sp_std::vec::Vec { - unimplemented!() - } - } + fn initialize_block(header: &::Header) { + log::trace!(target: LOG_TARGET, "initialize_block: {header:#?}"); + Executive::initialize_block(header); + } + } - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - _source: TransactionSource, - utx: ::Extrinsic, - _: ::Hash, - ) -> TransactionValidity { - if let Extrinsic::IncludeData(data) = utx { - return Ok(ValidTransaction { - priority: data.len() as u64, - requires: vec![], - provides: vec![data], - longevity: 1, - propagate: false, - }); - } - - system::validate_transaction(utx) - } - } + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - system::execute_transaction(extrinsic) - } + fn metadata_at_version(_version: u32) -> Option { + unimplemented!() + } + fn metadata_versions() -> sp_std::vec::Vec { + unimplemented!() + } + } - fn finalize_block() -> ::Header { - system::finalize_block() - } + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + utx: ::Extrinsic, + block_hash: ::Hash, + ) -> TransactionValidity { + let validity = Executive::validate_transaction(source, utx.clone(), block_hash); + log::trace!(target: LOG_TARGET, "validate_transaction {:?} {:?}", utx, validity); + validity + } + } - fn inherent_extrinsics(_data: InherentData) -> Vec<::Extrinsic> { - vec![] - } + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { + Executive::apply_extrinsic(extrinsic) + } - fn check_inherents(_block: Block, _data: InherentData) -> CheckInherentsResult { - CheckInherentsResult::new() - } - } + fn finalize_block() -> ::Header { + log::trace!(target: LOG_TARGET, "finalize_block"); + Executive::finalize_block() + } - impl self::TestAPI for Runtime { - fn balance_of(id: AccountId) -> u64 { - system::balance_of(id) - } - - fn benchmark_add_one(val: &u64) -> u64 { - val + 1 - } - - fn benchmark_vector_add_one(vec: &Vec) -> Vec { - let mut vec = vec.clone(); - vec.iter_mut().for_each(|v| *v += 1); - vec - } - - fn fail_convert_parameter(_: DecodeFails) {} - - fn fail_convert_return_value() -> DecodeFails { - DecodeFails::default() - } - - fn function_signature_changed() -> u64 { - 1 - } - - fn fail_on_native() -> u64 { - panic!("Failing because we are on native") - } - fn fail_on_wasm() -> u64 { - 1 - } - - fn use_trie() -> u64 { - code_using_trie() - } - - fn benchmark_indirect_call() -> u64 { - let function = benchmark_add_one; - (0..1000).fold(0, |p, i| p + function(i)) - } - fn benchmark_direct_call() -> u64 { - (0..1000).fold(0, |p, i| p + benchmark_add_one(i)) - } - - fn vec_with_capacity(_size: u32) -> Vec { - unimplemented!("is not expected to be invoked from non-wasm builds"); - } - - fn get_block_number() -> u64 { - system::get_block_number().expect("Block number is initialized") - } - - fn take_block_number() -> Option { - system::take_block_number() - } - - fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) { - test_ed25519_crypto() - } - - fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic) { - test_sr25519_crypto() - } - - fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic) { - test_ecdsa_crypto() - } - - fn test_storage() { - test_read_storage(); - test_read_child_storage(); - } - - fn test_witness(proof: StorageProof, root: crate::Hash) { - test_witness(proof, root); - } - - fn test_multiple_arguments(data: Vec, other: Vec, num: u32) { - assert_eq!(&data[..], &other[..]); - assert_eq!(data.len(), num as usize); - } - - fn do_trace_log() { - log::trace!("Hey I'm runtime"); - } - - fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool { - sp_io::crypto::ed25519_verify(&sig, &message, &public) - } - } + fn inherent_extrinsics(_data: InherentData) -> Vec<::Extrinsic> { + vec![] + } - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(1000) - } - - fn authorities() -> Vec { - system::authorities().into_iter().map(|a| { - let authority: sr25519::Public = a.into(); - AuraId::from(authority) - }).collect() - } - } + fn check_inherents(_block: Block, _data: InherentData) -> CheckInherentsResult { + CheckInherentsResult::new() + } + } - impl sp_consensus_babe::BabeApi for Runtime { - fn configuration() -> sp_consensus_babe::BabeConfiguration { - sp_consensus_babe::BabeConfiguration { - slot_duration: 1000, - epoch_length: EpochDuration::get(), - c: (3, 10), - authorities: system::authorities() - .into_iter().map(|x|(x, 1)).collect(), - randomness: >::randomness(), - allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, - } - } - - fn current_epoch_start() -> Slot { - >::current_epoch_start() - } - - fn current_epoch() -> sp_consensus_babe::Epoch { - >::current_epoch() - } - - fn next_epoch() -> sp_consensus_babe::Epoch { - >::next_epoch() - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: sp_consensus_babe::EquivocationProof< - ::Header, - >, - _key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof, - ) -> Option<()> { - None - } - - fn generate_key_ownership_proof( - _slot: sp_consensus_babe::Slot, - _authority_id: sp_consensus_babe::AuthorityId, - ) -> Option { - None - } - } + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - let ex = Extrinsic::IncludeData(header.number.encode()); - sp_io::offchain::submit_transaction(ex.encode()).unwrap(); - } - } + impl self::TestAPI for Runtime { + fn balance_of(id: AccountId) -> u64 { + Balances::free_balance(id) + } - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(_: Option>) -> Vec { - SessionKeys::generate(None) - } + fn benchmark_add_one(val: &u64) -> u64 { + val + 1 + } - fn decode_session_keys( - encoded: Vec, - ) -> Option, sp_core::crypto::KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } + fn benchmark_vector_add_one(vec: &Vec) -> Vec { + let mut vec = vec.clone(); + vec.iter_mut().for_each(|v| *v += 1); + vec + } - impl sp_consensus_grandpa::GrandpaApi for Runtime { - fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { - Vec::new() - } - - fn current_set_id() -> sp_consensus_grandpa::SetId { - 0 - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: sp_consensus_grandpa::EquivocationProof< - ::Hash, - NumberFor, - >, - _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, - ) -> Option<()> { - None - } - - fn generate_key_ownership_proof( - _set_id: sp_consensus_grandpa::SetId, - _authority_id: sp_consensus_grandpa::AuthorityId, - ) -> Option { - None - } - } + fn function_signature_changed() -> u64 { + 1 + } - impl sp_consensus_beefy::BeefyApi for Runtime { - fn beefy_genesis() -> Option { - None - } - - fn validator_set() -> Option> { - None - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: sp_consensus_beefy::EquivocationProof< - NumberFor, - sp_consensus_beefy::crypto::AuthorityId, - sp_consensus_beefy::crypto::Signature - >, - _key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, - ) -> Option<()> { None } - - fn generate_key_ownership_proof( - _set_id: sp_consensus_beefy::ValidatorSetId, - _authority_id: sp_consensus_beefy::crypto::AuthorityId, - ) -> Option { None } - } + fn use_trie() -> u64 { + code_using_trie() + } - impl pallet_beefy_mmr::BeefyMmrApi for Runtime { - fn authority_set_proof() -> sp_consensus_beefy::mmr::BeefyAuthoritySet { - Default::default() - } + fn benchmark_indirect_call() -> u64 { + let function = benchmark_add_one; + (0..1000).fold(0, |p, i| p + function(i)) + } + fn benchmark_direct_call() -> u64 { + (0..1000).fold(0, |p, i| p + benchmark_add_one(i)) + } - fn next_authority_set_proof() -> sp_consensus_beefy::mmr::BeefyNextAuthoritySet { - Default::default() - } - } + fn vec_with_capacity(size: u32) -> Vec { + Vec::with_capacity(size as usize) + } - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(_account: AccountId) -> Index { - 0 - } - } + fn get_block_number() -> u64 { + System::block_number() + } + + fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) { + test_ed25519_crypto() } - } else { - impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - version() - } - - fn execute_block(block: Block) { - system::execute_block(block); - } - - fn initialize_block(header: &::Header) { - system::initialize_block(header) - } - } - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - unimplemented!() - } + fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic) { + test_sr25519_crypto() + } - fn metadata_at_version(_version: u32) -> Option { - unimplemented!() - } + fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic) { + test_ecdsa_crypto() + } - fn metadata_versions() -> sp_std::vec::Vec { - unimplemented!() - } - } + fn test_storage() { + test_read_storage(); + test_read_child_storage(); + } - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - _source: TransactionSource, - utx: ::Extrinsic, - _: ::Hash, - ) -> TransactionValidity { - if let Extrinsic::IncludeData(data) = utx { - return Ok(ValidTransaction{ - priority: data.len() as u64, - requires: vec![], - provides: vec![data], - longevity: 1, - propagate: false, - }); - } - - system::validate_transaction(utx) - } - } + fn test_witness(proof: StorageProof, root: crate::Hash) { + test_witness(proof, root); + } + + fn test_multiple_arguments(data: Vec, other: Vec, num: u32) { + assert_eq!(&data[..], &other[..]); + assert_eq!(data.len(), num as usize); + } - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - system::execute_transaction(extrinsic) - } + fn do_trace_log() { + log::trace!("Hey I'm runtime"); + } - fn finalize_block() -> ::Header { - system::finalize_block() - } + fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool { + sp_io::crypto::ed25519_verify(&sig, &message, &public) + } + } - fn inherent_extrinsics(_data: InherentData) -> Vec<::Extrinsic> { - vec![] - } + impl sp_consensus_aura::AuraApi for Runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + sp_consensus_aura::SlotDuration::from_millis(1000) + } - fn check_inherents(_block: Block, _data: InherentData) -> CheckInherentsResult { - CheckInherentsResult::new() - } - } + fn authorities() -> Vec { + SubstrateTest::authorities().into_iter().map(|a| { + let authority: sr25519::Public = a.into(); + AuraId::from(authority) + }).collect() + } + } - impl self::TestAPI for Runtime { - fn balance_of(id: AccountId) -> u64 { - system::balance_of(id) - } - - fn benchmark_add_one(val: &u64) -> u64 { - val + 1 - } - - fn benchmark_vector_add_one(vec: &Vec) -> Vec { - let mut vec = vec.clone(); - vec.iter_mut().for_each(|v| *v += 1); - vec - } - - fn fail_convert_parameter(_: DecodeFails) {} - - fn fail_convert_return_value() -> DecodeFails { - DecodeFails::default() - } - - fn function_signature_changed() -> Vec { - let mut vec = Vec::new(); - vec.push(1); - vec.push(2); - vec - } - - fn fail_on_native() -> u64 { - 1 - } - - fn fail_on_wasm() -> u64 { - panic!("Failing because we are on wasm") - } - - fn use_trie() -> u64 { - code_using_trie() - } - - fn benchmark_indirect_call() -> u64 { - (0..10000).fold(0, |p, i| p + BENCHMARK_ADD_ONE.get()(i)) - } - - fn benchmark_direct_call() -> u64 { - (0..10000).fold(0, |p, i| p + benchmark_add_one(i)) - } - - fn vec_with_capacity(size: u32) -> Vec { - Vec::with_capacity(size as usize) - } - - fn get_block_number() -> u64 { - system::get_block_number().expect("Block number is initialized") - } - - fn take_block_number() -> Option { - system::take_block_number() - } - - fn test_ed25519_crypto() -> (ed25519::AppSignature, ed25519::AppPublic) { - test_ed25519_crypto() - } - - fn test_sr25519_crypto() -> (sr25519::AppSignature, sr25519::AppPublic) { - test_sr25519_crypto() - } - - fn test_ecdsa_crypto() -> (ecdsa::AppSignature, ecdsa::AppPublic) { - test_ecdsa_crypto() - } - - fn test_storage() { - test_read_storage(); - test_read_child_storage(); - } - - fn test_witness(proof: StorageProof, root: crate::Hash) { - test_witness(proof, root); - } - - fn test_multiple_arguments(data: Vec, other: Vec, num: u32) { - assert_eq!(&data[..], &other[..]); - assert_eq!(data.len(), num as usize); - } - - fn do_trace_log() { - log::trace!("Hey I'm runtime: {}", log::STATIC_MAX_LEVEL); - } - - fn verify_ed25519(sig: ed25519::Signature, public: ed25519::Public, message: Vec) -> bool { - sp_io::crypto::ed25519_verify(&sig, &message, &public) - } + impl sp_consensus_babe::BabeApi for Runtime { + fn configuration() -> sp_consensus_babe::BabeConfiguration { + let epoch_config = Babe::epoch_config().unwrap_or(TEST_RUNTIME_BABE_EPOCH_CONFIGURATION); + sp_consensus_babe::BabeConfiguration { + slot_duration: Babe::slot_duration(), + epoch_length: EpochDuration::get(), + c: epoch_config.c, + authorities: SubstrateTest::authorities() + .into_iter().map(|x|(x, 1)).collect(), + randomness: Babe::randomness(), + allowed_slots: epoch_config.allowed_slots, } + } - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(1000) - } - - fn authorities() -> Vec { - system::authorities().into_iter().map(|a| { - let authority: sr25519::Public = a.into(); - AuraId::from(authority) - }).collect() - } - } + fn current_epoch_start() -> Slot { + Babe::current_epoch_start() + } - impl sp_consensus_babe::BabeApi for Runtime { - fn configuration() -> sp_consensus_babe::BabeConfiguration { - sp_consensus_babe::BabeConfiguration { - slot_duration: 1000, - epoch_length: EpochDuration::get(), - c: (3, 10), - authorities: system::authorities() - .into_iter().map(|x|(x, 1)).collect(), - randomness: >::randomness(), - allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots, - } - } - - fn current_epoch_start() -> Slot { - >::current_epoch_start() - } - - fn current_epoch() -> sp_consensus_babe::Epoch { - >::current_epoch() - } - - fn next_epoch() -> sp_consensus_babe::Epoch { - >::next_epoch() - } - - fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: sp_consensus_babe::EquivocationProof< - ::Header, - >, - _key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof, - ) -> Option<()> { - None - } - - fn generate_key_ownership_proof( - _slot: sp_consensus_babe::Slot, - _authority_id: sp_consensus_babe::AuthorityId, - ) -> Option { - None - } - } + fn current_epoch() -> sp_consensus_babe::Epoch { + Babe::current_epoch() + } - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - let ex = Extrinsic::IncludeData(header.number.encode()); - sp_io::offchain::submit_transaction(ex.encode()).unwrap() - } - } + fn next_epoch() -> sp_consensus_babe::Epoch { + Babe::next_epoch() + } - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(_: Option>) -> Vec { - SessionKeys::generate(None) - } + fn submit_report_equivocation_unsigned_extrinsic( + _equivocation_proof: sp_consensus_babe::EquivocationProof< + ::Header, + >, + _key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof, + ) -> Option<()> { + None + } - fn decode_session_keys( - encoded: Vec, - ) -> Option, sp_core::crypto::KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } + fn generate_key_ownership_proof( + _slot: sp_consensus_babe::Slot, + _authority_id: sp_consensus_babe::AuthorityId, + ) -> Option { + None + } + } - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(_account: AccountId) -> Index { - 0 - } - } + impl sp_offchain::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &::Header) { + let ext = Extrinsic::new_unsigned( + substrate_test_pallet::pallet::Call::storage_change{ + key:b"some_key".encode(), + value:Some(header.number.encode()) + }.into(), + ); + sp_io::offchain::submit_transaction(ext.encode()).unwrap(); + } + } + + impl sp_session::SessionKeys for Runtime { + fn generate_session_keys(_: Option>) -> Vec { + SessionKeys::generate(None) + } + + fn decode_session_keys( + encoded: Vec, + ) -> Option, sp_core::crypto::KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + } + + impl sp_consensus_grandpa::GrandpaApi for Runtime { + fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { + Vec::new() + } + + fn current_set_id() -> sp_consensus_grandpa::SetId { + 0 + } + + fn submit_report_equivocation_unsigned_extrinsic( + _equivocation_proof: sp_consensus_grandpa::EquivocationProof< + ::Hash, + NumberFor, + >, + _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, + ) -> Option<()> { + None + } + + fn generate_key_ownership_proof( + _set_id: sp_consensus_grandpa::SetId, + _authority_id: sp_consensus_grandpa::AuthorityId, + ) -> Option { + None } } } @@ -1360,13 +814,194 @@ fn test_witness(proof: StorageProof, root: crate::Hash) { assert!(ext.storage_root(Default::default()).as_slice() != &root[..]); } +/// Some tests require the hashed keys of the storage. As the values of hashed keys are not trivial +/// to guess, this small module provides the values of the keys, and the code which is required to +/// generate the keys. +#[cfg(feature = "std")] +pub mod storage_key_generator { + use super::*; + use sp_core::Pair; + use sp_keyring::AccountKeyring; + + /// Generate hex string without prefix + pub(super) fn hex(x: T) -> String + where + T: array_bytes::Hex, + { + x.hex(Default::default()) + } + + fn concat_hashes(input: &Vec<&[u8]>) -> String { + input.iter().map(|s| sp_core::hashing::twox_128(s)).map(hex).collect() + } + + fn twox_64_concat(x: &[u8]) -> Vec { + sp_core::hashing::twox_64(x).iter().chain(x.iter()).cloned().collect::>() + } + + /// Generate the hashed storage keys from the raw literals. These keys are expected to be be in + /// storage with given substrate-test runtime. + pub fn generate_expected_storage_hashed_keys() -> Vec { + let literals: Vec<&[u8]> = vec![b":code", b":extrinsic_index", b":heappages"]; + + let keys: Vec> = vec![ + vec![b"Babe", b"Authorities"], + vec![b"Babe", b"EpochConfig"], + vec![b"Babe", b"NextAuthorities"], + vec![b"Babe", b"SegmentIndex"], + vec![b"Babe", b":__STORAGE_VERSION__:"], + vec![b"Balances", b":__STORAGE_VERSION__:"], + vec![b"Balances", b"TotalIssuance"], + vec![b"SubstrateTest", b"Authorities"], + vec![b"SubstrateTest", b":__STORAGE_VERSION__:"], + vec![b"System", b"LastRuntimeUpgrade"], + vec![b"System", b"ParentHash"], + vec![b"System", b":__STORAGE_VERSION__:"], + vec![b"System", b"UpgradedToTripleRefCount"], + vec![b"System", b"UpgradedToU32RefCount"], + ]; + + let mut expected_keys = keys.iter().map(concat_hashes).collect::>(); + + expected_keys.extend(literals.into_iter().map(hex)); + + let balances_map_keys = (0..16_usize) + .into_iter() + .map(|i| AccountKeyring::numeric(i).public().to_vec()) + .chain(vec![ + AccountKeyring::Alice.public().to_vec(), + AccountKeyring::Bob.public().to_vec(), + AccountKeyring::Charlie.public().to_vec(), + ]) + .map(|pubkey| { + sp_core::hashing::blake2_128(&pubkey) + .iter() + .chain(pubkey.iter()) + .cloned() + .collect::>() + }) + .map(|hash_pubkey| { + [concat_hashes(&vec![b"System", b"Account"]), hex(hash_pubkey)].concat() + }); + + expected_keys.extend(balances_map_keys); + + expected_keys.push( + [ + concat_hashes(&vec![b"System", b"BlockHash"]), + hex(0u64.using_encoded(twox_64_concat)), + ] + .concat(), + ); + + expected_keys.sort(); + expected_keys + } + + /// Provides the commented list of hashed keys. This contains a hard-coded list of hashed keys + /// that would be generated by `generate_expected_storage_hashed_keys`. This list is provided + /// for the debugging convenience only. Value of each hex-string is documented with the literal + /// origin. + pub fn get_expected_storage_hashed_keys() -> Vec { + [ + //System|:__STORAGE_VERSION__: + "00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429", + //SubstrateTest|Authorities + "00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d", + //Babe|:__STORAGE_VERSION__: + "1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429", + //Babe|Authorities + "1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d", + //Babe|SegmentIndex + "1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4", + //Babe|NextAuthorities + "1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c", + //Babe|EpochConfig + "1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef", + //System|:__STORAGE_VERSION__: + "26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429", + //System|UpgradedToU32RefCount + "26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710", + //System|ParentHash + "26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc", + //System::BlockHash|0 + "26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000", + //System|UpgradedToTripleRefCount + "26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439", + + // System|Account|blake2_128Concat("//11") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901cae4e3edfbb32c91ed3f01ab964f4eeeab50338d8e5176d3141802d7b010a55dadcd5f23cf8aaafa724627e967e90e", + // System|Account|blake2_128Concat("//4") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da91b614bd4a126f2d5d294e9a8af9da25248d7e931307afb4b68d8d565d4c66e00d856c6d65f5fed6bb82dcfb60e936c67", + // System|Account|blake2_128Concat("//7") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94b21aff9fe1e8b2fc4b0775b8cbeff28ba8e2c7594dd74730f3ca835e95455d199261897edc9735d602ea29615e2b10b", + // System|Account|blake2_128Concat("//Bob") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", + // System|Account|blake2_128Concat("//3") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95786a2916fcb81e1bd5dcd81e0d2452884617f575372edb5a36d85c04cdf2e4699f96fe33eb5f94a28c041b88e398d0c", + // System|Account|blake2_128Concat("//14") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95b8542d9672c7b7e779cc7c1e6b605691c2115d06120ea2bee32dd601d02f36367564e7ddf84ae2717ca3f097459652e", + // System|Account|blake2_128Concat("//6") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da996c30bdbfab640838e6b6d3c33ab4adb4211b79e34ee8072eab506edd4b93a7b85a14c9a05e5cdd056d98e7dbca87730", + // System|Account|blake2_128Concat("//9") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da99dc65b1339ec388fbf2ca0cdef51253512c6cfd663203ea16968594f24690338befd906856c4d2f4ef32dad578dba20c", + // System|Account|blake2_128Concat("//8") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da99e6eb5abd62f5fd54793da91a47e6af6125d57171ff9241f07acaa1bb6a6103517965cf2cd00e643b27e7599ebccba70", + // System|Account|blake2_128Concat("//Charlie") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22", + // System|Account|blake2_128Concat("//10") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d0052993b6f3bd0544fd1f5e4125b9fbde3e789ecd53431fe5c06c12b72137153496dace35c695b5f4d7b41f7ed5763b", + // System|Account|blake2_128Concat("//1") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d6b7e9a5f12bc571053265dade10d3b4b606fc73f57f03cdb4c932d475ab426043e429cecc2ffff0d2672b0df8398c48", + // System|Account|blake2_128Concat("//Alice") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + // System|Account|blake2_128Concat("//2") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e1a35f56ee295d39287cbffcfc60c4b346f136b564e1fad55031404dd84e5cd3fa76bfe7cc7599b39d38fd06663bbc0a", + // System|Account|blake2_128Concat("//5") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e2c1dc507e2035edbbd8776c440d870460c57f0008067cc01c5ff9eb2e2f9b3a94299a915a91198bd1021a6c55596f57", + // System|Account|blake2_128Concat("//0") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9eca0e653a94f4080f6311b4e7b6934eb2afba9278e30ccf6a6ceb3a8b6e336b70068f045c666f2e7f4f9cc5f47db8972", + // System|Account|blake2_128Concat("//13") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9ee8bf7ef90fc56a8aa3b90b344c599550c29b161e27ff8ba45bf6bad4711f326fc506a8803453a4d7e3158e993495f10", + // System|Account|blake2_128Concat("//12") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9f5d6f1c082fe63eec7a71fcad00f4a892e3d43b7b0d04e776e69e7be35247cecdac65504c579195731eaf64b7940966e", + // System|Account|blake2_128Concat("//15") + "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9fbf0818841edf110e05228a6379763c4fc3c37459d9bdc61f58a5ebc01e9e2305a19d390c0543dc733861ec3cf1de01f", + // System|LastRuntimeUpgrade + "26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8", + // :code + "3a636f6465", + // :extrinsic_index + "3a65787472696e7369635f696e646578", + // :heappages + "3a686561707061676573", + // Balances|:__STORAGE_VERSION__: + "c2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429", + // Balances|TotalIssuance + "c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80", + ].into_iter().map(String::from).collect::>() + } + + #[test] + fn expected_keys_vec_are_matching() { + assert_eq!( + storage_key_generator::get_expected_storage_hashed_keys(), + storage_key_generator::generate_expected_storage_hashed_keys(), + ); + } +} + #[cfg(test)] mod tests { + use super::*; use codec::Encode; + use frame_support::dispatch::DispatchInfo; use sc_block_builder::BlockBuilderProvider; use sp_api::ProvideRuntimeApi; use sp_consensus::BlockOrigin; use sp_core::{storage::well_known_keys::HEAP_PAGES, ExecutionContext}; + use sp_keyring::AccountKeyring; + use sp_runtime::{traits::SignedExtension, transaction_validity::InvalidTransaction}; use sp_state_machine::ExecutionStrategy; use substrate_test_runtime_client::{ prelude::*, runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, @@ -1374,7 +1009,7 @@ mod tests { #[test] fn heap_pages_is_respected() { - // This tests that the on-chain HEAP_PAGES parameter is respected. + // This tests that the on-chain `HEAP_PAGES` parameter is respected. // Create a client devoting only 8 pages of wasm memory. This gives us ~512k of heap memory. let mut client = TestClientBuilder::new() @@ -1421,7 +1056,6 @@ mod tests { } fn witness_backend() -> (sp_trie::MemoryDB, crate::Hash) { - use sp_trie::TrieMut; let mut root = crate::Hash::default(); let mut mdb = sp_trie::MemoryDB::::default(); { @@ -1446,4 +1080,127 @@ mod tests { runtime_api.test_witness(best_hash, proof, root).unwrap(); } + + pub fn new_test_ext() -> sp_io::TestExternalities { + genesismap::GenesisStorageBuilder::new( + vec![AccountKeyring::One.public().into(), AccountKeyring::Two.public().into()], + vec![AccountKeyring::One.into(), AccountKeyring::Two.into()], + 1000 * currency::DOLLARS, + ) + .build_storage() + .into() + } + + #[test] + fn validate_storage_keys() { + assert_eq!( + genesismap::GenesisStorageBuilder::default() + .build_storage() + .top + .keys() + .cloned() + .map(storage_key_generator::hex) + .collect::>(), + storage_key_generator::get_expected_storage_hashed_keys() + ); + } + + #[test] + fn validate_unsigned_works() { + sp_tracing::try_init_simple(); + new_test_ext().execute_with(|| { + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &substrate_test_pallet::Call::bench_call { transfer: Default::default() }, + ), + InvalidTransaction::Call.into(), + ); + + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &substrate_test_pallet::Call::include_data { data: vec![] }, + ), + InvalidTransaction::Call.into(), + ); + + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &substrate_test_pallet::Call::fill_block { ratio: Perbill::from_percent(50) }, + ), + InvalidTransaction::Call.into(), + ); + + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &substrate_test_pallet::Call::deposit_log_digest_item { + log: DigestItem::Other(vec![]) + }, + ), + Ok(Default::default()), + ); + + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &substrate_test_pallet::Call::storage_change { key: vec![], value: None }, + ), + Ok(Default::default()), + ); + + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &substrate_test_pallet::Call::read { count: 0 }, + ), + Ok(Default::default()), + ); + + assert_eq!( + ::validate_unsigned( + TransactionSource::External, + &substrate_test_pallet::Call::read_and_panic { count: 0 }, + ), + Ok(Default::default()), + ); + }); + } + + #[test] + fn check_substrate_check_signed_extension_works() { + sp_tracing::try_init_simple(); + new_test_ext().execute_with(|| { + let x = sp_keyring::AccountKeyring::Alice.into(); + let info = DispatchInfo::default(); + let len = 0_usize; + assert_eq!( + CheckSubstrateCall {} + .validate( + &x, + &ExtrinsicBuilder::new_call_with_priority(16).build().function, + &info, + len + ) + .unwrap() + .priority, + 16 + ); + + assert_eq!( + CheckSubstrateCall {} + .validate( + &x, + &ExtrinsicBuilder::new_call_do_not_propagate().build().function, + &info, + len + ) + .unwrap() + .propagate, + false + ); + }) + } } diff --git a/test-utils/runtime/src/substrate_test_pallet.rs b/test-utils/runtime/src/substrate_test_pallet.rs new file mode 100644 index 0000000000000..98ebd550b9eef --- /dev/null +++ b/test-utils/runtime/src/substrate_test_pallet.rs @@ -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(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::storage] + #[pallet::getter(fn authorities)] + pub type Authorities = StorageValue<_, Vec, ValueQuery>; + + #[pallet::genesis_config] + #[cfg_attr(feature = "std", derive(Default))] + pub struct GenesisConfig { + pub authorities: Vec, + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + >::put(self.authorities.clone()); + } + } + + #[pallet::call] + impl Pallet { + /// Legacy call used in transaction pool benchmarks. + #[pallet::call_index(0)] + #[pallet::weight(100)] + pub fn bench_call(_origin: OriginFor, _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, _data: Vec) -> 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, + key: Vec, + value: Option>, + ) -> 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, + key: Vec, + value: Vec, + ) -> 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, key: Vec) -> 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, data: Vec) -> 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, + log: sp_runtime::generic::DigestItem, + ) -> DispatchResult { + >::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, + _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) -> 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, _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, 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, count: u32) -> DispatchResult { + Self::execute_read(count, true) + } + } + + impl Pallet { + 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 ValidateUnsigned for Pallet { + type Call = Call; + + 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(call: &pallet::Call) -> 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()), + } +} diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs deleted file mode 100644 index caabad336c069..0000000000000 --- a/test-utils/runtime/src/system.rs +++ /dev/null @@ -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(PhantomData); - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::storage] - pub type ExtrinsicData = StorageMap<_, Blake2_128Concat, u32, Vec, ValueQuery>; - - // The current block number being processed. Set by `execute_block`. - #[pallet::storage] - pub type Number = StorageValue<_, BlockNumber, OptionQuery>; - - #[pallet::storage] - pub type ParentHash = StorageValue<_, Hash, ValueQuery>; - - #[pallet::storage] - pub type NewAuthorities = StorageValue<_, Vec, OptionQuery>; - - #[pallet::storage] - pub type StorageDigest = StorageValue<_, Digest, OptionQuery>; - - #[pallet::storage] - pub type Authorities = StorageValue<_, Vec, ValueQuery>; - - #[pallet::genesis_config] - #[cfg_attr(feature = "std", derive(Default))] - pub struct GenesisConfig { - pub authorities: Vec, - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - >::put(self.authorities.clone()); - } - } -} - -pub fn balance_of_key(who: AccountId) -> Vec { - 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. - >::put(&header.number); - >::put(&header.parent_hash); - >::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 = storage::unhashed::get(v); - } -} - -pub fn authorities() -> Vec { - >::get() -} - -pub fn get_block_number() -> Option { - >::get() -} - -pub fn take_block_number() -> Option { - >::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 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); - >::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(>::take).collect(); - let extrinsics_root = trie::blake2_256_ordered_root(txs, StateVersion::V0); - let number = >::take().expect("Number is set by `initialize_block`"); - let parent_hash = >::take(); - let mut digest = - >::take().expect("StorageDigest is set by `initialize_block`"); - - let o_new_authorities = >::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) -> 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 { - >::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> { - crate::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - crate::native_version() - } - } - - fn executor() -> NativeElseWasmExecutor { - 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(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(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(); - }) - } -} diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index 8a39b8295041a..8e28449661650 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -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 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() } diff --git a/utils/frame/rpc/system/src/lib.rs b/utils/frame/rpc/system/src/lib.rs index 46d8472b27f6b..26efa02970efe 100644 --- a/utils/frame/rpc/system/src/lib.rs +++ b/utils/frame/rpc/system/src/lib.rs @@ -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))); } }