Skip to content

Commit

Permalink
slim down grandpa prover
Browse files Browse the repository at this point in the history
  • Loading branch information
seunlanlege committed Nov 21, 2024
1 parent 8f6e8e8 commit a877701
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 118 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions modules/consensus/grandpa/prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ publish = false

[dependencies]
hex = "0.4.3"
hex-literal = "0.4.1"
anyhow.workspace = true
serde = { workspace = true, default-features = true}
subxt = { workspace = true, default-features = true }
Expand Down
84 changes: 27 additions & 57 deletions modules/consensus/grandpa/prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#![allow(clippy::all)]
#![deny(missing_docs)]

//! GRANDPA prover utilities
//! GRANDPA consensus prover utilities
use anyhow::anyhow;
use codec::{Decode, Encode};
Expand Down Expand Up @@ -44,17 +44,17 @@ pub struct GrandpaProver<T: Config> {
pub para_ids: Vec<u32>,
/// State machine identifier for the chain
pub state_machine: StateMachine,
/// Storage for babe epoch start
pub babe_epoch_start: Vec<u8>,
/// Storage key for current set id
pub current_set_id: Vec<u8>,
}

// We redefine these here because we want the header to be bounded by subxt::config::Header in the
// prover
/// Commit
/// We redefine these here because we want the header to be bounded by subxt::config::Header in the
/// prover
pub type Commit = finality_grandpa::Commit<H256, u32, AuthoritySignature, AuthorityId>;

/// This is the storage key for the grandpa.currentSetId storage item in the runtime. Ideally the
/// grandpa pallet is always referred to as "grandpa" in the construct runtime macro.
pub const GRANDPA_CURRENT_SET_ID: [u8; 32] =
hex_literal::hex!("5f9cc45b7a00c5899361e1c6099678dc8a2d09463effcc78a22d75b9cb87dffc");

/// Justification
#[cfg_attr(test, derive(Debug))]
#[derive(Clone, Encode, Decode)]
Expand All @@ -67,6 +67,19 @@ pub struct GrandpaJustification<H: Header + codec::Decode> {
pub votes_ancestries: Vec<H>,
}

/// Options for initializing the GRANDPA consensus prover.
#[derive(Clone, Serialize, Deserialize)]
pub struct ProverOptions<'a> {
/// The ws url to the node
pub ws_url: &'a str,
/// Parachain Ids if this GRANDPA consensus hosts parachains
pub para_ids: Vec<u32>,
/// State machine identifier for the chain
pub state_machine: StateMachine,
/// Max rpc payload for websocket connections
pub max_rpc_payload_size: u32,
}

/// An encoded justification proving that the given header has been finalized
#[derive(Clone, Serialize, Deserialize)]
pub struct JustificationNotification(pub sp_core::Bytes);
Expand All @@ -79,18 +92,13 @@ where
sp_core::H256: From<T::Hash>,
T::Header: codec::Decode,
{
/// Initializes the parachain and relay chain clients given the ws urls.
pub async fn new(
ws_url: &str,
para_ids: Vec<u32>,
state_machine: StateMachine,
babe_epoch_start: Vec<u8>,
current_set_id: Vec<u8>,
) -> Result<Self, anyhow::Error> {
let max_rpc_payload_size = 15 * 1024 * 1024;
/// Initializes the GRANDPA prover given the parameters. Internally connects over WS to the
/// provided RPC
pub async fn new(options: ProverOptions<'_>) -> Result<Self, anyhow::Error> {
let ProverOptions { max_rpc_payload_size, ws_url, state_machine, para_ids } = options;
let client = subxt_utils::client::ws_client(ws_url, max_rpc_payload_size).await?;

Ok(Self { client, para_ids, state_machine, babe_epoch_start, current_set_id })
Ok(Self { client, para_ids, state_machine })
}

/// Construct the initial consensus state.
Expand All @@ -112,7 +120,7 @@ where
.client
.storage()
.at(hash)
.fetch_raw(&self.current_set_id[..])
.fetch_raw(&GRANDPA_CURRENT_SET_ID[..])
.await
.ok()
.flatten()
Expand Down Expand Up @@ -220,7 +228,6 @@ where
/// Returns the proof for parachain headers finalized by the provided finality proof
pub async fn query_finalized_parachain_headers_with_proof<H>(
&self,
_previous_finalized_height: u32,
latest_finalized_height: u32,
finality_proof: FinalityProof<H>,
) -> Result<ParachainHeadersWithFinalityProof<H>, anyhow::Error>
Expand Down Expand Up @@ -265,41 +272,4 @@ where
parachain_headers: parachain_headers_with_proof,
})
}

