, Error>
+{
+ fn inherent_identifier(&self) -> &'static InherentIdentifier {
+ &INHERENT_IDENTIFIER
+ }
+
+ fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> {
+ let proof = (self.inner)()?;
+ if let Some(proof) = proof {
+ inherent_data.put_data(INHERENT_IDENTIFIER, &proof)
+ } else {
+ Ok(())
+ }
+ }
+
+ fn error_to_string(&self, _error: &[u8]) -> Option {
+ Some(format!("no further information"))
+ }
+}
+
+
+pub fn random_chunk(random_hash: &[u8], total_chunks: u32) -> u32 {
+ let mut buf = [0u8; 8];
+ buf.copy_from_slice(&random_hash[0..8]);
+ let random_u64 = u64::from_be_bytes(buf);
+ (random_u64 % total_chunks as u64) as u32
+}
+
+#[cfg(feature = "std")]
+pub mod registration {
+ use sp_consensus::SelectChain;
+ use sp_inherents::{InherentDataProviders};
+ use log::warn;
+ use sc_client_api::{HeaderBackend, BlockBackend};
+ use sp_runtime::{traits::{Block as BlockT, Header, Saturating, Zero}, generic::BlockId};
+ use std::sync::Arc;
+ use sp_trie::{TrieConfiguration, TrieMut};
+ use crate::{StorageProof, CHUNK_SIZE};
+ use std::iter::once;
+
+ type TrieLayout = sp_trie::Layout::;
+ type Hasher = sp_core::Blake2Hasher;
+
+
+ /// Register uncles inherent data provider, if not registered already.
+ pub fn register_storage_proof_inherent_data_provider(
+ client: Arc,
+ select_chain: SC,
+ inherent_data_providers: &InherentDataProviders,
+ ) -> Result<(), sp_consensus::Error> where
+ B: BlockT,
+ C: BlockBackend + HeaderBackend + Send + Sync + 'static,
+ SC: SelectChain + 'static,
+ {
+ if !inherent_data_providers.has_provider(&crate::INHERENT_IDENTIFIER) {
+ inherent_data_providers
+ .register_provider(crate::InherentDataProvider::new(move || {
+ {
+ let chain_head = match select_chain.best_chain() {
+ Ok(x) => x,
+ Err(e) => {
+ warn!(target: "storage-proof", "Unable to get chain head: {:?}", e);
+ return Ok(None);
+ }
+ };
+
+ let number = chain_head.number().saturating_sub(crate::STORAGE_PERIOD.into());
+ if number.is_zero() {
+ // Too early to collect proofs.
+ return Ok(None);
+ }
+
+ match client.block_indexed_body(&BlockId::number(number)) {
+ Ok(Some(transactions)) => {
+ Ok(Some(build_proof::(chain_head.parent_hash().as_ref(), transactions)?))
+ },
+ Ok(None) => {
+ // Nothing was indexed in that block.
+ Ok(None)
+ }
+ Err(e) => {
+ warn!(target: "storage-proof", "Unable to get transactions: {:?}", e);
+ Ok(None)
+ }
+ }
+ }
+ }))
+ .map_err(|err| sp_consensus::Error::InherentData(err.into()))?;
+ }
+ Ok(())
+ }
+
+ fn build_proof(random_hash: &[u8], transactions: Vec>)
+ -> Result
+ {
+ let mut block_root = sp_trie::empty_trie_root::();
+ let mut db = sp_trie::MemoryDB::::default();
+
+ let mut target_chunk = None;
+ let mut target_root = Default::default();
+ let mut target_chunk_key = Default::default();
+ let mut target_block_key = Default::default();
+ let mut chunk_proof = Default::default();
+
+ let total_chunks: u64 = transactions.iter().map(|t| ((t.len() + CHUNK_SIZE - 1) / CHUNK_SIZE) as u64).sum();
+ let mut buf = [0u8; 8];
+ buf.copy_from_slice(&random_hash[0..8]);
+ let random_u64 = u64::from_be_bytes(buf);
+ let target_chunk_index = random_u64 % total_chunks;
+ //Generate tries for each
+
+ let mut chunk_index = 0;
+ for (ti, transaction) in transactions.into_iter().enumerate() {
+ let mut transaction_root = sp_trie::empty_trie_root::();
+ {
+ let mut trie = sp_trie::TrieDBMut::::new(&mut db, &mut transaction_root);
+ let chunks = transaction.chunks(crate::CHUNK_SIZE).map(|c| c.to_vec());
+ for (index, chunk) in chunks.enumerate() {
+ let index = TrieLayout::encode_index(index as u32);
+ trie.insert(&index, &chunk)
+ .map_err(|e| sp_inherents::Error::from(format!("Trie error: {:?}", e)))?;
+ if chunk_index == target_chunk_index {
+ target_chunk = Some(chunk);
+ target_chunk_key = index;
+ }
+ chunk_index += 1;
+ }
+ trie.commit();
+ }
+ let transaction_key = TrieLayout::encode_index(ti as u32);
+ if target_chunk.is_some() && target_root == Default::default() {
+ target_root = transaction_root.clone();
+ target_block_key = transaction_key.clone();
+ chunk_proof = sp_trie::generate_trie_proof::(
+ &db,
+ transaction_root.clone(),
+ &[target_chunk_key.clone()]
+ ).map_err(|e| sp_inherents::Error::from(format!("Trie error: {:?}", e)))?;
+ }
+ {
+ let mut block_trie = sp_trie::TrieDBMut::::new(&mut db, &mut block_root);
+ block_trie.insert(&transaction_key, transaction_root.as_ref())
+ .map_err(|e| sp_inherents::Error::from(format!("Trie error: {:?}", e)))?;
+ block_trie.commit();
+ }
+ };
+ let block_proof = sp_trie::generate_trie_proof::(
+ &db,
+ block_root,
+ &[target_block_key]
+ ).map_err(|e| sp_inherents::Error::from(format!("Trie error: {:?}", e)))?;
+
+ let proof = sp_trie::StorageProof::merge(
+ once(sp_trie::StorageProof::new(chunk_proof)).chain(
+ once(sp_trie::StorageProof::new(block_proof))));
+
+ Ok(StorageProof {
+ proof: proof.into_nodes(),
+ chunk: target_chunk.unwrap(),
+ })
+ }
+}
diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs
index f0b2bfd4bc3d3..d8394a89de526 100644
--- a/primitives/trie/src/storage_proof.rs
+++ b/primitives/trie/src/storage_proof.rs
@@ -58,6 +58,10 @@ impl StorageProof {
StorageProofNodeIterator::new(self)
}
+ /// Convert into plain node vector.
+ pub fn into_nodes(self) -> Vec> {
+ self.trie_nodes
+ }
/// Creates a `MemoryDB` from `Self`.
pub fn into_memory_db(self) -> crate::MemoryDB {
self.into()
From 178493593d441291b970891d5db5d1e3ae6774eb Mon Sep 17 00:00:00 2001
From: arkpar
Date: Thu, 25 Mar 2021 11:48:46 +0100
Subject: [PATCH 02/20] WIP: Tests
---
frame/transaction-storage/src/lib.rs | 42 ++++++++++++++++---
primitives/io/src/lib.rs | 1 +
.../src/overlayed_changes/mod.rs | 5 +++
3 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs
index 54a597b439a86..c5805092ab2db 100644
--- a/frame/transaction-storage/src/lib.rs
+++ b/frame/transaction-storage/src/lib.rs
@@ -120,7 +120,7 @@ pub mod pallet {
#[pallet::call]
impl Pallet {
- #[pallet::weight(0)]
+ #[pallet::weight(1)]
pub(super) fn store(
origin: OriginFor,
data: Vec,
@@ -150,7 +150,7 @@ pub mod pallet {
Ok(().into())
}
- #[pallet::weight(0)]
+ #[pallet::weight(1)]
pub(super) fn renew(
origin: OriginFor,
block: T::BlockNumber,
@@ -172,7 +172,7 @@ pub mod pallet {
Ok(().into())
}
- #[pallet::weight(0)]
+ #[pallet::weight(1)]
fn check_proof(
origin: OriginFor,
proof: Option,
@@ -268,6 +268,27 @@ pub mod pallet {
#[pallet::storage]
pub(super) type StoragePeriod = StorageValue<_, T::BlockNumber>;
+ #[pallet::genesis_config]
+ pub struct GenesisConfig {
+ pub byte_fee: BalanceOf,
+ }
+
+ #[cfg(feature = "std")]
+ impl Default for GenesisConfig {
+ fn default() -> Self {
+ Self {
+ byte_fee: 10u32.into(),
+ }
+ }
+ }
+
+ #[pallet::genesis_build]
+ impl GenesisBuild for GenesisConfig {
+ fn build(&self) {
+ >::put(&self.byte_fee);
+ }
+ }
+
#[pallet::inherent]
impl ProvideInherent for Pallet {
type Call = Call;
@@ -282,6 +303,10 @@ pub mod pallet {
fn check_inherent(_call: &Self::Call, _data: &InherentData) -> result::Result<(), Self::Error> {
Ok(())
}
+
+ fn is_inherent(call: &Self::Call) -> bool {
+ matches!(call, Call::check_proof(_))
+ }
}
impl Pallet {
@@ -326,7 +351,7 @@ mod tests {
{
System: frame_system::{Pallet, Call, Config, Storage, Event},
Balances: pallet_balances::{Pallet, Call, Storage, Config, Event},
- TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Inherent, Event},
+ TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Config, Inherent, Event},
}
);
@@ -384,11 +409,18 @@ mod tests {
// We use default for brevity, but you can configure as desired if needed.
frame_system: Default::default(),
pallet_balances: Default::default(),
+ pallet_transaction_storage: pallet_transaction_storage::GenesisConfig::default(),
}.build_storage().unwrap();
t.into()
}
#[test]
- fn weights_work() {
+ fn stores_transaction() {
+ let mut ext = new_test_ext();
+ let data = vec![1u8, 2u8, 3u8];
+ ext.execute_with(|| {
+ assert_ok!(TransactionStorage::store(Origin::signed(1), data));
+ });
+ assert!(ext.overlayed_changes().transaction_index_ops().len() == 1);
}
}
diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs
index 08902e9ebc9f3..0ef3b74d384ec 100644
--- a/primitives/io/src/lib.rs
+++ b/primitives/io/src/lib.rs
@@ -1466,6 +1466,7 @@ pub type SubstrateHostFunctions = (
crate::trie::HostFunctions,
offchain_index::HostFunctions,
runtime_tasks::HostFunctions,
+ transaction_index::HostFunctions,
);
#[cfg(test)]
diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs
index 2fe5947a0c798..c01d56ab919a0 100644
--- a/primitives/state-machine/src/overlayed_changes/mod.rs
+++ b/primitives/state-machine/src/overlayed_changes/mod.rs
@@ -520,6 +520,11 @@ impl OverlayedChanges {
self.children.get(key).map(|(overlay, info)| (overlay.changes(), info))
}
+ /// Get an list of all index operations.
+ pub fn transaction_index_ops(&self) -> &[IndexOperation] {
+ &self.transaction_index_ops
+ }
+
/// Convert this instance with all changes into a [`StorageChanges`] instance.
#[cfg(feature = "std")]
pub fn into_storage_changes<
From dd79ea55c5e7a5c609f5028e17da791634ad07ec Mon Sep 17 00:00:00 2001
From: arkpar
Date: Thu, 15 Apr 2021 14:00:23 +0300
Subject: [PATCH 03/20] Tests, benchmarks and docs
---
Cargo.lock | 2 +
bin/node/runtime/Cargo.toml | 2 +
bin/node/runtime/src/lib.rs | 5 +-
client/db/src/lib.rs | 7 +-
frame/benchmarking/src/lib.rs | 29 ++-
frame/transaction-storage/Cargo.toml | 11 +-
frame/transaction-storage/README.md | 238 +-----------------
frame/transaction-storage/src/benchmarking.rs | 141 +++++++++++
frame/transaction-storage/src/lib.rs | 203 +++++----------
frame/transaction-storage/src/mock.rs | 148 +++++++++++
frame/transaction-storage/src/tests.rs | 140 +++++++++++
frame/transaction-storage/src/weights.rs | 91 +++++++
primitives/storage-proof/src/lib.rs | 77 +++---
13 files changed, 668 insertions(+), 426 deletions(-)
create mode 100644 frame/transaction-storage/src/benchmarking.rs
create mode 100644 frame/transaction-storage/src/mock.rs
create mode 100644 frame/transaction-storage/src/tests.rs
create mode 100644 frame/transaction-storage/src/weights.rs
diff --git a/Cargo.lock b/Cargo.lock
index ac63de633f69f..310cef0a8a912 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5607,9 +5607,11 @@ dependencies = [
name = "pallet-transaction-storage"
version = "3.0.0"
dependencies = [
+ "frame-benchmarking",
"frame-support",
"frame-support-test",
"frame-system",
+ "hex-literal",
"pallet-balances",
"parity-scale-codec",
"serde",
diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml
index d53dc4013e77e..e57944674fcc4 100644
--- a/bin/node/runtime/Cargo.toml
+++ b/bin/node/runtime/Cargo.toml
@@ -153,6 +153,7 @@ std = [
"pallet-tips/std",
"pallet-transaction-payment-rpc-runtime-api/std",
"pallet-transaction-payment/std",
+ "pallet-transaction-storage/std",
"pallet-treasury/std",
"sp-transaction-pool/std",
"pallet-utility/std",
@@ -195,6 +196,7 @@ runtime-benchmarks = [
"pallet-staking/runtime-benchmarks",
"pallet-timestamp/runtime-benchmarks",
"pallet-tips/runtime-benchmarks",
+ "pallet-transaction-storage/runtime-benchmarks",
"pallet-treasury/runtime-benchmarks",
"pallet-utility/runtime-benchmarks",
"pallet-uniques/runtime-benchmarks",
diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs
index 37b439cacea71..3094a5bb3ddb0 100644
--- a/bin/node/runtime/src/lib.rs
+++ b/bin/node/runtime/src/lib.rs
@@ -1118,6 +1118,7 @@ impl pallet_transaction_storage::Config for Runtime {
type Event = Event;
type Currency = Balances;
type Call = Call;
+ type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight;
}
construct_runtime!(
@@ -1164,11 +1165,8 @@ construct_runtime!(
Mmr: pallet_mmr::{Pallet, Storage},
Lottery: pallet_lottery::{Pallet, Call, Storage, Event},
Gilt: pallet_gilt::{Pallet, Call, Storage, Event, Config},
-<<<<<<< HEAD
Uniques: pallet_uniques::{Pallet, Call, Storage, Event},
-=======
TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Inherent, Event},
->>>>>>> 589fb673e6 (Transaction storage runtime module)
}
);
@@ -1542,6 +1540,7 @@ impl_runtime_apis! {
add_benchmark!(params, batches, frame_system, SystemBench::);
add_benchmark!(params, batches, pallet_timestamp, Timestamp);
add_benchmark!(params, batches, pallet_tips, Tips);
+ add_benchmark!(params, batches, pallet_transaction_storage, TransactionStorage);
add_benchmark!(params, batches, pallet_treasury, Treasury);
add_benchmark!(params, batches, pallet_uniques, Uniques);
add_benchmark!(params, batches, pallet_utility, Utility);
diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs
index d3e451dc49af7..cda197ab0687a 100644
--- a/client/db/src/lib.rs
+++ b/client/db/src/lib.rs
@@ -3054,13 +3054,16 @@ pub(crate) mod tests {
for i in 0 .. 10 {
let mut index = Vec::new();
if i == 0 {
- index.push(IndexOperation::Insert { extrinsic: 0, offset: 1 });
+ index.push(IndexOperation::Insert {
+ extrinsic: 0,
+ hash: x1_hash.as_ref().to_vec(),
+ size: (x1.len() - 1) as u32,
+ });
} else if i < 5 {
// keep renewing 1st
index.push(IndexOperation::Renew {
extrinsic: 0,
hash: x1_hash.as_ref().to_vec(),
- size: (x1.len() - 1) as u32,
});
} // else stop renewing
let hash = insert_block(
diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs
index 63f65db366651..8160bd5d1dd21 100644
--- a/frame/benchmarking/src/lib.rs
+++ b/frame/benchmarking/src/lib.rs
@@ -736,17 +736,20 @@ macro_rules! impl_benchmark {
SelectedBenchmark as $crate::BenchmarkingSetup
>::components(&selected_benchmark);
+ let mut progress = $crate::benchmarking::current_time();
// Default number of steps for a component.
let mut prev_steps = 10;
- let repeat_benchmark = |
+ let mut repeat_benchmark = |
repeat: u32,
c: &[($crate::BenchmarkParameter, u32)],
results: &mut $crate::Vec<$crate::BenchmarkResults>,
verify: bool,
+ step: u32,
+ num_steps: u32,
| -> Result<(), &'static str> {
// Run the benchmark `repeat` times.
- for _ in 0..repeat {
+ for r in 0..repeat {
// Set up the externalities environment for the setup we want to
// benchmark.
let closure_to_benchmark = <
@@ -801,6 +804,20 @@ macro_rules! impl_benchmark {
"Read/Write Count {:?}", read_write_count
);
+ let time = $crate::benchmarking::current_time();
+ if time.saturating_sub(progress) > 5000000000 {
+ progress = $crate::benchmarking::current_time();
+ $crate::log::info!(
+ target: "benchmark",
+ "Benchmarking {} {}/{}, run {}/{}",
+ extrinsic,
+ step,
+ num_steps,
+ r,
+ repeat,
+ );
+ }
+
// Time the storage root recalculation.
let start_storage_root = $crate::benchmarking::current_time();
$crate::storage_root();
@@ -829,9 +846,9 @@ macro_rules! impl_benchmark {
if components.is_empty() {
if verify {
// If `--verify` is used, run the benchmark once to verify it would complete.
- repeat_benchmark(1, Default::default(), &mut $crate::Vec::new(), true)?;
+ repeat_benchmark(1, Default::default(), &mut $crate::Vec::new(), true, 1, 1)?;
}
- repeat_benchmark(repeat, Default::default(), &mut results, false)?;
+ repeat_benchmark(repeat, Default::default(), &mut results, false, 1, 1)?;
} else {
// Select the component we will be benchmarking. Each component will be benchmarked.
for (idx, (name, low, high)) in components.iter().enumerate() {
@@ -869,9 +886,9 @@ macro_rules! impl_benchmark {
if verify {
// If `--verify` is used, run the benchmark once to verify it would complete.
- repeat_benchmark(1, &c, &mut $crate::Vec::new(), true)?;
+ repeat_benchmark(1, &c, &mut $crate::Vec::new(), true, s, num_of_steps)?;
}
- repeat_benchmark(repeat, &c, &mut results, false)?;
+ repeat_benchmark(repeat, &c, &mut results, false, s, num_of_steps)?;
}
}
}
diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml
index 863408dc1ac52..3e11b60e38706 100644
--- a/frame/transaction-storage/Cargo.toml
+++ b/frame/transaction-storage/Cargo.toml
@@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
serde = { version = "1.0.101", optional = true }
+hex-literal = { version = "0.3.1", optional = true }
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
frame-support = { version = "3.0.0", default-features = false, path = "../support" }
frame-system = { version = "3.0.0", default-features = false, path = "../system" }
@@ -23,13 +24,21 @@ sp-std = { version = "3.0.0", default-features = false, path = "../../primitives
sp-io = { version = "3.0.0", default-features = false, path = "../../primitives/io" }
sp-inherents = { version = "3.0.0", default-features = false, path = "../../primitives/inherents" }
sp-storage-proof = { version = "3.0.0", default-features = false, path = "../../primitives/storage-proof" }
+sp-core = { version = "3.0.0", path = "../../primitives/core", default-features = false, optional = true }
+frame-benchmarking = { version = "3.1.0", default-features = false, path = "../benchmarking", optional = true }
[dev-dependencies]
-sp-core = { version = "3.0.0", path = "../../primitives/core", default-features = false }
frame-support-test = { version = "3.0.0", path = "../support/test" }
+sp-storage-proof = { version = "3.0.0", default-features = true, path = "../../primitives/storage-proof" }
+sp-core = { version = "3.0.0", path = "../../primitives/core", default-features = false }
[features]
default = ["std"]
+runtime-benchmarks = [
+ "frame-benchmarking",
+ "sp-core",
+ "hex-literal",
+]
std = [
"serde",
"codec/std",
diff --git a/frame/transaction-storage/README.md b/frame/transaction-storage/README.md
index 46a0d076a969a..4eaddae1786e7 100644
--- a/frame/transaction-storage/README.md
+++ b/frame/transaction-storage/README.md
@@ -1,238 +1,2 @@
-
-# Example Pallet
-
-The Example: A simple example of a FRAME pallet demonstrating
-concepts, APIs and structures common to most FRAME runtimes.
-
-Run `cargo doc --package pallet-example --open` to view this pallet's documentation.
-
-### Documentation Guidelines:
-
-
-
-
-
Documentation comments (i.e. /// comment) - should
- accompany pallet functions and be restricted to the pallet interface,
- not the internals of the pallet implementation. Only state inputs,
- outputs, and a brief description that mentions whether calling it
- requires root, but without repeating the source code details.
- Capitalize the first word of each documentation comment and end it with
- a full stop. See
- Generic example of annotating source code with documentation comments
-
Self-documenting code - Try to refactor code to be self-documenting.
-
Code comments - Supplement complex code with a brief explanation, not every line of code.
-
Identifiers - surround by backticks (i.e. INHERENT_IDENTIFIER, InherentType,
- u64)
-
Usage scenarios - should be simple doctests. The compiler should ensure they stay valid.
-
Extended tutorials - should be moved to external files and refer to.
-
-
Mandatory - include all of the sections/subsections where MUST is specified.
-
Optional - optionally include sections/subsections where CAN is specified.
-
-
-### Documentation Template:
-
-Copy and paste this template from frame/example/src/lib.rs into file
-`frame//src/lib.rs` of your own custom pallet and complete it.
-
-// Add heading with custom pallet name
-
-\# Pallet
-
-// Add simple description
-
-// Include the following links that shows what trait needs to be implemented to use the pallet
-// and the supported dispatchables that are documented in the Call enum.
-
-- \[`::Trait`](https://docs.rs/pallet-example/latest/pallet_example/trait.Trait.html)
-- \[`Call`](https://docs.rs/pallet-example/latest/pallet_example/enum.Call.html)
-- \[`Module`](https://docs.rs/pallet-example/latest/pallet_example/struct.Module.html)
-
-\## Overview
-
-
-// Short description of pallet's purpose.
-// Links to Traits that should be implemented.
-// What this pallet is for.
-// What functionality the pallet provides.
-// When to use the pallet (use case examples).
-// How it is used.
-// Inputs it uses and the source of each input.
-// Outputs it produces.
-
-
-
-
-\## Terminology
-
-// Add terminology used in the custom pallet. Include concepts, storage items, or actions that you think
-// deserve to be noted to give context to the rest of the documentation or pallet usage. The author needs to
-// use some judgment about what is included. We don't want a list of every storage item nor types - the user
-// can go to the code for that. For example, "transfer fee" is obvious and should not be included, but
-// "free balance" and "reserved balance" should be noted to give context to the pallet.
-// Please do not link to outside resources. The reference docs should be the ultimate source of truth.
-
-
-
-\## Goals
-
-// Add goals that the custom pallet is designed to achieve.
-
-
-
-\### Scenarios
-
-
-
-\####
-
-// Describe requirements prior to interacting with the custom pallet.
-// Describe the process of interacting with the custom pallet for this scenario and public API functions used.
-
-\## Interface
-
-\### Supported Origins
-
-// What origins are used and supported in this pallet (root, signed, none)
-// i.e. root when \`ensure_root\` used
-// i.e. none when \`ensure_none\` used
-// i.e. signed when \`ensure_signed\` used
-
-\`inherent\`
-
-
-
-
-\### Types
-
-// Type aliases. Include any associated types and where the user would typically define them.
-
-\`ExampleType\`
-
-
-
-// Reference documentation of aspects such as `storageItems` and `dispatchable` functions should only be
-// included in the https://docs.rs Rustdocs for Substrate and not repeated in the README file.
-
-\### Dispatchable Functions
-
-
-
-// A brief description of dispatchable functions and a link to the rustdoc with their actual documentation.
-
-// MUST have link to Call enum
-// MUST have origin information included in function doc
-// CAN have more info up to the user
-
-\### Public Functions
-
-
-
-// A link to the rustdoc and any notes about usage in the pallet, not for specific functions.
-// For example, in the Balances Pallet: "Note that when using the publicly exposed functions,
-// you (the runtime developer) are responsible for implementing any necessary checks
-// (e.g. that the sender is the signer) before calling a function that will affect storage."
-
-
-
-// It is up to the writer of the respective pallet (with respect to how much information to provide).
-
-\#### Public Inspection functions - Immutable (getters)
-
-// Insert a subheading for each getter function signature
-
-\##### \`example_getter_name()\`
-
-// What it returns
-// Why, when, and how often to call it
-// When it could panic or error
-// When safety issues to consider
-
-\#### Public Mutable functions (changing state)
-
-// Insert a subheading for each setter function signature
-
-\##### \`example_setter_name(origin, parameter_name: T::ExampleType)\`
-
-// What state it changes
-// Why, when, and how often to call it
-// When it could panic or error
-// When safety issues to consider
-// What parameter values are valid and why
-
-\### Storage Items
-
-// Explain any storage items included in this pallet
-
-\### Digest Items
-
-// Explain any digest items included in this pallet
-
-\### Inherent Data
-
-// Explain what inherent data (if any) is defined in the pallet and any other related types
-
-\### Events:
-
-// Insert events for this pallet if any
-
-\### Errors:
-
-// Explain what generates errors
-
-\## Usage
-
-// Insert 2-3 examples of usage and code snippets that show how to
-// use Pallet in a custom pallet.
-
-\### Prerequisites
-
-// Show how to include necessary imports for and derive
-// your pallet configuration trait with the `INSERT_CUSTOM_PALLET_NAME` trait.
-
-\```rust
-use ;
-
-pub trait Config: ::Config { }
-\```
-
-\### Simple Code Snippet
-
-// Show a simple example (e.g. how to query a public getter function of )
-
-\### Example from FRAME
-
-// Show a usage example in an actual runtime
-
-// See:
-// - Substrate TCR https://github.com/parity-samples/substrate-tcr
-// - Substrate Kitties https://shawntabrizi.github.io/substrate-collectables-workshop/#/
-
-\## Genesis Config
-
-
-
-\## Dependencies
-
-// Dependencies on other FRAME pallets and the genesis config should be mentioned,
-// but not the Rust Standard Library.
-// Genesis configuration modifications that may be made to incorporate this pallet
-// Interaction with other pallets
-
-
-
-\## Related Pallets
-
-// Interaction with other pallets in the form of a bullet point list
-
-\## References
-
-
-
-// Links to reference material, if applicable. For example, Phragmen, W3F research, etc.
-// that the implementation is based on.
-
-
-License: Unlicense
+License: Apache-2.0
diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs
new file mode 100644
index 0000000000000..490a81632ce9d
--- /dev/null
+++ b/frame/transaction-storage/src/benchmarking.rs
@@ -0,0 +1,141 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2021 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.
+
+//! Benchmarks for transction-storage Pallet
+
+#![cfg(feature = "runtime-benchmarks")]
+
+use sp_std::*;
+use super::*;
+use sp_runtime::traits::{Zero, One, Bounded};
+use frame_system::{RawOrigin, Pallet as System, EventRecord};
+use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite};
+use frame_support::{traits::{Currency}};
+
+use crate::Pallet as TransactionStorage;
+use crate::mock::{run_to_block, setup};
+
+const MAX_EXTRINSICS: u32 = 100;
+
+const PROOF: &[u8] = &hex_literal::hex!("
+ 0104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000014cd0780ffff80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe8
+ 7d12a3662c4c0080e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb
+ 13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2
+ f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f
+ 1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f
+ 3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a47
+ 8e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cf
+ f93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e31
+ 6a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f
+ 53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c8
+ 0e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4cbd05807777809a5d7a720ce5f9d9a012
+ fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf
+ 3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9
+ a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062d
+ c1cf3ac289390ae4c00809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a
+ 3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c
+ 4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bc
+ bf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce
+ 186c4ddc53f118e0ddd4decd8cccd0780ffff8081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb0
+ 3bdb31008081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253
+ 515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa139
+ 8e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5
+ f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3a
+ a1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2b
+ a8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f32
+ 2d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa
+ 9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f0
+ 2f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b82
+ 5bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb31cd0780ffff80b4f23ac50c8e67d9b280f2b31a
+ 5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd1885
+ 44c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2
+ b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd
+ 188544c5f9b0080b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9
+ b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84
+ d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e
+ 67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977aca
+ ac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac5
+ 0c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b89297
+ 7acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b104401
+ 0000
+");
+
+type BalanceOf = <::Currency as Currency<::AccountId>>::Balance;
+
+fn assert_last_event(generic_event: ::Event) {
+ let events = System::::events();
+ let system_event: ::Event = generic_event.into();
+ let EventRecord { event, .. } = &events[events.len() - 1];
+ assert_eq!(event, &system_event);
+}
+
+benchmarks! {
+ store {
+ let l in 1 .. MAX_DATA_SIZE;
+ setup::()?;
+ let caller: T::AccountId = whitelisted_caller();
+ T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value());
+ }: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize])
+ verify {
+ assert!(TransactionRoots::::get(T::BlockNumber::one(), 0u32).is_some());
+ assert_last_event::(Event::Stored(0).into());
+ }
+
+ renew {
+ setup::()?;
+ let caller: T::AccountId = whitelisted_caller();
+ T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value());
+ TransactionStorage::::store(
+ RawOrigin::Signed(caller.clone()).into(),
+ vec![0u8; MAX_DATA_SIZE as usize]
+ )?;
+ }: _(RawOrigin::Signed(caller.clone()), T::BlockNumber::zero(), 0)
+ verify {
+ assert_last_event::(Event::Renewed(1).into());
+ }
+
+ check_proof_max {
+ setup::()?;
+ run_to_block::(1);
+ let caller: T::AccountId = whitelisted_caller();
+ T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value());
+ for _ in 0 .. MAX_EXTRINSICS {
+ TransactionStorage::::store(
+ RawOrigin::Signed(caller.clone()).into(),
+ vec![0u8; MAX_DATA_SIZE as usize]
+ )?;
+ }
+ run_to_block::(11);
+ let random_hash = [0u8];
+ let mut encoded_proof = PROOF;
+ let proof = sp_storage_proof::StorageProof::decode(&mut encoded_proof).unwrap();
+ }: check_proof(RawOrigin::None, Some(proof))
+ verify {
+ assert_last_event::(Event::ProofChecked.into());
+ }
+}
+
+impl_benchmark_test_suite!(
+ TransactionStorage,
+ crate::mock::runtime::new_test_ext(),
+ crate::mock::runtime::Test,
+);
diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs
index c5805092ab2db..fd98870fc0914 100644
--- a/frame/transaction-storage/src/lib.rs
+++ b/frame/transaction-storage/src/lib.rs
@@ -17,10 +17,16 @@
//! Transaction storage pallet. Indexes transactions and manages storage proofs.
-
// Ensure we're `no_std` when compiling for Wasm.
#![cfg_attr(not(feature = "std"), no_std)]
+#[cfg(any(test, feature = "runtime-benchmarks"))]
+mod mock;
+#[cfg(test)]
+mod tests;
+mod benchmarking;
+pub mod weights;
+
use frame_support::{
traits::{ReservableCurrency, Currency},
dispatch::{Dispatchable, GetDispatchInfo},
@@ -28,50 +34,44 @@ use frame_support::{
use sp_std::prelude::*;
use sp_std::{result};
use codec::{Encode, Decode};
-use sp_runtime::{
- traits::{
- Saturating, BlakeTwo256, Hash, Zero,
- },
-};
-use sp_storage_proof::StorageProof;
+use sp_runtime::traits::{Saturating, BlakeTwo256, Hash, Zero};
+use sp_storage_proof::{StorageProof, DEFAULT_STORAGE_PERIOD};
/// A type alias for the balance type from this pallet's point of view.
type BalanceOf = <::Currency as Currency<::AccountId>>::Balance;
// Re-export pallet items so that they can be accessed from the crate namespace.
pub use pallet::*;
+pub use weights::WeightInfo;
const CHUNK_SIZE: usize = sp_storage_proof::CHUNK_SIZE;
+/// Maximum bytes that can be storead in one transaction.
+// Increasing it further also requires raising the allocator limit.
+pub const MAX_DATA_SIZE: u32 = 8 * 1024 * 1024;
-#[derive(Encode, Decode, sp_runtime::RuntimeDebug)]
+#[derive(Encode, Decode, sp_runtime::RuntimeDebug, PartialEq, Eq)]
pub struct TransactionInfo {
chunk_root: ::Output,
content_hash: ::Output,
size: u32,
}
-// Definition of the pallet logic, to be aggregated at runtime definition through
-// `construct_runtime`.
#[frame_support::pallet]
pub mod pallet {
- // Import various types used to declare pallet in scope.
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use super::*;
- /// Our pallet's configuration trait. All our types and constants go in here. If the
- /// pallet is dependent on specific other pallets, then their configuration traits
- /// should be added to our implied traits list.
- ///
- /// `frame_system::Config` should always be included.
#[pallet::config]
- pub trait Config: pallet_balances::Config + frame_system::Config {
+ pub trait Config: frame_system::Config {
/// The overarching event type.
type Event: From> + IsType<::Event>;
/// A dispatchable call.
type Call: Parameter + Dispatchable + GetDispatchInfo + From>;
/// The currency trait.
type Currency: ReservableCurrency;
+ /// Weight information for extrinsics in this pallet.
+ type WeightInfo: WeightInfo;
}
#[pallet::error]
@@ -101,15 +101,16 @@ pub mod pallet {
#[pallet::hooks]
impl Hooks> for Pallet {
fn on_initialize(_n: T::BlockNumber) -> Weight {
+ // This will be cleared in in `on_finalize`
>::put(0);
0
}
fn on_finalize(n: T::BlockNumber) {
>::insert(n, >::get().unwrap_or(0));
- // Drop obsolete roots
>::kill();
- let period = >::get().unwrap();
+ // Drop obsolete roots
+ let period = >::get().unwrap_or(DEFAULT_STORAGE_PERIOD.into());
let obsolete = n.saturating_sub(period);
if obsolete > Zero::zero() {
>::remove_prefix(obsolete);
@@ -120,7 +121,13 @@ pub mod pallet {
#[pallet::call]
impl Pallet {
- #[pallet::weight(1)]
+ /// Index and store data on chain. Minimum data size is 1 bytes, maxmum is `MAX_DATA_SIZE`.
+ /// Data will be removed after `STORAGE_PERIOD` blocks, unless `renew` is called.
+ /// #
+ /// - n*log(n) of data size, as all data is pushed to an in-memory trie.
+ /// Additionally contains a DB write.
+ /// #
+ #[pallet::weight(T::WeightInfo::store(data.len() as u32))]
pub(super) fn store(
origin: OriginFor,
data: Vec,
@@ -143,14 +150,20 @@ pub mod pallet {
size: data.len() as u32,
content_hash: content_hash.into(),
});
+ Self::deposit_event(Event::Stored(counter));
counter += 1;
>::put(counter);
-
- Self::deposit_event(Event::Stored);
Ok(().into())
}
- #[pallet::weight(1)]
+ /// Renew previously stored data. Parameters are the block number that contains
+ /// previous `store` or `renew` call and transaction index within that block.
+ /// Transaction index is emitted in the `Stored` or `Renewed` event.
+ /// Applies same fees as `store`.
+ /// #
+ /// - Constant with a single DB read.
+ /// #
+ #[pallet::weight(T::WeightInfo::renew())]
pub(super) fn renew(
origin: OriginFor,
block: T::BlockNumber,
@@ -165,21 +178,27 @@ pub mod pallet {
let mut counter = >::get().unwrap_or(0);
let block_num = >::block_number();
>::insert(block_num, counter, info);
+ Self::deposit_event(Event::Renewed(counter));
counter += 1;
>::put(counter);
-
- Self::deposit_event(Event::Renewed);
Ok(().into())
}
- #[pallet::weight(1)]
- fn check_proof(
+ /// Check storage proof for block number `block_number() - StoragePeriod`.
+ /// If such block does not exist the proof is expected to be `None`.
+ /// #
+ /// - Linear w.r.t the number of indexed transactions in the proved block for random probing.
+ /// There's a DB read for each transaction.
+ /// Here we assume a maximum of 100 probed transactions.
+ /// #
+ #[pallet::weight(T::WeightInfo::check_proof_max())]
+ pub(super) fn check_proof(
origin: OriginFor,
proof: Option,
) -> DispatchResultWithPostInfo {
ensure_none(origin)?;
let number = >::block_number();
- let period = >::get().unwrap();
+ let period = >::get().unwrap_or(DEFAULT_STORAGE_PERIOD.into());
let target_number = number.saturating_sub(period);
if target_number.is_zero() {
ensure!(proof.is_none(), Error::::UnexpectedProof);
@@ -189,7 +208,8 @@ pub mod pallet {
let mut total_chunks = 0;
for t in 0 .. transaction_count {
match >::get(target_number, t) {
- Some(info) => total_chunks += ((info.size as u64 + CHUNK_SIZE as u64 - 1) / CHUNK_SIZE as u64) as u32,
+ Some(info) => total_chunks +=
+ ((info.size as u64 + CHUNK_SIZE as u64 - 1) / CHUNK_SIZE as u64) as u32,
None => break,
}
}
@@ -205,10 +225,11 @@ pub mod pallet {
let (info, chunk_index) = loop {
match >::get(target_number, t) {
Some(info) => {
- total_chunks += ((info.size as u64 + CHUNK_SIZE as u64 - 1) / CHUNK_SIZE as u64) as u32;
- if total_chunks >= selected_chunk_index {
- break (info, total_chunks - selected_chunk_index)
+ let chunks = ((info.size as u64 + CHUNK_SIZE as u64 - 1) / CHUNK_SIZE as u64) as u32;
+ if total_chunks + chunks >= selected_chunk_index {
+ break (info, selected_chunk_index - total_chunks)
}
+ total_chunks += chunks;
},
None => Err(Error::::MissingStateData)?,
}
@@ -219,11 +240,12 @@ pub mod pallet {
sp_io::trie::blake2_256_verity_proof(
info.chunk_root,
&proof.proof,
- &(chunk_index as u32).to_be_bytes(),
+ &sp_storage_proof::encode_index(chunk_index),
&proof.chunk,
),
Error::::InvalidProof
);
+ Self::deposit_event(Event::ProofChecked);
Ok(().into())
}
}
@@ -231,8 +253,12 @@ pub mod pallet {
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event {
- Stored,
- Renewed,
+ /// Stored data under specified index.
+ Stored(u32),
+ /// Renewed data under specified index.
+ Renewed(u32),
+ /// Storage proof was successfully checked.
+ ProofChecked,
}
/// Collection of extrinsic storage roots for the current block.
@@ -260,11 +286,14 @@ pub mod pallet {
#[pallet::storage]
#[pallet::getter(fn byte_fee)]
+ /// Storage fee per byte.
pub(super) type ByteFee = StorageValue<_, BalanceOf>;
#[pallet::storage]
pub(super) type Counter = StorageValue<_, u32>;
+ /// Storage period for data in blocks. Should match `sp_storage_proof::DEFAULT_STORAGE_PERIOD`
+ /// for block authoring.
#[pallet::storage]
pub(super) type StoragePeriod = StorageValue<_, T::BlockNumber>;
@@ -320,107 +349,3 @@ pub mod pallet {
}
}
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use frame_support::{
- assert_ok, parameter_types,
- weights::{DispatchInfo, GetDispatchInfo}, traits::{OnInitialize, OnFinalize}
- };
- use sp_core::H256;
- // The testing primitives are very useful for avoiding having to work with signatures
- // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required.
- use sp_runtime::{
- testing::Header, BuildStorage,
- traits::{BlakeTwo256, IdentityLookup},
- };
- // Reexport crate as its pallet name for construct_runtime.
- use crate as pallet_transaction_storage;
-
- type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
- type Block = frame_system::mocking::MockBlock;
-
- // For testing the pallet, we construct a mock runtime.
- frame_support::construct_runtime!(
- pub enum Test where
- Block = Block,
- NodeBlock = Block,
- UncheckedExtrinsic = UncheckedExtrinsic,
- {
- System: frame_system::{Pallet, Call, Config, Storage, Event},
- Balances: pallet_balances::{Pallet, Call, Storage, Config, Event},
- TransactionStorage: pallet_transaction_storage::{Pallet, Call, Storage, Config, Inherent, Event},
- }
- );
-
- parameter_types! {
- pub const BlockHashCount: u64 = 250;
- pub BlockWeights: frame_system::limits::BlockWeights =
- frame_system::limits::BlockWeights::simple_max(1024);
- }
- impl frame_system::Config for Test {
- type BaseCallFilter = ();
- type BlockWeights = ();
- type BlockLength = ();
- type DbWeight = ();
- type Origin = Origin;
- type Index = u64;
- type BlockNumber = u64;
- type Hash = H256;
- type Call = Call;
- type Hashing = BlakeTwo256;
- type AccountId = u64;
- type Lookup = IdentityLookup;
- type Header = Header;
- type Event = Event;
- type BlockHashCount = BlockHashCount;
- type Version = ();
- type PalletInfo = PalletInfo;
- type AccountData = pallet_balances::AccountData;
- type OnNewAccount = ();
- type OnKilledAccount = ();
- type SystemWeightInfo = ();
- type SS58Prefix = ();
- }
- parameter_types! {
- pub const ExistentialDeposit: u64 = 1;
- }
- impl pallet_balances::Config for Test {
- type MaxLocks = ();
- type Balance = u64;
- type DustRemoval = ();
- type Event = Event;
- type ExistentialDeposit = ExistentialDeposit;
- type AccountStore = System;
- type WeightInfo = ();
- }
- impl Config for Test {
- type Event = Event;
- type Call = Call;
- type Currency = Balances;
- }
-
- // This function basically just builds a genesis storage key/value store according to
- // our desired mockup.
- pub fn new_test_ext() -> sp_io::TestExternalities {
- let t = GenesisConfig {
- // We use default for brevity, but you can configure as desired if needed.
- frame_system: Default::default(),
- pallet_balances: Default::default(),
- pallet_transaction_storage: pallet_transaction_storage::GenesisConfig::default(),
- }.build_storage().unwrap();
- t.into()
- }
-
- #[test]
- fn stores_transaction() {
- let mut ext = new_test_ext();
- let data = vec![1u8, 2u8, 3u8];
- ext.execute_with(|| {
- assert_ok!(TransactionStorage::store(Origin::signed(1), data));
- });
- assert!(ext.overlayed_changes().transaction_index_ops().len() == 1);
- }
-}
diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs
new file mode 100644
index 0000000000000..c91e9afcfe619
--- /dev/null
+++ b/frame/transaction-storage/src/mock.rs
@@ -0,0 +1,148 @@
+// This file is part of Substrate.
+
+// Copyright (C) 2019-2021 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.
+
+//! Test environment for transaction-storage pallet.
+
+use crate as pallet_transaction_storage;
+use crate::Config;
+
+use frame_support::{
+ traits::{OnInitialize, OnFinalize, Currency},
+};
+use sp_runtime::traits::One;
+
+type BalanceOf = <::Currency as Currency<::AccountId>>::Balance;
+
+#[cfg(test)]
+pub mod runtime {
+ use super::*;
+ use sp_core::H256;
+ use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::Header, BuildStorage};
+ use frame_support::parameter_types;
+ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
+ pub type Block = frame_system::mocking::MockBlock;
+
+
+ // Configure a mock runtime to test the pallet.
+ frame_support::construct_runtime!(
+ pub enum Test where
+ Block = Block,
+ NodeBlock = Block,
+ UncheckedExtrinsic = UncheckedExtrinsic,
+ {
+ System: frame_system::{Pallet, Call, Config, Storage, Event},
+ Balances: pallet_balances::{Pallet, Call, Config, Storage, Event},
+ TransactionStorage: pallet_transaction_storage::{
+ Pallet, Call, Storage, Config, Inherent, Event
+ },
+ }
+ );
+
+ parameter_types! {
+ pub const BlockHashCount: u64 = 250;
+ pub const SS58Prefix: u8 = 42;
+ }
+
+ impl frame_system::Config for Test {
+ type BaseCallFilter = ();
+ type BlockWeights = ();
+ type BlockLength = ();
+ type Origin = Origin;
+ type Call = Call;
+ type Index = u64;
+ type BlockNumber = u64;
+ type Hash = H256;
+ type Hashing = BlakeTwo256;
+ type AccountId = u64;
+ type Lookup = IdentityLookup;
+ type Header = Header;
+ type Event = Event;
+ type BlockHashCount = BlockHashCount;
+ type DbWeight = ();
+ type Version = ();
+ type PalletInfo = PalletInfo;
+ type AccountData = pallet_balances::AccountData;
+ type OnNewAccount = ();
+ type OnKilledAccount = ();
+ type SystemWeightInfo = ();
+ type SS58Prefix = SS58Prefix;
+ type OnSetCode = ();
+ }
+
+ parameter_types! {
+ pub const ExistentialDeposit: u64 = 1;
+ }
+
+ impl pallet_balances::Config for Test {
+ type Balance = u64;
+ type DustRemoval = ();
+ type Event = Event;
+ type ExistentialDeposit = ExistentialDeposit;
+ type AccountStore = System;
+ type WeightInfo = ();
+ type MaxLocks = ();
+ }
+
+ parameter_types! {
+ pub IgnoredIssuance: u64 = Balances::total_balance(&0); // Account zero is ignored.
+ pub const QueueCount: u32 = 3;
+ pub const MaxQueueLen: u32 = 3;
+ pub const FifoQueueLen: u32 = 1;
+ pub const Period: u64 = 3;
+ pub const MinFreeze: u64 = 2;
+ pub const IntakePeriod: u64 = 2;
+ pub const MaxIntakeBids: u32 = 2;
+ }
+
+ impl pallet_transaction_storage::Config for Test {
+ type Event = Event;
+ type Call = Call;
+ type Currency = Balances;
+ type WeightInfo = ();
+ }
+
+ pub fn new_test_ext() -> sp_io::TestExternalities {
+ let t = GenesisConfig {
+ frame_system: Default::default(),
+ pallet_balances: pallet_balances::GenesisConfig:: {
+ balances: vec![(1, 1000000000), (2, 100), (3, 100), (4, 100)]
+ },
+ pallet_transaction_storage: pallet_transaction_storage::GenesisConfig::default(),
+ }.build_storage().unwrap();
+ t.into()
+ }
+
+}
+
+pub fn run_to_block(n: u32) {
+ while frame_system::Pallet::::block_number() < (n as u32).into() {
+ pallet_transaction_storage::Pallet::::on_finalize(frame_system::Pallet::::block_number());
+ frame_system::Pallet::::on_finalize(frame_system::Pallet::::block_number());
+ frame_system::Pallet::