Skip to content

Commit

Permalink
move generate_proof from IsmpRuntimeApi to MmrRuntimeApi
Browse files Browse the repository at this point in the history
  • Loading branch information
seunlanlege committed Dec 21, 2024
1 parent 00ddda9 commit fd2f1fe
Show file tree
Hide file tree
Showing 33 changed files with 257 additions and 115 deletions.
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 14 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ members = [
"modules/pallets/relayer",
"modules/pallets/fishermen",
"modules/pallets/host-executive",
"modules/pallets/rpc",
"modules/pallets/runtime-api",
"modules/pallets/ismp/rpc",
"modules/pallets/ismp/runtime-api",
"modules/pallets/demo",
"modules/pallets/testsuite",
"modules/pallets/call-decompressor",
Expand Down Expand Up @@ -50,10 +50,11 @@ members = [
"modules/consensus/grandpa/primitives",
"modules/consensus/grandpa/verifier",
"modules/trees/ethereum",
"modules/trees/mmr/pallet",
"modules/trees/mmr/primitives",
"modules/trees/mmr/gadget",
"modules/trees/mmr/pallet/runtime-api",
"modules/pallets/mmr",
"modules/pallets/mmr/primitives",
"modules/pallets/mmr/gadget",
"modules/pallets/mmr/runtime-api",
"modules/pallets/mmr/rpc",
"modules/ismp/state-machines/evm",
"modules/ismp/state-machines/substrate",
"modules/ismp/state-machines/hyperbridge",
Expand Down Expand Up @@ -302,8 +303,8 @@ hyperbridge-client-machine = { path = "modules/ismp/state-machines/hyperbridge",

# published pallets
pallet-ismp = { version = "1.15.3", path = "modules/pallets/ismp", default-features = false }
pallet-ismp-rpc = { version = "1.15.3", path = "modules/pallets/rpc" }
pallet-ismp-runtime-api = { version = "1.15.3", path = "modules/pallets/runtime-api", default-features = false }
pallet-ismp-rpc = { version = "1.15.3", path = "modules/pallets/ismp/rpc" }
pallet-ismp-runtime-api = { version = "1.15.3", path = "modules/pallets/ismp/runtime-api", default-features = false }
pallet-hyperbridge = { version = "1.15.3", path = "modules/pallets/hyperbridge", default-features = false }
pallet-token-gateway = { version = "1.15.3", path = "modules/pallets/token-gateway", default-features = false }
token-gateway-primitives = { version = "1.15.3", path = "modules/pallets/token-gateway/primitives", default-features = false }
Expand All @@ -317,14 +318,15 @@ pallet-call-decompressor = { path = "modules/pallets/call-decompressor", default
pallet-xcm-gateway = { path = "modules/pallets/asset-gateway", default-features = false }
pallet-token-governor = { path = "modules/pallets/token-governor", default-features = false }
pallet-state-coprocessor = { path = "modules/pallets/state-coprocessor", default-features = false }
pallet-mmr = { path = "modules/trees/mmr/pallet", default-features = false }
pallet-token-gateway-inspector = { path = "modules/pallets/token-gateway-inspector", default-features = false }

# merkle trees
ethereum-triedb = { version = "0.1.1", path = "./modules/trees/ethereum", default-features = false }
mmr-primitives = { path = "modules/trees/mmr/primitives", default-features = false }
pallet-mmr-runtime-api = { path = "modules/trees/mmr/pallet/runtime-api", default-features = false }
mmr-gadget = { path = "modules/trees/mmr/gadget" }
pallet-mmr = { path = "modules/pallets/mmr", default-features = false }
pallet-mmr-rpc = { path = "modules/pallets/mmr/rpc", default-features = false }
mmr-primitives = { path = "modules/pallets/mmr/primitives", default-features = false }
pallet-mmr-runtime-api = { path = "modules/pallets/mmr/runtime-api", default-features = false }
mmr-gadget = { path = "modules/pallets/mmr/gadget" }

# runtimes
gargantua-runtime = { path = "./parachain/runtimes/gargantua", default-features = false }
Expand Down
16 changes: 1 addition & 15 deletions docs/pages/developers/polkadot/pallet-ismp-rpc.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,7 @@ This method accepts a list of response commitments and responds with the request
let commitment = H256::random();
let params = rpc_params![pallet_ismp::offchain::LeafIndexQuery { commitment }];
let requests: Vec<Request> = client.rpc().request("ismp_queryResponses", params).await.unwrap();
```

### `query_mmr_proof`
This method queries the mmr proof a list of request or response commitments, it responds with a `Proof` struct which contains the scale encoded `sp_mmr_primitives::primitives::Proof<H256>`.

```rust showLineNumbers
let client = OnlineClient::<T>::from_url("ws://127.0.0.1:9944")
.await.unwrap();
// Use an actual request commitment that exists
let commitment = H256::random();
// Block height at which proof should be queried
let at = 100;
let params = rpc_params![at, pallet_ismp::offchain::ProofKeys::Requests(vec![commitment])];
let requests: Proof = client.rpc().request("ismp_queryMmrProof", params).await.unwrap();
```
```mmr_queryProof

### `query_child_trie_proof`
This method accepts a list of keys and generates a merkle patricia trie proof from palle-ismp's child trie. It responds with a proof struct which contains the scale encoded proof noded `Vec<Vec<u8>>`.
Expand Down
9 changes: 1 addition & 8 deletions docs/pages/developers/polkadot/pallet-ismp-runtime-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ impl pallet_ismp_runtime_api::IsmpRuntimeApi<Block, <Block as BlockT>::Hash> for
pallet_ismp::Pallet::<Runtime>::challenge_period(state_machine_id)
}

/// Generate a proof for the provided leaf indices
fn generate_proof(
keys: ProofKeys
) -> Result<(Vec<Leaf>, Proof<<Block as BlockT>::Hash>), sp_mmr_primitives::Error> {
pallet_ismp::Pallet::<Runtime>::generate_proof(keys)
}

/// Fetch all ISMP events in the block, should only be called from runtime-api.
fn block_events() -> Vec<::ismp::events::Event> {
pallet_ismp::Pallet::<Runtime>::block_events()
Expand Down Expand Up @@ -67,4 +60,4 @@ impl pallet_ismp_runtime_api::IsmpRuntimeApi<Block, <Block as BlockT>::Hash> for

## Implementation

- [pallet-ismp-runtime-api](https://github.com/polytope-labs/hyperbridge/blob/main/modules/ismp/pallets/runtime-api/src/lib.rs)
- [pallet-ismp-runtime-api](https://github.com/polytope-labs/hyperbridge/blob/main/modules/ismp/pallets/runtime-api/src/lib.rs)
6 changes: 2 additions & 4 deletions modules/hyperclient/src/providers/substrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,7 @@ impl<C: subxt::Config + Clone> Client for SubstrateClient<C> {
let keys =
ProofKeys::Requests(keys.into_iter().map(|key| key.commitment).collect());
let params = rpc_params![at, keys];
let response: Proof =
self.client.rpc().request("ismp_queryMmrProof", params).await?;
let response: Proof = self.client.rpc().request("mmr_queryProof", params).await?;
Ok(response.proof)
},
// Use child trie proofs for queries going to substrate chains
Expand Down Expand Up @@ -241,8 +240,7 @@ impl<C: subxt::Config + Clone> Client for SubstrateClient<C> {
let keys =
ProofKeys::Responses(keys.into_iter().map(|key| key.commitment).collect());
let params = rpc_params![at, keys];
let response: Proof =
self.client.rpc().request("ismp_queryMmrProof", params).await?;
let response: Proof = self.client.rpc().request("mmr_queryProof", params).await?;
Ok(response.proof)
},
// Use child trie proofs for queries going to substrate chains
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,7 @@ use ismp::{
router::{Request, Response},
};
use jsonrpsee::types::ErrorObjectOwned;
use pallet_ismp::{
child_trie::CHILD_TRIE_PREFIX,
offchain::{Leaf, LeafIndexQuery, ProofKeys},
};
use pallet_ismp::{child_trie::CHILD_TRIE_PREFIX, offchain::LeafIndexQuery};
use pallet_ismp_runtime_api::IsmpRuntimeApi;
use sc_client_api::{Backend, BlockBackend, ChildInfo, ProofProvider, StateBackend};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -120,7 +117,7 @@ pub struct Proof {
}

/// Converts a runtime trap into an RPC error.
fn runtime_error_into_rpc_error(e: impl std::fmt::Display) -> ErrorObjectOwned {
pub fn runtime_error_into_rpc_error(e: impl std::fmt::Display) -> ErrorObjectOwned {
ErrorObject::owned(
9876, // no real reason for this value
"Something wrong",
Expand Down Expand Up @@ -162,10 +159,6 @@ where
#[method(name = "ismp_queryResponses")]
fn query_responses(&self, query: Vec<LeafIndexQuery>) -> RpcResult<Vec<Response>>;

/// Query mmr proof for some commitments
#[method(name = "ismp_queryMmrProof")]
fn query_mmr_proof(&self, height: u32, keys: ProofKeys) -> RpcResult<Proof>;

/// Query state proof from global state trie
#[method(name = "ismp_queryStateProof")]
fn query_state_proof(&self, height: u32, keys: Vec<Vec<u8>>) -> RpcResult<Proof>;
Expand Down Expand Up @@ -271,22 +264,6 @@ where
.map_err(|_| runtime_error_into_rpc_error("Error fetching responses"))
}

fn query_mmr_proof(&self, height: u32, keys: ProofKeys) -> RpcResult<Proof> {
let mut api = self.client.runtime_api();
api.register_extension(OffchainDbExt::new(self.offchain_db.clone()));
let at = self
.client
.block_hash(height.into())
.ok()
.flatten()
.ok_or_else(|| runtime_error_into_rpc_error("invalid block height provided"))?;
let (_, proof): (Vec<Leaf>, pallet_ismp::offchain::Proof<Block::Hash>) = api
.generate_proof(at, keys)
.map_err(|_| runtime_error_into_rpc_error("Error calling runtime api"))?
.map_err(|_| runtime_error_into_rpc_error("Error generating mmr proof"))?;
Ok(Proof { proof: proof.encode(), height })
}

fn query_state_proof(&self, height: u32, keys: Vec<Vec<u8>>) -> RpcResult<Proof> {
let at = self.client.block_hash(height.into()).ok().flatten().ok_or_else(|| {
runtime_error_into_rpc_error("Could not find valid blockhash for provided height")
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ sp_api::impl_runtime_apis! {
pallet_ismp::Pallet::<Runtime>::challenge_period(consensus_state_id)
}
/// Generate a proof for the provided leaf indices
fn generate_proof(
keys: ProofKeys
) -> Result<(Vec<Leaf>, Proof<<Block as BlockT>::Hash>), sp_mmr_primitives::Error> {
pallet_ismp::Pallet::<Runtime>::generate_proof(keys)
}
/// Fetch all ISMP events and their extrinsic metadata, should only be called from runtime-api.
fn block_events() -> Vec<ismp::events::Event> {
pallet_ismp::Pallet::<Runtime>::block_events()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,14 @@ use ismp::{
host::StateMachine,
router::{Request, Response},
};
use pallet_ismp::offchain::{Leaf, Proof, ProofKeys};
use primitive_types::H256;
use sp_mmr_primitives::Error;

sp_api::decl_runtime_apis! {
/// Required runtime APIs needed for client subsystems like the RPC
pub trait IsmpRuntimeApi<Hash: codec::Codec> {
/// Should return the host's state machine identifier
fn host_state_machine() -> StateMachine;

/// Generate a proof for the provided leaf indices
fn generate_proof(
commitments: ProofKeys
) -> Result<(Vec<Leaf>, Proof<Hash>), Error>;

/// Fetch all ISMP events
fn block_events() -> Vec<ismp::events::Event>;

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ homepage = "https://docs.hyperbridge.network/developers/polkadot/getting-started
documentation = "https://docs.rs/ismp-parachain"
description = "Merkle mountain range primitives for pallet-ismp"
keywords = ["substrate", "polkadot-sdk", "ISMP", "interoperability"]
readme = "./README.md"
readme = "README.md"
publish = false

[dependencies]
Expand Down
File renamed without changes.
File renamed without changes.
32 changes: 32 additions & 0 deletions modules/pallets/mmr/rpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "pallet-mmr-rpc"
version = "0.1.0"
edition = "2021"
authors = ["Polytope Labs <hello@polytope.technology>"]
license = "Apache-2.0"
repository = "https://github.com/polytope-labs/hyperbridge"
homepage = "https://docs.hyperbridge.network/developers/polkadot/getting-started"
documentation = "https://docs.rs/pallet-ismp-rpc"
description = "RPC apis for pallet-ismp"
keywords = ["substrate", "polkadot-sdk", "ISMP", "interoperability"]
readme = "README.md"
publish = false

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
anyhow = { workspace = true }
codec = { workspace = true, features = ["derive"], default-features = true }
jsonrpsee = { workspace = true, features = ["client-core", "server", "macros"] }

sp-mmr-primitives = { workspace = true, default-features = true }
sc-client-api = { workspace = true, default-features = true }
sp-api = { workspace = true, default-features = true }
sp-blockchain = { workspace = true, default-features = true }
sp-core = { workspace = true, default-features = true }
sp-runtime = { workspace = true, default-features = true }

pallet-ismp = { workspace = true, default-features = true }
pallet-ismp-rpc = { workspace = true, default-features = true }
pallet-mmr-runtime-api = { workspace = true, default-features = true }
91 changes: 91 additions & 0 deletions modules/pallets/mmr/rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) 2024 Polytope Labs.
// 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.

use jsonrpsee::{core::RpcResult, proc_macros::rpc};

use anyhow::anyhow;
use codec::Encode;

use pallet_ismp::offchain::{Leaf, ProofKeys};
use pallet_ismp_rpc::{runtime_error_into_rpc_error, Proof};
use pallet_mmr_runtime_api::MmrRuntimeApi;
use sc_client_api::{Backend, BlockBackend};
use sp_api::{ApiExt, ProvideRuntimeApi};
use sp_core::{
offchain::{storage::OffchainDb, OffchainDbExt, OffchainStorage},
H256,
};
use sp_runtime::traits::{Block as BlockT, Header, NumberFor};
use std::sync::Arc;

/// Mmr RPC methods.
#[rpc(client, server)]
pub trait MmrApi<Hash> {
/// Query mmr proof for some commitments
#[method(name = "mmr_queryProof")]
fn query_proof(&self, height: u32, keys: ProofKeys) -> RpcResult<Proof>;
}

/// An implementation of Mmr specific RPC methods.
pub struct MmrRpcHandler<C, B, S, T> {
client: Arc<C>,
offchain_db: OffchainDb<S>,
_marker: std::marker::PhantomData<(B, T)>,
}

impl<C, B, S, T> MmrRpcHandler<C, B, S, T>
where
B: BlockT,
S: OffchainStorage + Clone + Send + Sync + 'static,
T: Backend<B, OffchainStorage = S> + Send + Sync + 'static,
{
/// Create new `MmrRpcHandler` with the given reference to the client.
pub fn new(client: Arc<C>, backend: Arc<T>) -> Result<Self, anyhow::Error> {
let offchain_db = OffchainDb::new(
backend
.offchain_storage()
.ok_or_else(|| anyhow!("Offchain Storage not present in backend!"))?,
);

Ok(Self { client, offchain_db, _marker: Default::default() })
}
}

impl<C, B, S, T> MmrApiServer<B::Hash> for MmrRpcHandler<C, B, S, T>
where
B: BlockT,
B::Hash: Into<H256>,
S: OffchainStorage + Clone + Send + Sync + 'static,
T: Backend<B> + Send + Sync + 'static,
C: Send + Sync + 'static + ProvideRuntimeApi<B> + BlockBackend<B>,
C::Api: MmrRuntimeApi<B, B::Hash, NumberFor<B>, Leaf>,
u64: From<<B::Header as Header>::Number>,
{
fn query_proof(&self, height: u32, keys: ProofKeys) -> RpcResult<Proof> {
let mut api = self.client.runtime_api();
api.register_extension(OffchainDbExt::new(self.offchain_db.clone()));
let at = self
.client
.block_hash(height.into())
.ok()
.flatten()
.ok_or_else(|| runtime_error_into_rpc_error("invalid block height provided"))?;
let (_, proof): (Vec<Leaf>, pallet_ismp::offchain::Proof<B::Hash>) = api
.generate_proof(at, keys)
.map_err(|_| runtime_error_into_rpc_error("Error calling runtime api"))?
.map_err(|_| runtime_error_into_rpc_error("Error generating mmr proof"))?;
Ok(Proof { proof: proof.encode(), height })
}
}
Loading

0 comments on commit fd2f1fe

Please sign in to comment.