/// Queries the block at which the epoch for the given block belongs to ends.
pub async fn session_start_and_end_for_block(
&self,
block: u32,
) -> Result<(u32, u32), anyhow::Error> {
let block_hash = self
.client
.rpc()
.block_hash(Some(block.into()))
.await?
.ok_or(anyhow!("Failed to fetch block hash"))?;
let bytes = self
.client
.storage()
.at(block_hash)
.fetch_raw(&self.babe_epoch_start[..])
.await?
.ok_or_else(|| anyhow!("Failed to fetch epoch information"))?;

let (previous_epoch_start, current_epoch_start): (u32, u32) =
codec::Decode::decode(&mut &*bytes)?;
Ok((
current_epoch_start,
current_epoch_start + (current_epoch_start - previous_epoch_start),
))
}

/// Returns the session length in blocks
pub async fn session_length(&self) -> Result<u32, anyhow::Error> {
let metadata = self.client.rpc().metadata().await?;
let metadata = metadata
.pallet_by_name_err("Babe")?
.constant_by_name("EpochDuration")
.ok_or(anyhow!("Failed to fetch constant"))?;
Ok(Decode::decode(&mut metadata.value())?)
}
}
1 change: 0 additions & 1 deletion modules/consensus/grandpa/verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#![allow(clippy::all)]
#![deny(missing_docs)]

#[cfg(test)]
mod tests;

extern crate alloc;
Expand Down
39 changes: 23 additions & 16 deletions modules/consensus/grandpa/verifier/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#![cfg(test)]

use crate::verify_parachain_headers_with_grandpa_finality_proof;
use anyhow::anyhow;
use codec::{Decode, Encode};
use futures::StreamExt;
use grandpa_prover::GrandpaProver;
use grandpa_prover::{GrandpaProver, ProverOptions};
use grandpa_verifier_primitives::{
justification::GrandpaJustification, ParachainHeadersWithFinalityProof,
};
Expand All @@ -10,14 +13,26 @@ use polkadot_core_primitives::Header;
use serde::{Deserialize, Serialize};
use subxt::{
config::substrate::{BlakeTwo256, SubstrateHeader},
rpc_params,
rpc_params, OnlineClient,
};
pub type Justification = GrandpaJustification<Header>;

/// An encoded justification proving that the given header has been finalized
#[derive(Clone, Serialize, Deserialize)]
pub struct JustificationNotification(sp_core::Bytes);

/// Returns the session length in blocks
pub async fn session_length<T: subxt::Config>(
client: &OnlineClient<T>,
) -> Result<u32, anyhow::Error> {
let metadata = client.rpc().metadata().await?;
let metadata = metadata
.pallet_by_name_err("Babe")?
.constant_by_name("EpochDuration")
.ok_or(anyhow!("Failed to fetch constant"))?;
Ok(Decode::decode(&mut metadata.value())?)
}

