diff --git a/Cargo.lock b/Cargo.lock index ca965102f9170..a959ef0c98433 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15964,6 +15964,7 @@ dependencies = [ "sp-storage 19.0.0", "sp-timestamp", "sp-transaction-pool", + "sp-transaction-storage-proof", "sp-version", "sp-weights", "staging-chain-spec-builder", @@ -23568,6 +23569,7 @@ dependencies = [ "async-trait", "parity-scale-codec", "scale-info", + "sp-api", "sp-core 28.0.0", "sp-inherents", "sp-runtime", diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 7c111579f0672..799d9b378efe1 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -125,3 +125,13 @@ try-runtime = [ "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] + +# Enables `TransactionIndex` host functions for parachain validation +# without requiring maintenance of a transaction index. +# However, the host environment (polkadot-prepare/execute-worker) still expects these functions to exist, +# so we provide a replacement no-op implementation gated by this feature. +# +# Used by: `validate_block::implementation::validate_block`. +# +# Note: The parachain collator software is expected to use/include `transaction_index::HostFunctions`. +transaction-index = [] diff --git a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs index 32351a318f3ca..3a94b4a77ed3b 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs @@ -122,6 +122,10 @@ where sp_io::offchain_index::host_clear.replace_implementation(host_offchain_index_clear), cumulus_primitives_proof_size_hostfunction::storage_proof_size::host_storage_proof_size .replace_implementation(host_storage_proof_size), + #[cfg(feature = "transaction-index")] + sp_io::transaction_index::host_index.replace_implementation(host_transaction_index_index), + #[cfg(feature = "transaction-index")] + sp_io::transaction_index::host_renew.replace_implementation(host_transaction_index_renew), ); let block_data = codec::decode_from_bytes::>(block_data) @@ -230,7 +234,6 @@ where if overlay.storage(well_known_keys::CODE).is_some() && num_blocks > 1 { panic!("When applying a runtime upgrade, only one block per PoV is allowed. Received {num_blocks}.") } - run_with_externalities_and_recorder::( &backend, &mut Default::default(), @@ -548,3 +551,21 @@ fn host_default_child_storage_next_key(storage_key: &[u8], key: &[u8]) -> Option fn host_offchain_index_set(_key: &[u8], _value: &[u8]) {} fn host_offchain_index_clear(_key: &[u8]) {} + +/// Parachain validation does not require maintaining a transaction index, +/// and indexing transactions does **not** contribute to the parachain state. +/// However, the host environment still expects this function to exist, +/// so we provide a no-op implementation. +#[cfg(feature = "transaction-index")] +fn host_transaction_index_index(_extrinsic: u32, _size: u32, _context_hash: [u8; 32]) { + // No-op host function used during parachain validation. +} + +/// Parachain validation does not require maintaining a transaction index, +/// and indexing transactions does **not** contribute to the parachain state. +/// However, the host environment still expects this function to exist, +/// so we provide a no-op implementation. +#[cfg(feature = "transaction-index")] +fn host_transaction_index_renew(_extrinsic: u32, _context_hash: [u8; 32]) { + // No-op host function used during parachain validation. +} diff --git a/cumulus/polkadot-omni-node/lib/Cargo.toml b/cumulus/polkadot-omni-node/lib/Cargo.toml index 3e01fa6ec1680..4ee8b868988be 100644 --- a/cumulus/polkadot-omni-node/lib/Cargo.toml +++ b/cumulus/polkadot-omni-node/lib/Cargo.toml @@ -80,6 +80,7 @@ sp-statement-store = { workspace = true, default-features = true } sp-storage = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } sp-transaction-pool = { workspace = true, default-features = true } +sp-transaction-storage-proof = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } sp-weights = { workspace = true, default-features = true } substrate-frame-rpc-system = { workspace = true, default-features = true } diff --git a/cumulus/polkadot-omni-node/lib/src/common/mod.rs b/cumulus/polkadot-omni-node/lib/src/common/mod.rs index aaa37486f2c58..fc9717063880c 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/mod.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/mod.rs @@ -42,6 +42,7 @@ use sp_runtime::{ use sp_session::SessionKeys; use sp_statement_store::runtime_api::ValidateStatement; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; +use sp_transaction_storage_proof::runtime_api::TransactionStorageApi; use std::{fmt::Debug, path::PathBuf, str::FromStr}; pub trait NodeBlock: @@ -74,6 +75,7 @@ pub trait NodeRuntimeApi: + CollectCollationInfo + ValidateStatement + GetParachainInfo + + TransactionStorageApi + RelayParentOffsetApi + Sized { @@ -90,6 +92,7 @@ impl NodeRuntimeApi for T where + CollectCollationInfo + ValidateStatement + GetParachainInfo + + TransactionStorageApi { } diff --git a/cumulus/polkadot-omni-node/lib/src/common/spec.rs b/cumulus/polkadot-omni-node/lib/src/common/spec.rs index bc4acf3ba9cf5..f904873b99e97 100644 --- a/cumulus/polkadot-omni-node/lib/src/common/spec.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/spec.rs @@ -39,7 +39,7 @@ use cumulus_client_service::{ use cumulus_primitives_core::{BlockT, GetParachainInfo, ParaId}; use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; use futures::FutureExt; -use log::info; +use log::{debug, info}; use parachains_common_types::Hash; use polkadot_primitives::CollatorPair; use prometheus_endpoint::Registry; @@ -61,6 +61,13 @@ use sp_keystore::KeystorePtr; use sp_runtime::traits::AccountIdConversion; use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; +// Override default idle connection timeout of 10 seconds to give IPFS clients more +// time to query data over Bitswap. This is needed when manually adding our node +// to a swarm of an IPFS node, because the IPFS node doesn't keep any active +// substreams with us and our node closes a connection after +// `idle_connection_timeout`. +const IPFS_WORKAROUND_TIMEOUT: Duration = Duration::from_secs(3600); + pub(crate) trait BuildImportQueue< Block: BlockT, RuntimeApi, @@ -326,7 +333,16 @@ pub(crate) trait NodeSpec: BaseNodeSpec { Net: NetworkBackend, { let fut = async move { - let parachain_config = prepare_node_config(parachain_config); + let mut parachain_config = prepare_node_config(parachain_config); + + // Some additional customization in relation to starting the node as an ipfs server. + if parachain_config.network.idle_connection_timeout < IPFS_WORKAROUND_TIMEOUT && + parachain_config.network.ipfs_server + { + debug!("Overriding `config.network.idle_connection_timeout` to allow long-lived connections with IPFS nodes. The old value: {:?} is replaced by: {:?}.", parachain_config.network.idle_connection_timeout, IPFS_WORKAROUND_TIMEOUT); + parachain_config.network.idle_connection_timeout = IPFS_WORKAROUND_TIMEOUT; + } + let parachain_public_addresses = parachain_config.network.public_addresses.clone(); let parachain_fork_id = parachain_config.chain_spec.fork_id().map(ToString::to_string); let advertise_non_global_ips = parachain_config.network.allow_non_globals_in_dht; diff --git a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs index 77fa28d4418cc..56eb3d2ae7602 100644 --- a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs +++ b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs @@ -248,6 +248,12 @@ macro_rules! impl_node_runtime_apis { unimplemented!() } } + + impl sp_transaction_storage_proof::runtime_api::TransactionStorageApi<$block> for $runtime { + fn retention_period() -> sp_runtime::traits::NumberFor<$block> { + unimplemented!() + } + } } }; } diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs index 9cd0246ceff56..682e9df1cedd1 100644 --- a/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs +++ b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs @@ -68,7 +68,7 @@ use sc_service::{Configuration, Error, PartialComponents, TaskManager}; use sc_telemetry::TelemetryHandle; use sc_transaction_pool::TransactionPoolHandle; use sc_transaction_pool_api::OffchainTransactionPoolFactory; -use sp_api::ProvideRuntimeApi; +use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_consensus::Environment; use sp_core::traits::SpawnEssentialNamed; use sp_inherents::CreateInherentDataProviders; @@ -77,6 +77,7 @@ use sp_runtime::{ app_crypto::AppCrypto, traits::{Block as BlockT, Header as HeaderT, UniqueSaturatedInto}, }; +use sp_transaction_storage_proof::runtime_api::TransactionStorageApi; use std::{marker::PhantomData, sync::Arc, time::Duration}; struct Verifier { @@ -596,8 +597,28 @@ where ); let client_for_aura = client.clone(); + let client_clone = client.clone(); let params = SlotBasedParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + create_inherent_data_providers: move |parent, ()| { + let client_clone = client_clone.clone(); + async move { + let has_tx_storage_api = client_clone + .runtime_api() + .has_api::>(parent) + .unwrap_or(false); + if has_tx_storage_api { + let storage_proof = + sp_transaction_storage_proof::registration::new_data_provider( + &*client_clone, + &parent, + client_clone.runtime_api().retention_period(parent)?, + )?; + Ok(vec![storage_proof]) + } else { + Ok(vec![]) + } + } + }, block_import, para_client: client.clone(), para_backend: backend.clone(), @@ -623,7 +644,6 @@ where // We have a separate function only to be able to use `docify::export` on this piece of // code. - Self::launch_slot_based_collator(params); Ok(()) @@ -721,10 +741,30 @@ where client.clone(), ); + let client_clone = client.clone(); let params = aura::ParamsWithExport { export_pov: node_extra_args.export_pov, params: AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + create_inherent_data_providers: move |parent, ()| { + let client_clone = client_clone.clone(); + async move { + let has_tx_storage_api = client_clone + .runtime_api() + .has_api::>(parent) + .unwrap_or(false); + if has_tx_storage_api { + let storage_proof = + sp_transaction_storage_proof::registration::new_data_provider( + &*client_clone, + &parent, + client_clone.runtime_api().retention_period(parent)?, + )?; + Ok(vec![storage_proof]) + } else { + Ok(vec![]) + } + } + }, block_import, para_client: client.clone(), para_backend: backend, diff --git a/prdoc/pr_10662.prdoc b/prdoc/pr_10662.prdoc new file mode 100644 index 0000000000000..a45f7f67f1648 --- /dev/null +++ b/prdoc/pr_10662.prdoc @@ -0,0 +1,29 @@ +title: "Bulletin as parachain missing features" +doc: +- audience: Runtime Dev + description: |- + This PR adds the required support and features for running Bulletin as a parachain. It is a top-level PR that merges three partial features: + + 1. Add transaction_index::HostFunctions with NO-OP impl to the cumulus ParachainSystem validate_block for polkadot-prepare/execute-worker + 2. Add custom inherent provider for pallet-transaction-storage to omni node + 3. Configurable RetentionPeriod feeded to the inherent provider over runtime API + + This PR also refactors `pallet-transaction-storage` and `sp-transaction-storage-proof` (the `new_data_provider` inherent provider), both of which rely on a hard-coded `DEFAULT_RETENTION_PERIOD`. This PR: + - adds a new configurable argument `retention_period` to the `new_data_provider` + - introduces the `TransactionStorageApi::retention_period` runtime API, which the runtime can specify arbitrary + - provides an example of using `new_data_provider`, with the node client calling the runtime API when constructing inherent provider data +- audience: [ Node Dev, Node Operator ] + description: | + * Node developers/operators could enable the transaction storage inherent data provider setup by using --enable-tx-storage-idp flag. This is especially useful in the context of bulletin chain. + * Node developers will set up the network `idle_connection_timeout` to 1h when using `--ipfs-server` flag, again, useful in the context of bulletin chain. +crates: +- name: cumulus-pallet-parachain-system + bump: patch +- name: polkadot-omni-node-lib + bump: major +- name: sp-inherents + bump: minor +- name: sp-transaction-storage-proof + bump: major +- name: pallet-transaction-storage + bump: major diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 0ec655e3fa6ac..eeea8455fb5c9 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -47,6 +47,7 @@ use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_api::ProvideRuntimeApi; use sp_core::crypto::Pair; use sp_runtime::{generic, traits::Block as BlockT, SaturatedConversion}; +use sp_transaction_storage_proof::runtime_api::TransactionStorageApi; use std::{path::Path, sync::Arc}; /// Host functions required for kitchensink runtime and Substrate node. @@ -631,6 +632,8 @@ pub fn new_full_base::Hash>>( sp_transaction_storage_proof::registration::new_data_provider( &*client_clone, &parent, + // Use `unwrap_or` in case the runtime api is not available. + client_clone.runtime_api().retention_period(parent).unwrap_or(100800), )?; Ok((slot, timestamp, storage_proof)) diff --git a/substrate/bin/node/cli/tests/res/default_genesis_config.json b/substrate/bin/node/cli/tests/res/default_genesis_config.json index 85a8057bb60a3..d83392ffd5113 100644 --- a/substrate/bin/node/cli/tests/res/default_genesis_config.json +++ b/substrate/bin/node/cli/tests/res/default_genesis_config.json @@ -100,7 +100,7 @@ "transactionStorage": { "byteFee": 10, "entryFee": 1000, - "storagePeriod": 100800 + "retentionPeriod": 100800 }, "allianceMotion": { "members": [] diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index edb9ed749d8ae..6f1170651bc0c 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3776,6 +3776,12 @@ pallet_revive::impl_runtime_apis_plus_revive_traits!( } } + impl sp_transaction_storage_proof::runtime_api::TransactionStorageApi for Runtime { + fn retention_period() -> NumberFor { + TransactionStorage::retention_period() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index c3ee687bda0a9..f5a2e8923e4eb 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -46,6 +46,7 @@ std = [ "sp-inherents/std", "sp-io/std", "sp-runtime/std", + "sp-transaction-storage-proof/std", "tracing/std", ] runtime-benchmarks = [ diff --git a/substrate/frame/transaction-storage/README.md b/substrate/frame/transaction-storage/README.md index b173c0a84d5a0..62741a0127281 100644 --- a/substrate/frame/transaction-storage/README.md +++ b/substrate/frame/transaction-storage/README.md @@ -2,8 +2,8 @@ Indexes transactions and manages storage proofs. -Allows storing arbitrary data on the chain. Data is automatically removed after `StoragePeriod` blocks, unless the -storage is renewed. Validators must submit proof of storing a random chunk of data for block `N - StoragePeriod` when +Allows storing arbitrary data on the chain. Data is automatically removed after `RetentionPeriod` blocks, unless the +storage is renewed. Validators must submit proof of storing a random chunk of data for block `N - RetentionPeriod` when producing block `N`. # Running a chain @@ -17,7 +17,7 @@ cargo run --release -- build-spec --chain=local > sc_init.json ``` Edit the json chain spec file to customise the chain. The storage chain genesis params are configured in the -`transactionStorage` section. Note that `storagePeriod` is specified in blocks and changing it also requires code +`transactionStorage` section. Note that `retentionPeriod` is specified in blocks and changing it also requires code changes at the moment. Build a raw spec from the init spec. @@ -34,7 +34,7 @@ cargo run --release -- --chain=sc.json -d /tmp/bob --storage-chain --keep-blocks ``` `--storage-chain` enables transaction indexing. `--keep-blocks=100800` enables block pruning. The value here should be -greater or equal than the storage period. `--ipfs-server` enables serving stored content over IPFS. +greater or equal than the retention period. `--ipfs-server` enables serving stored content over IPFS. Once the network is started, any other joining nodes need to sync with `--sync=fast`. Regular sync will fail because block pruning removes old blocks. The chain does not keep full block history. @@ -78,7 +78,7 @@ ipfs swarm connect ipfs block get /ipfs/ > kitten.jpeg ``` -To renew data and prevent it from being disposed after the storage period, use `transactionStorage.renew(block, index)` +To renew data and prevent it from being disposed after the retention period, use `transactionStorage.renew(block, index)` where `block` is the block number of the previous store or renew transaction, and index is the index of that transaction in the block. diff --git a/substrate/frame/transaction-storage/src/benchmarking.rs b/substrate/frame/transaction-storage/src/benchmarking.rs index d65fd667d4ea5..491aed33e00b6 100644 --- a/substrate/frame/transaction-storage/src/benchmarking.rs +++ b/substrate/frame/transaction-storage/src/benchmarking.rs @@ -169,7 +169,7 @@ mod benchmarks { vec![0u8; T::MaxTransactionSize::get() as usize], )?; } - run_to_block::(StoragePeriod::::get() + BlockNumberFor::::one()); + run_to_block::(crate::Pallet::::retention_period() + BlockNumberFor::::one()); let encoded_proof = proof(); let proof = TransactionStorageProof::decode(&mut &*encoded_proof).unwrap(); diff --git a/substrate/frame/transaction-storage/src/lib.rs b/substrate/frame/transaction-storage/src/lib.rs index 62040c9d8966c..253eb2cd06b68 100644 --- a/substrate/frame/transaction-storage/src/lib.rs +++ b/substrate/frame/transaction-storage/src/lib.rs @@ -57,6 +57,9 @@ pub type CreditOf = Credit<::AccountId, ::get(); + let period = Self::retention_period(); let obsolete = n.saturating_sub(period.saturating_add(One::one())); if obsolete > Zero::zero() { weight.saturating_accrue(db_weight.writes(1)); @@ -235,7 +238,7 @@ pub mod pallet { ProofChecked::::take() || { // Proof is not required for early or empty blocks. let number = frame_system::Pallet::::block_number(); - let period = StoragePeriod::::get(); + let period = Self::retention_period(); let target_number = number.saturating_sub(period); target_number.is_zero() || { @@ -264,11 +267,11 @@ pub mod pallet { !T::MaxTransactionSize::get().is_zero(), "MaxTransactionSize must be greater than zero" ); - let default_period = sp_transaction_storage_proof::DEFAULT_STORAGE_PERIOD.into(); - let storage_period = GenesisConfig::::default().storage_period; + let default_period = DEFAULT_RETENTION_PERIOD.into(); + let retention_period = GenesisConfig::::default().retention_period; assert_eq!( - storage_period, default_period, - "GenesisConfig.storage_period must match DEFAULT_STORAGE_PERIOD" + retention_period, default_period, + "GenesisConfig.retention_period must match DEFAULT_RETENTION_PERIOD" ); } } @@ -276,8 +279,8 @@ pub mod pallet { #[pallet::call] impl Pallet { /// Index and store data off chain. Minimum data size is 1 byte, maximum is - /// `MaxTransactionSize`. Data will be removed after `StoragePeriod` blocks, unless `renew` - /// is called. + /// `MaxTransactionSize`. Data will be removed after `RetentionPeriod` blocks, unless + /// `renew` is called. /// /// Emits [`Stored`](Event::Stored) when successful. /// @@ -376,7 +379,7 @@ pub mod pallet { Ok(().into()) } - /// Check storage proof for block number `block_number() - StoragePeriod`. If such a block + /// Check storage proof for block number `block_number() - RetentionPeriod`. If such a block /// does not exist, the proof is expected to be `None`. /// /// ## Complexity @@ -394,7 +397,7 @@ pub mod pallet { // Get the target block metadata. let number = frame_system::Pallet::::block_number(); - let period = StoragePeriod::::get(); + let period = Self::retention_period(); let target_number = number.saturating_sub(period); ensure!(!target_number.is_zero(), Error::::UnexpectedProof); let transactions = @@ -456,10 +459,13 @@ pub mod pallet { /// Storage fee per transaction. pub type EntryFee = StorageValue<_, BalanceOf>; - /// Storage period for data in blocks. Should match `sp_storage_proof::DEFAULT_STORAGE_PERIOD` - /// for block authoring. + /// Number of blocks for which stored data must be retained. + /// + /// Data older than `RetentionPeriod` blocks is eligible for removal unless it + /// has been explicitly renewed. Validators are required to prove possession of + /// data corresponding to block `N - RetentionPeriod` when producing block `N`. #[pallet::storage] - pub type StoragePeriod = StorageValue<_, BlockNumberFor, ValueQuery>; + pub type RetentionPeriod = StorageValue<_, BlockNumberFor, ValueQuery>; // Intermediates #[pallet::storage] @@ -474,7 +480,7 @@ pub mod pallet { pub struct GenesisConfig { pub byte_fee: BalanceOf, pub entry_fee: BalanceOf, - pub storage_period: BlockNumberFor, + pub retention_period: BlockNumberFor, } impl Default for GenesisConfig { @@ -482,7 +488,7 @@ pub mod pallet { Self { byte_fee: 10u32.into(), entry_fee: 1000u32.into(), - storage_period: sp_transaction_storage_proof::DEFAULT_STORAGE_PERIOD.into(), + retention_period: DEFAULT_RETENTION_PERIOD.into(), } } } @@ -492,7 +498,7 @@ pub mod pallet { fn build(&self) { ByteFee::::put(self.byte_fee); EntryFee::::put(self.entry_fee); - StoragePeriod::::put(self.storage_period); + RetentionPeriod::::put(self.retention_period); } } @@ -525,14 +531,18 @@ pub mod pallet { ) -> Option> { Transactions::::get(block) } - /// Get ByteFee storage information from outside of this pallet. + /// Get ByteFee storage information from the outside of this pallet. pub fn byte_fee() -> Option> { ByteFee::::get() } - /// Get EntryFee storage information from outside of this pallet. + /// Get EntryFee storage information from the outside of this pallet. pub fn entry_fee() -> Option> { EntryFee::::get() } + /// Get RetentionPeriod storage information from the outside of this pallet. + pub fn retention_period() -> BlockNumberFor { + RetentionPeriod::::get() + } fn apply_fee(sender: T::AccountId, size: u32) -> DispatchResult { let byte_fee = ByteFee::::get().ok_or(Error::::NotConfigured)?; diff --git a/substrate/frame/transaction-storage/src/mock.rs b/substrate/frame/transaction-storage/src/mock.rs index 25f44b953bfb2..939c7d18ff21c 100644 --- a/substrate/frame/transaction-storage/src/mock.rs +++ b/substrate/frame/transaction-storage/src/mock.rs @@ -68,7 +68,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ..Default::default() }, transaction_storage: pallet_transaction_storage::GenesisConfig:: { - storage_period: 10, + retention_period: 10, byte_fee: 2, entry_fee: 200, }, diff --git a/substrate/primitives/inherents/src/client_side.rs b/substrate/primitives/inherents/src/client_side.rs index bbbb72c0eda01..49822a24e4b98 100644 --- a/substrate/primitives/inherents/src/client_side.rs +++ b/substrate/primitives/inherents/src/client_side.rs @@ -143,3 +143,27 @@ impl InherentDataProvider for Tuple { None } } + +#[async_trait::async_trait] +impl InherentDataProvider for Vec { + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { + for idp in self { + idp.provide_inherent_data(inherent_data).await?; + } + Ok(()) + } + + async fn try_handle_error( + &self, + identifier: &InherentIdentifier, + error: &[u8], + ) -> Option> { + for idp in self { + if let Some(r) = idp.try_handle_error(identifier, error).await { + return Some(r); + } + } + + None + } +} diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index a9040c1249a15..d404875e08b12 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -19,6 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = { optional = true, workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } +sp-api = { workspace = true } sp-core = { optional = true, workspace = true } sp-inherents = { workspace = true } sp-runtime = { workspace = true } @@ -30,6 +31,7 @@ std = [ "async-trait", "codec/std", "scale-info/std", + "sp-api/std", "sp-core/std", "sp-inherents/std", "sp-runtime/std", diff --git a/substrate/primitives/transaction-storage-proof/src/lib.rs b/substrate/primitives/transaction-storage-proof/src/lib.rs index c92197a3fc308..55ea1276e3c1a 100644 --- a/substrate/primitives/transaction-storage-proof/src/lib.rs +++ b/substrate/primitives/transaction-storage-proof/src/lib.rs @@ -20,6 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +pub mod runtime_api; + extern crate alloc; use core::result::Result; @@ -33,8 +35,6 @@ pub use sp_inherents::Error; /// The identifier for the proof inherent. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"tx_proof"; -/// Storage period for data. -pub const DEFAULT_STORAGE_PERIOD: u32 = 100800; /// Proof trie value size. pub const CHUNK_SIZE: usize = 256; @@ -168,15 +168,14 @@ pub mod registration { pub fn new_data_provider( client: &C, parent: &B::Hash, + retention_period: NumberFor, ) -> Result where B: BlockT, C: IndexedBody, { let parent_number = client.number(*parent)?.unwrap_or(Zero::zero()); - let number = parent_number - .saturating_add(One::one()) - .saturating_sub(DEFAULT_STORAGE_PERIOD.into()); + let number = parent_number.saturating_add(One::one()).saturating_sub(retention_period); if number.is_zero() { // Too early to collect proofs. return Ok(InherentDataProvider::new(None)); diff --git a/substrate/primitives/transaction-storage-proof/src/runtime_api.rs b/substrate/primitives/transaction-storage-proof/src/runtime_api.rs new file mode 100644 index 0000000000000..b7d920a8a8f61 --- /dev/null +++ b/substrate/primitives/transaction-storage-proof/src/runtime_api.rs @@ -0,0 +1,28 @@ +// 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. + +//! Runtime API definition for the transaction storage proof processing. + +use sp_runtime::traits::NumberFor; + +sp_api::decl_runtime_apis! { + /// Runtime API trait for transaction storage support. + pub trait TransactionStorageApi { + /// Get the actual value of a retention period in blocks. + fn retention_period() -> NumberFor; + } +}