From b85c5a0df7e53358167c7ce6a3aa3b9900e18476 Mon Sep 17 00:00:00 2001
From: Sebastian Kunert <skunert49@gmail.com>
Date: Thu, 2 May 2024 14:20:51 +0200
Subject: [PATCH] Add PoV-reclaim enablement guide to polkadot-sdk-docs (#4244)

This adds a small guide on how to prepare your parachain for pov-reclaim
usage.
---
 Cargo.lock                                |  7 ++
 docs/sdk/Cargo.toml                       |  7 +-
 docs/sdk/src/guides/enable_pov_reclaim.rs | 84 +++++++++++++++++++++++
 docs/sdk/src/guides/mod.rs                |  3 +
 docs/sdk/src/meta_contributing.rs         |  2 +-
 templates/parachain/node/Cargo.toml       |  1 +
 templates/parachain/node/src/service.rs   |  2 +
 templates/parachain/runtime/Cargo.toml    |  1 +
 templates/parachain/runtime/src/lib.rs    |  1 +
 9 files changed, 106 insertions(+), 2 deletions(-)
 create mode 100644 docs/sdk/src/guides/enable_pov_reclaim.rs

diff --git a/Cargo.lock b/Cargo.lock
index f5b2ee855f5..d72d6229e1a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11786,6 +11786,7 @@ dependencies = [
  "cumulus-primitives-core",
  "cumulus-primitives-parachain-inherent",
  "cumulus-relay-chain-interface",
+ "docify",
  "frame-benchmarking",
  "frame-benchmarking-cli",
  "futures",
@@ -11842,6 +11843,7 @@ dependencies = [
  "cumulus-primitives-core",
  "cumulus-primitives-storage-weight-reclaim",
  "cumulus-primitives-utility",
+ "docify",
  "frame-benchmarking",
  "frame-executive",
  "frame-support",
@@ -13897,8 +13899,11 @@ dependencies = [
 name = "polkadot-sdk-docs"
 version = "0.0.1"
 dependencies = [
+ "cumulus-client-service",
  "cumulus-pallet-aura-ext",
  "cumulus-pallet-parachain-system",
+ "cumulus-primitives-proof-size-hostfunction",
+ "cumulus-primitives-storage-weight-reclaim",
  "docify",
  "frame-executive",
  "frame-support",
@@ -13936,9 +13941,11 @@ dependencies = [
  "sc-consensus-grandpa",
  "sc-consensus-manual-seal",
  "sc-consensus-pow",
+ "sc-executor",
  "sc-network",
  "sc-rpc",
  "sc-rpc-api",
+ "sc-service",
  "scale-info",
  "simple-mermaid",
  "sp-api",
diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml
index 426c5d9de4a..fe53845d849 100644
--- a/docs/sdk/Cargo.toml
+++ b/docs/sdk/Cargo.toml
@@ -51,6 +51,8 @@ sc-consensus-grandpa = { path = "../../substrate/client/consensus/grandpa" }
 sc-consensus-beefy = { path = "../../substrate/client/consensus/beefy" }
 sc-consensus-manual-seal = { path = "../../substrate/client/consensus/manual-seal" }
 sc-consensus-pow = { path = "../../substrate/client/consensus/pow" }
+sc-executor = { path = "../../substrate/client/executor" }
+sc-service = { path = "../../substrate/client/service" }
 
 substrate-wasm-builder = { path = "../../substrate/utils/wasm-builder" }
 
@@ -60,9 +62,12 @@ cumulus-pallet-parachain-system = { path = "../../cumulus/pallets/parachain-syst
 	"parameterized-consensus-hook",
 ] }
 parachain-info = { package = "staging-parachain-info", path = "../../cumulus/parachains/pallets/parachain-info" }
-pallet-aura = { path = "../../substrate/frame/aura", default-features = false }
+cumulus-primitives-proof-size-hostfunction = { path = "../../cumulus/primitives/proof-size-hostfunction" }
+cumulus-client-service = { path = "../../cumulus/client/service" }
+cumulus-primitives-storage-weight-reclaim = { path = "../../cumulus/primitives/storage-weight-reclaim" }
 
 # Pallets and FRAME internals
+pallet-aura = { path = "../../substrate/frame/aura" }
 pallet-timestamp = { path = "../../substrate/frame/timestamp" }
 pallet-balances = { path = "../../substrate/frame/balances" }
 pallet-assets = { path = "../../substrate/frame/assets" }
diff --git a/docs/sdk/src/guides/enable_pov_reclaim.rs b/docs/sdk/src/guides/enable_pov_reclaim.rs
new file mode 100644
index 00000000000..3c0c5fba215
--- /dev/null
+++ b/docs/sdk/src/guides/enable_pov_reclaim.rs
@@ -0,0 +1,84 @@
+//! This guide will teach you how to enable storage weight reclaiming for a parachain. The
+//! explanations in this guide assume a project structure similar to the one detailed in
+//! the [substrate documentation](crate::polkadot_sdk::substrate#anatomy-of-a-binary-crate). Full
+//! technical details are available in the original [pull request](https://github.com/paritytech/polkadot-sdk/pull/3002).
+//!
+//! # What is PoV reclaim?
+//! When a parachain submits a block to a relay chain like Polkadot or Kusama, it sends the block
+//! itself and a storage proof. Together they form the Proof-of-Validity (PoV). The PoV allows the
+//! relay chain to validate the parachain block by re-executing it. Relay chain
+//! validators distribute this PoV among themselves over the network. This distribution is costly
+//! and limits the size of the storage proof. The storage weight dimension of FRAME weights reflects
+//! this cost and limits the size of the storage proof. However, the storage weight determined
+//! during [benchmarking](crate::reference_docs::frame_benchmarking_weight) represents the worst
+//! case. In reality, runtime operations often consume less space in the storage proof. PoV reclaim
+//! offers a mechanism to reclaim the difference between the benchmarked worst-case and the real
+//! proof-size consumption.
+//!
+//!
+//! # How to enable PoV reclaim
+//! ## 1. Add the host function to your node
+//!
+//! To reclaim excess storage weight, a parachain runtime needs the
+//! ability to fetch the size of the storage proof from the node. The reclaim
+//! mechanism uses the
+//! [`storage_proof_size`](cumulus_primitives_proof_size_hostfunction::storage_proof_size)
+//! host function for this purpose. For convenience, cumulus provides
+//! [`ParachainHostFunctions`](cumulus_client_service::ParachainHostFunctions), a set of
+//! host functions typically used by cumulus-based parachains. In the binary crate of your
+//! parachain, find the instantiation of the [`WasmExecutor`](sc_executor::WasmExecutor) and set the
+//! correct generic type.
+//!
+//! This example from the parachain-template shows a type definition that includes the correct
+//! host functions.
+#![doc = docify::embed!("../../templates/parachain/node/src/service.rs", wasm_executor)]
+//!
+//! > **Note:**
+//! >
+//! > If you see error `runtime requires function imports which are not present on the host:
+//! > 'env:ext_storage_proof_size_storage_proof_size_version_1'`, it is likely
+//! > that this step in the guide was not set up correctly.
+//!
+//! ## 2. Enable storage proof recording during import
+//!
+//! The reclaim mechanism reads the size of the currently recorded storage proof multiple times
+//! during block authoring and block import. Proof recording during authoring is already enabled on
+//! parachains. You must also ensure that storage proof recording is enabled during block import.
+//! Find where your node builds the fundamental substrate components by calling
+//! [`new_full_parts`](sc_service::new_full_parts). Replace this
+//! with [`new_full_parts_record_import`](sc_service::new_full_parts_record_import) and
+//! pass `true` as the last parameter to enable import recording.
+#![doc = docify::embed!("../../templates/parachain/node/src/service.rs", component_instantiation)]
+//!
+//! > **Note:**
+//! >
+//! > If you see error `Storage root must match that calculated.` during block import, it is likely
+//! > that this step in the guide was not
+//! > set up correctly.
+//!
+//! ## 3. Add the SignedExtension to your runtime
+//!
+//! In your runtime, you will find a list of SignedExtensions.
+//! To enable the reclaiming,
+//! add [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim)
+//! to that list. For maximum efficiency, make sure that `StorageWeightReclaim` is last in the list.
+//! The extension will check the size of the storage proof before and after an extrinsic execution.
+//! It reclaims the difference between the calculated size and the benchmarked size.
+#![doc = docify::embed!("../../templates/parachain/runtime/src/lib.rs", template_signed_extra)]
+//!
+//! ## Optional: Verify that reclaim works
+//!
+//! Start your node with the log target `runtime::storage_reclaim` set to `trace` to enable full
+//! logging for `StorageWeightReclaim`. The following log is an example from a local testnet. To
+//! trigger the log, execute any extrinsic on the network.
+//!
+//! ```ignore
+//! ...
+//! 2024-04-22 17:31:48.014 TRACE runtime::storage_reclaim: [ferdie] Reclaiming storage weight. benchmarked: 3593, consumed: 265 unspent: 0
+//! ...
+//! ```
+//!
+//! In the above example we see a benchmarked size of 3593 bytes, while the extrinsic only consumed
+//! 265 bytes of proof size. This results in 3328 bytes of reclaim.
+#![deny(rustdoc::broken_intra_doc_links)]
+#![deny(rustdoc::private_intra_doc_links)]
diff --git a/docs/sdk/src/guides/mod.rs b/docs/sdk/src/guides/mod.rs
index 3120f253310..2dc807af8ea 100644
--- a/docs/sdk/src/guides/mod.rs
+++ b/docs/sdk/src/guides/mod.rs
@@ -23,3 +23,6 @@ pub mod cumulus_enabled_parachain;
 /// How to make a given runtime XCM-enabled, capable of sending messages (`Transact`) between itself
 /// and the relay chain to which it is connected.
 pub mod xcm_enabled_parachain;
+
+/// How to enable storage weight reclaiming in a parachain node and runtime.
+pub mod enable_pov_reclaim;
diff --git a/docs/sdk/src/meta_contributing.rs b/docs/sdk/src/meta_contributing.rs
index fcdcea9934b..a029595254c 100644
--- a/docs/sdk/src/meta_contributing.rs
+++ b/docs/sdk/src/meta_contributing.rs
@@ -139,7 +139,7 @@
 //!
 //! ```sh
 //! SKIP_WASM_BUILD=1 \
-//! RUSTDOCFLAGS="--html-in-header $(pwd)/docs/sdk/headers/header.html --extend-css $(pwd)/docs/sdk/headers/theme.css --default-theme=ayu" \
+//! RUSTDOCFLAGS="--html-in-header $(pwd)/docs/sdk/assets/header.html --extend-css $(pwd)/docs/sdk/assets/theme.css --default-theme=ayu" \
 //! cargo doc -p polkadot-sdk-docs --no-deps --open
 //! ```
 //!
diff --git a/templates/parachain/node/Cargo.toml b/templates/parachain/node/Cargo.toml
index 63267acdbca..ed857b4e4b9 100644
--- a/templates/parachain/node/Cargo.toml
+++ b/templates/parachain/node/Cargo.toml
@@ -24,6 +24,7 @@ serde = { features = ["derive"], workspace = true, default-features = true }
 jsonrpsee = { version = "0.22", features = ["server"] }
 futures = "0.3.28"
 serde_json = { workspace = true, default-features = true }
+docify = "0.2.8"
 
 # Local
 parachain-template-runtime = { path = "../runtime" }
diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs
index 20e5b37b41b..ad4689c6e55 100644
--- a/templates/parachain/node/src/service.rs
+++ b/templates/parachain/node/src/service.rs
@@ -39,6 +39,7 @@ use sc_transaction_pool_api::OffchainTransactionPoolFactory;
 use sp_keystore::KeystorePtr;
 use substrate_prometheus_endpoint::Registry;
 
+#[docify::export(wasm_executor)]
 type ParachainExecutor = WasmExecutor<ParachainHostFunctions>;
 
 type ParachainClient = TFullClient<Block, RuntimeApi, ParachainExecutor>;
@@ -61,6 +62,7 @@ pub type Service = PartialComponents<
 ///
 /// Use this macro if you don't actually need the full service, but just the builder in order to
 /// be able to perform chain operations.
+#[docify::export(component_instantiation)]
 pub fn new_partial(config: &Configuration) -> Result<Service, sc_service::Error> {
 	let telemetry = config
 		.telemetry_endpoints
diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml
index 9cd5b7ca599..d15ff2807a6 100644
--- a/templates/parachain/runtime/Cargo.toml
+++ b/templates/parachain/runtime/Cargo.toml
@@ -28,6 +28,7 @@ scale-info = { version = "2.11.1", default-features = false, features = [
 	"derive",
 ] }
 smallvec = "1.11.0"
+docify = "0.2.8"
 
 # Local
 pallet-parachain-template = { path = "../pallets/template", default-features = false }
diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs
index 14af00f9b2c..179a425ca04 100644
--- a/templates/parachain/runtime/src/lib.rs
+++ b/templates/parachain/runtime/src/lib.rs
@@ -75,6 +75,7 @@ pub type SignedBlock = generic::SignedBlock<Block>;
 pub type BlockId = generic::BlockId<Block>;
 
 /// The SignedExtension to the basic transaction logic.
+#[docify::export(template_signed_extra)]
 pub type SignedExtra = (
 	frame_system::CheckNonZeroSender<Runtime>,
 	frame_system::CheckSpecVersion<Runtime>,
-- 
GitLab