#[ignore]
#[tokio::test]
async fn follow_grandpa_justifications() {
Expand All @@ -29,29 +44,22 @@ async fn follow_grandpa_justifications() {
let relay_ws_url = std::env::var("RELAY_HOST")
.unwrap_or_else(|_| "wss://hyperbridge-paseo-relay.blockops.network:443".to_string());

// let relay_ws_url = format!("ws://{relay}:9944");

let para_ids = vec![2000];
let babe_epoch_start_key =
hex::decode("1cb6f36e027abb2091cfb5110ab5087fe90e2fbf2d792cb324bffa9427fe1f0e").unwrap();
let current_set_id_key =
hex::decode("5f9cc45b7a00c5899361e1c6099678dc8a2d09463effcc78a22d75b9cb87dffc").unwrap();

println!("Connecting to relay chain {relay_ws_url}");
let prover = GrandpaProver::<subxt_utils::BlakeSubstrateChain>::new(
&relay_ws_url,
let prover = GrandpaProver::<subxt_utils::BlakeSubstrateChain>::new(ProverOptions {
ws_url: &relay_ws_url,
para_ids,
StateMachine::Polkadot(0),
babe_epoch_start_key,
current_set_id_key,
)
state_machine: StateMachine::Polkadot(0),
max_rpc_payload_size: u32::MAX,
})
.await
.unwrap();

println!("Connected to relay chain");

println!("Waiting for grandpa proofs to become available");
let session_length = prover.session_length().await.unwrap();
let session_length = session_length(&prover.client).await.unwrap();
prover
.client
.blocks()
Expand Down Expand Up @@ -104,7 +112,6 @@ async fn follow_grandpa_justifications() {

let proof = prover
.query_finalized_parachain_headers_with_proof::<SubstrateHeader<u32, BlakeTwo256>>(
consensus_state.latest_height,
justification.commit.target_number,
finality_proof.clone(),
)
Expand Down
14 changes: 6 additions & 8 deletions modules/ismp/pallets/pallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,8 @@ pub mod pallet {

let metadata = match message.commitment {
MessageCommitment::Request(commitment) => RequestCommitments::<T>::get(commitment),
MessageCommitment::Response(commitment) => {
ResponseCommitments::<T>::get(commitment)
},
MessageCommitment::Response(commitment) =>
ResponseCommitments::<T>::get(commitment),
};

let Some(mut metadata) = metadata else {
Expand Down Expand Up @@ -688,11 +687,10 @@ pub mod pallet {
// check that requests will be successfully dispatched
// so we can not be spammed with failing txs
.map(|result| match result {
MessageResult::Request(results)
| MessageResult::Response(results)
| MessageResult::Timeout(results) => {
results.into_iter().map(|result| result.map(|_| ())).collect::<Vec<_>>()
},
MessageResult::Request(results) |
MessageResult::Response(results) |
MessageResult::Timeout(results) =>
results.into_iter().map(|result| result.map(|_| ())).collect::<Vec<_>>(),
MessageResult::ConsensusMessage(_) | MessageResult::FrozenClient(_) => {
vec![Ok(())]
},
Expand Down
30 changes: 12 additions & 18 deletions parachain/runtimes/gargantua/src/ismp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,10 @@ impl IsmpModule for ProxyModule {
let token_governor = ModuleId::Pallet(PalletId(pallet_token_governor::PALLET_ID));

match pallet_id {
pallet_ismp_demo::PALLET_ID => {
pallet_ismp_demo::IsmpModuleCallback::<Runtime>::default().on_accept(request)
},
id if id == xcm_gateway => {
pallet_xcm_gateway::Module::<Runtime>::default().on_accept(request)
},
pallet_ismp_demo::PALLET_ID =>
pallet_ismp_demo::IsmpModuleCallback::<Runtime>::default().on_accept(request),
id if id == xcm_gateway =>
pallet_xcm_gateway::Module::<Runtime>::default().on_accept(request),
id if id == token_governor => TokenGovernor::default().on_accept(request),
_ => Err(anyhow!("Destination module not found")),
}
Expand All @@ -254,9 +252,8 @@ impl IsmpModule for ProxyModule {
let pallet_id = ModuleId::from_bytes(dest).map_err(|err| Error::Custom(err.to_string()))?;

match pallet_id {
pallet_ismp_demo::PALLET_ID => {
pallet_ismp_demo::IsmpModuleCallback::<Runtime>::default().on_response(response)
},
pallet_ismp_demo::PALLET_ID =>
pallet_ismp_demo::IsmpModuleCallback::<Runtime>::default().on_response(response),
_ => Err(anyhow!("Destination module not found")),
}
}
Expand All @@ -269,9 +266,8 @@ impl IsmpModule for ProxyModule {
}
(&post.from, post.source.clone(), post.dest.clone())
},
Timeout::Request(Request::Get(get)) => {
(&get.from, get.source.clone(), get.dest.clone())
},
Timeout::Request(Request::Get(get)) =>
(&get.from, get.source.clone(), get.dest.clone()),
Timeout::Response(res) => (&res.source_module(), res.source_chain(), res.dest_chain()),
};

Expand All @@ -282,12 +278,10 @@ impl IsmpModule for ProxyModule {
let pallet_id = ModuleId::from_bytes(from).map_err(|err| Error::Custom(err.to_string()))?;
let xcm_gateway = ModuleId::Evm(XcmGateway::token_gateway_address(&dest));
match pallet_id {
pallet_ismp_demo::PALLET_ID => {
pallet_ismp_demo::IsmpModuleCallback::<Runtime>::default().on_timeout(timeout)
},
id if id == xcm_gateway => {
pallet_xcm_gateway::Module::<Runtime>::default().on_timeout(timeout)
},
pallet_ismp_demo::PALLET_ID =>
pallet_ismp_demo::IsmpModuleCallback::<Runtime>::default().on_timeout(timeout),
id if id == xcm_gateway =>
pallet_xcm_gateway::Module::<Runtime>::default().on_timeout(timeout),
// instead of returning an error, do nothing. The timeout is for a connected chain.
_ => Ok(()),
}
Expand Down
15 changes: 6 additions & 9 deletions parachain/runtimes/nexus/src/ismp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,8 @@ impl IsmpModule for ProxyModule {
let token_governor = ModuleId::Pallet(PalletId(pallet_token_governor::PALLET_ID));

match pallet_id {
id if id == xcm_gateway => {
pallet_xcm_gateway::Module::<Runtime>::default().on_accept(request)
},
id if id == xcm_gateway =>
pallet_xcm_gateway::Module::<Runtime>::default().on_accept(request),
id if id == token_governor => TokenGovernor::default().on_accept(request),
_ => Err(anyhow!("Destination module not found")),
}
Expand All @@ -249,9 +248,8 @@ impl IsmpModule for ProxyModule {
(&post.from, &post.source, &post.dest)
},
Timeout::Request(Request::Get(get)) => (&get.from, &get.source, &get.dest),
Timeout::Response(res) => {
(&res.source_module(), &res.source_chain(), &res.dest_chain())
},
Timeout::Response(res) =>
(&res.source_module(), &res.source_chain(), &res.dest_chain()),
};

if *source != HostStateMachine::get() {
Expand All @@ -261,9 +259,8 @@ impl IsmpModule for ProxyModule {
let pallet_id = ModuleId::from_bytes(from).map_err(|err| Error::Custom(err.to_string()))?;
let xcm_gateway = ModuleId::Evm(XcmGateway::token_gateway_address(dest));
match pallet_id {
id if id == xcm_gateway => {
pallet_xcm_gateway::Module::<Runtime>::default().on_timeout(timeout)
},
id if id == xcm_gateway =>
pallet_xcm_gateway::Module::<Runtime>::default().on_timeout(timeout),
// instead of returning an error, do nothing. The timeout is for a connected chain.
_ => Ok(()),
}
Expand Down
17 changes: 8 additions & 9 deletions parachain/runtimes/nexus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,20 +748,19 @@ impl InstanceFilter<RuntimeCall> for ProxyType {
fn filter(&self, c: &RuntimeCall) -> bool {
match self {
ProxyType::Any => true,
ProxyType::NonTransfer => {
!matches!(c, RuntimeCall::Balances { .. } | RuntimeCall::Assets { .. })
},
ProxyType::NonTransfer =>
!matches!(c, RuntimeCall::Balances { .. } | RuntimeCall::Assets { .. }),
ProxyType::CancelProxy => matches!(
c,
RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. })
| RuntimeCall::Utility { .. }
| RuntimeCall::Multisig { .. }
RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) |
RuntimeCall::Utility { .. } |
RuntimeCall::Multisig { .. }
),
ProxyType::Collator => matches!(
c,
RuntimeCall::CollatorSelection { .. }
| RuntimeCall::Utility { .. }
| RuntimeCall::Multisig { .. }
RuntimeCall::CollatorSelection { .. } |
RuntimeCall::Utility { .. } |
RuntimeCall::Multisig { .. }
),
}
}
Expand Down

0 comments on commit a877701

Please sign in to comment.