From 69c279a10c2449ee62609c013705475565355e16 Mon Sep 17 00:00:00 2001 From: Shunsuke Watanabe Date: Mon, 22 May 2023 15:55:56 +0900 Subject: [PATCH 1/6] forward blocks to the specified height --- client/consensus/manual-seal/src/rpc.rs | 97 +++++++++++++++++++++---- node/src/rpc.rs | 2 +- 2 files changed, 84 insertions(+), 15 deletions(-) diff --git a/client/consensus/manual-seal/src/rpc.rs b/client/consensus/manual-seal/src/rpc.rs index d6b5a1d..16b061c 100644 --- a/client/consensus/manual-seal/src/rpc.rs +++ b/client/consensus/manual-seal/src/rpc.rs @@ -3,6 +3,8 @@ use crate::error::Error; use futures::{ channel::{mpsc, oneshot}, + prelude::*, + stream::StreamExt, SinkExt, }; use jsonrpsee::{ @@ -11,7 +13,12 @@ use jsonrpsee::{ }; use sc_consensus::ImportedAux; use serde::{Deserialize, Serialize}; -use sp_runtime::EncodedJustification; +use sp_blockchain::HeaderBackend; +use sp_runtime::{ + traits::{Block as BlockT, Header}, + EncodedJustification, SaturatedConversion, +}; +use std::sync::Arc; /// Sender passed to the authorship task to report errors or successes. pub type Sender = Option>>; @@ -48,28 +55,44 @@ pub enum EngineCommand { /// RPC trait that provides methods for interacting with the manual-seal authorship task over rpc. #[rpc(client, server)] -pub trait ManualSealApi { +pub trait ManualSealApi +where + Block: BlockT, +{ /// Instructs the manual-seal authorship task to create a new block #[method(name = "engine_createBlock")] async fn create_block( &self, create_empty: bool, finalize: bool, - parent_hash: Option, - ) -> RpcResult>; + parent_hash: Option, + ) -> RpcResult>; /// Instructs the manual-seal authorship task to finalize a block #[method(name = "engine_finalizeBlock")] async fn finalize_block( &self, - hash: Hash, + hash: Block::Hash, justification: Option, ) -> RpcResult; + + #[method(name = "engine_forwardBlocksTo")] + async fn forward_blocks_to( + &self, + height: <::Header as Header>::Number, + ) -> RpcResult<()>; + + #[method(name = "engine_revertBlocksTo")] + async fn revert_blocks_to( + &self, + height: <::Header as Header>::Number, + ) -> RpcResult<()>; } /// A struct that implements the [`ManualSealApiServer`]. -pub struct ManualSeal { - import_block_channel: mpsc::Sender>, +pub struct ManualSeal { + client: Arc, + import_block_channel: mpsc::Sender>, } /// return type of `engine_createBlock` @@ -81,21 +104,30 @@ pub struct CreatedBlock { pub aux: ImportedAux, } -impl ManualSeal { +impl ManualSeal { /// Create new `ManualSeal` with the given reference to the client. - pub fn new(import_block_channel: mpsc::Sender>) -> Self { - Self { import_block_channel } + pub fn new( + client: Arc, + import_block_channel: mpsc::Sender>, + ) -> Self { + Self { client, import_block_channel } } } #[async_trait] -impl ManualSealApiServer for ManualSeal { +impl ManualSealApiServer for ManualSeal +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi, + Client: HeaderBackend, + Client: Send + Sync + 'static, +{ async fn create_block( &self, create_empty: bool, finalize: bool, - parent_hash: Option, - ) -> RpcResult> { + parent_hash: Option, + ) -> RpcResult> { let mut sink = self.import_block_channel.clone(); let (sender, receiver) = oneshot::channel(); // NOTE: this sends a Result over the channel. @@ -117,7 +149,7 @@ impl ManualSealApiServer for ManualSeal { async fn finalize_block( &self, - hash: Hash, + hash: Block::Hash, justification: Option, ) -> RpcResult { let mut sink = self.import_block_channel.clone(); @@ -126,6 +158,43 @@ impl ManualSealApiServer for ManualSeal { sink.send(command).await?; receiver.await.map(|_| true).map_err(|e| JsonRpseeError::to_call_error(e)) } + + async fn forward_blocks_to( + &self, + height: <::Header as Header>::Number, + ) -> RpcResult<()> { + let best_number = self.client.info().best_number; + if height <= best_number { + return Err(JsonRpseeError::Custom( + "Target height is lower than current best height".into(), + )) + } + + let diff = height - best_number; + let to_height = (0..diff.saturated_into::()) + .into_iter() + .map(|_| EngineCommand::SealNewBlock { + create_empty: true, + finalize: false, + parent_hash: None, + sender: None, + }) + .collect::>>(); + + let mut forward_blocks_stream = stream::iter(to_height).map(Ok); + + let mut sink = self.import_block_channel.clone(); + sink.send_all(&mut forward_blocks_stream).await?; + + Ok(()) + } + + async fn revert_blocks_to( + &self, + height: <::Header as Header>::Number, + ) -> RpcResult<()> { + Ok(()) + } } /// report any errors or successes encountered by the authorship task back diff --git a/node/src/rpc.rs b/node/src/rpc.rs index 626728a..d67833b 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -56,7 +56,7 @@ where io.merge(TransactionPayment::new(client.clone()).into_rpc())?; // The final RPC extension receives commands for the manual seal consensus engine. - io.merge(ManualSeal::new(command_sink).into_rpc())?; + io.merge(ManualSeal::new(client, command_sink).into_rpc())?; Ok(io) } From d5181371e0ea55791bd987dfeeefe7cf67f666e9 Mon Sep 17 00:00:00 2001 From: Shunsuke Watanabe Date: Mon, 22 May 2023 17:06:47 +0900 Subject: [PATCH 2/6] revert blocks --- client/consensus/manual-seal/src/rpc.rs | 28 +++++++++++++++++++++---- node/src/rpc.rs | 13 +++++++----- node/src/service.rs | 2 ++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/client/consensus/manual-seal/src/rpc.rs b/client/consensus/manual-seal/src/rpc.rs index 16b061c..d1d73e1 100644 --- a/client/consensus/manual-seal/src/rpc.rs +++ b/client/consensus/manual-seal/src/rpc.rs @@ -90,8 +90,9 @@ where } /// A struct that implements the [`ManualSealApiServer`]. -pub struct ManualSeal { +pub struct ManualSeal { client: Arc, + backend: Arc, import_block_channel: mpsc::Sender>, } @@ -104,23 +105,25 @@ pub struct CreatedBlock { pub aux: ImportedAux, } -impl ManualSeal { +impl ManualSeal { /// Create new `ManualSeal` with the given reference to the client. pub fn new( client: Arc, + backend: Arc, import_block_channel: mpsc::Sender>, ) -> Self { - Self { client, import_block_channel } + Self { client, backend, import_block_channel } } } #[async_trait] -impl ManualSealApiServer for ManualSeal +impl ManualSealApiServer for ManualSeal where Block: BlockT, Client: sp_api::ProvideRuntimeApi, Client: HeaderBackend, Client: Send + Sync + 'static, + Backend: sc_client_api::backend::Backend + Send + Sync + 'static, { async fn create_block( &self, @@ -193,6 +196,23 @@ where &self, height: <::Header as Header>::Number, ) -> RpcResult<()> { + let best_number = self.client.info().best_number; + if height >= best_number { + return Err(JsonRpseeError::Custom( + "Target height is higher than current best height".into(), + )) + } + + let diff = best_number - height; + + println!("Diff: {:?}", diff); + + let reverted = self.backend + .revert(diff, true) + .map_err(|e| JsonRpseeError::Custom(format!("Backend Revert Error: {}", e)))?; + + println!("Reverted: {:?}", reverted); + Ok(()) } } diff --git a/node/src/rpc.rs b/node/src/rpc.rs index d67833b..12aae53 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -22,9 +22,11 @@ use sp_block_builder::BlockBuilder; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; /// Full client dependencies. -pub struct FullDeps { +pub struct FullDeps { /// The client instance to use. pub client: Arc, + /// The backend instance to use. + pub backend: Arc, /// Transaction pool instance. pub pool: Arc

, /// Whether to deny unsafe calls @@ -34,8 +36,8 @@ pub struct FullDeps { } /// Instantiate all full RPC extensions. -pub fn create_full( - deps: FullDeps, +pub fn create_full( + deps: FullDeps, ) -> Result, Box> where C: ProvideRuntimeApi, @@ -44,19 +46,20 @@ where C::Api: substrate_frame_rpc_system::AccountNonceApi, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: BlockBuilder, + B: sc_client_api::backend::Backend + Send + Sync + 'static, P: TransactionPool + 'static, { use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use substrate_frame_rpc_system::{System, SystemApiServer}; let mut io = RpcModule::new(()); - let FullDeps { client, pool, deny_unsafe, command_sink } = deps; + let FullDeps { client, backend, pool, deny_unsafe, command_sink } = deps; io.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; // The final RPC extension receives commands for the manual seal consensus engine. - io.merge(ManualSeal::new(client, command_sink).into_rpc())?; + io.merge(ManualSeal::new(client, backend, command_sink).into_rpc())?; Ok(io) } diff --git a/node/src/service.rs b/node/src/service.rs index 12e585c..4a49a32 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -169,11 +169,13 @@ pub fn new_full( let rpc_extensions_builder = { let client = client.clone(); + let backend = backend.clone(); let pool = transaction_pool.clone(); Box::new(move |deny_unsafe, _| { let deps = crate::rpc::FullDeps { client: client.clone(), + backend: backend.clone(), pool: pool.clone(), deny_unsafe, command_sink: rpc_command_sink.clone(), From d4bc4652aaa5454c1cdd173cefbff5607e599e8a Mon Sep 17 00:00:00 2001 From: Shunsuke Watanabe Date: Mon, 22 May 2023 17:49:54 +0900 Subject: [PATCH 3/6] cargo fmt --- client/consensus/manual-seal/src/rpc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/consensus/manual-seal/src/rpc.rs b/client/consensus/manual-seal/src/rpc.rs index d1d73e1..d719179 100644 --- a/client/consensus/manual-seal/src/rpc.rs +++ b/client/consensus/manual-seal/src/rpc.rs @@ -207,7 +207,8 @@ where println!("Diff: {:?}", diff); - let reverted = self.backend + let reverted = self + .backend .revert(diff, true) .map_err(|e| JsonRpseeError::Custom(format!("Backend Revert Error: {}", e)))?; From d1117e0d2a5f1f17ae87ad33be3d301177f22e3d Mon Sep 17 00:00:00 2001 From: Shunsuke Watanabe Date: Wed, 24 May 2023 13:15:20 +0900 Subject: [PATCH 4/6] fix ci --- .github/workflows/checks-and-tests.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/checks-and-tests.yaml b/.github/workflows/checks-and-tests.yaml index 3e0f56b..a55c058 100644 --- a/.github/workflows/checks-and-tests.yaml +++ b/.github/workflows/checks-and-tests.yaml @@ -31,9 +31,7 @@ jobs: uses: actions/checkout@v3 - name: Install Protoc - uses: arduino/setup-protoc@v1 - with: - version: '3.x' + run: sudo apt -y install protobuf-compiler - name: Install & display rust toolchain run: rustup show From 7f8c0464acdffdf2d901e9ce3fdddb6cc5a2d8e8 Mon Sep 17 00:00:00 2001 From: Shunsuke Watanabe Date: Mon, 29 May 2023 16:51:18 +0800 Subject: [PATCH 5/6] updated README --- README.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/README.md b/README.md index c44ab34..b5659d8 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Swanky node is a Substrate based blockchain configured to enable `pallet-contrac - [pallet-contracts](https://github.com/paritytech/substrate/tree/master/frame/contracts) (polkadot-0.9.39). - `grandpa` & `aura` consensus were removed. Instead, [`instant-seal`/`manual-seal`](https://github.com/AstarNetwork/swanky-node#consensus-manual-seal--instant-seal) & [`delayed-finalize`](https://github.com/AstarNetwork/swanky-node#consensus-delayed-finalize) are used. Blocks are sealed (1) as soon as a transaction get in the pool (2) when `engine_createBlock` RPC called. Blocks are finalized configured delay sec after blocks are sealed. +- Block height manipuration. Developpers can forward and revert blocks via RPC. - [pallet-dapps-staking](https://github.com/AstarNetwork/astar-frame/tree/polkadot-v0.9.39/frame/dapps-staking) and ChainExtension to interact with it. - [pallet-assets](https://github.com/paritytech/substrate/tree/polkadot-v0.9.39/frame/assets). - Pallet-assets chain-extension @@ -165,3 +166,41 @@ By default, either manual or instant seal does not result in block finalization ``` In the above example, a setting of `5` seconds would result in the blocks being finalized five seconds after being sealed. In contrast, setting the value to `0` would lead to instant finalization, with the blocks being finalized immediately upon being sealed. + +## Block height manipuration +Developpers can forward blocks and revert blocks to requested block heights. + +### Forward blocks via RPC +Forwarding blocks to requested block height by calling `engine_forwardBlocksTo`. + +```bash +$ curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d '{ feat/forward-revert-blocks ✭ + "jsonrpc":"2.0", + "id":1, + "method":"engine_forwardBlocksTo", + "params": [120, null] + }' +``` + +#### Params +- **Height** + `height` denotes an integral value that signifies the desired block height towards which the user intends to progress. If the value is lower than current height, RPC returns an error. + +### Revert blocks via RPC +Reverting blocks to requested block height by calling `engine_revertBlocksTo`. + +Note that reverting finalized blocks only works when node is launched with archive mode `--state-pruning archive` (or `--pruning archive`) since reverting blocks requires past blocks' states. +When blocks' states are pruned, RPC won't revert finalzied blocks. + +```bash +$ curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d '{ feat/forward-revert-blocks ✭ + "jsonrpc":"2.0", + "id":1, + "method":"engine_revertBlocksTo", + "params": [50, null] + }' +``` + +#### Params +- **Height** + `height` denotes an integral value that represents the desired block height which the user intends to revert to. If the value is higher than current height, RPC returns an error. From 7ecaf0ed0383057fed5d1b5646fb66e0ee2961fe Mon Sep 17 00:00:00 2001 From: PierreOssun Date: Mon, 26 Jun 2023 09:59:31 +0200 Subject: [PATCH 6/6] fix typos --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b5659d8..c607a69 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Swanky node is a Substrate based blockchain configured to enable `pallet-contrac - [pallet-contracts](https://github.com/paritytech/substrate/tree/master/frame/contracts) (polkadot-0.9.39). - `grandpa` & `aura` consensus were removed. Instead, [`instant-seal`/`manual-seal`](https://github.com/AstarNetwork/swanky-node#consensus-manual-seal--instant-seal) & [`delayed-finalize`](https://github.com/AstarNetwork/swanky-node#consensus-delayed-finalize) are used. Blocks are sealed (1) as soon as a transaction get in the pool (2) when `engine_createBlock` RPC called. Blocks are finalized configured delay sec after blocks are sealed. -- Block height manipuration. Developpers can forward and revert blocks via RPC. +- Block height manipulation. Developers can forward and revert blocks via RPC. - [pallet-dapps-staking](https://github.com/AstarNetwork/astar-frame/tree/polkadot-v0.9.39/frame/dapps-staking) and ChainExtension to interact with it. - [pallet-assets](https://github.com/paritytech/substrate/tree/polkadot-v0.9.39/frame/assets). - Pallet-assets chain-extension @@ -167,8 +167,8 @@ By default, either manual or instant seal does not result in block finalization In the above example, a setting of `5` seconds would result in the blocks being finalized five seconds after being sealed. In contrast, setting the value to `0` would lead to instant finalization, with the blocks being finalized immediately upon being sealed. -## Block height manipuration -Developpers can forward blocks and revert blocks to requested block heights. +## Block height manipulation +Developers can forward blocks and revert blocks to requested block heights. ### Forward blocks via RPC Forwarding blocks to requested block height by calling `engine_forwardBlocksTo`. @@ -190,7 +190,7 @@ $ curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d Reverting blocks to requested block height by calling `engine_revertBlocksTo`. Note that reverting finalized blocks only works when node is launched with archive mode `--state-pruning archive` (or `--pruning archive`) since reverting blocks requires past blocks' states. -When blocks' states are pruned, RPC won't revert finalzied blocks. +When blocks' states are pruned, RPC won't revert finalized blocks. ```bash $ curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d '{ feat/forward-revert-blocks ✭