Define SubstrateBeefy RPC client (#1615)

This commit is contained in:
Serban Iorga
2022-10-24 10:55:31 +03:00
committed by Bastian Köcher
parent 9bf36be259
commit 4f796ce803
5 changed files with 62 additions and 18 deletions
@@ -19,8 +19,8 @@
use crate::{ use crate::{
chain::{Chain, ChainWithBalances}, chain::{Chain, ChainWithBalances},
rpc::{ rpc::{
SubstrateAuthorClient, SubstrateChainClient, SubstrateFrameSystemClient, SubstrateAuthorClient, SubstrateChainClient, SubstrateFinalityClient,
SubstrateGrandpaClient, SubstrateStateClient, SubstrateSystemClient, SubstrateFrameSystemClient, SubstrateStateClient, SubstrateSystemClient,
SubstrateTransactionPaymentClient, SubstrateTransactionPaymentClient,
}, },
transaction_stall_timeout, ConnectionParams, Error, HashOf, HeaderIdOf, Result, SignParam, transaction_stall_timeout, ConnectionParams, Error, HashOf, HeaderIdOf, Result, SignParam,
@@ -642,11 +642,13 @@ impl<C: Chain> Client<C> {
.await .await
} }
/// Return new GRANDPA justifications stream. /// Return new finality justifications stream.
pub async fn subscribe_grandpa_justifications(&self) -> Result<Subscription<Bytes>> { pub async fn subscribe_finality_justifications<FC: SubstrateFinalityClient<C>>(
&self,
) -> Result<Subscription<Bytes>> {
let subscription = self let subscription = self
.jsonrpsee_execute(move |client| async move { .jsonrpsee_execute(move |client| async move {
Ok(SubstrateGrandpaClient::<C>::subscribe_justifications(&*client).await?) Ok(FC::subscribe_justifications(&client).await?)
}) })
.await?; .await?;
let (sender, receiver) = futures::channel::mpsc::channel(MAX_SUBSCRIPTION_CAPACITY); let (sender, receiver) = futures::channel::mpsc::channel(MAX_SUBSCRIPTION_CAPACITY);
@@ -39,6 +39,7 @@ pub use crate::{
}, },
client::{ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet, Subscription}, client::{ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet, Subscription},
error::{Error, Result}, error::{Error, Result},
rpc::{SubstrateBeefyFinalityClient, SubstrateFinalityClient, SubstrateGrandpaFinalityClient},
sync_header::SyncHeader, sync_header::SyncHeader,
transaction_tracker::TransactionTracker, transaction_tracker::TransactionTracker,
}; };
+44 -3
View File
@@ -16,9 +16,15 @@
//! The most generic Substrate node RPC interface. //! The most generic Substrate node RPC interface.
use crate::{Chain, TransactionStatusOf}; use async_trait::async_trait;
use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use crate::{Chain, ChainWithGrandpa, TransactionStatusOf};
use jsonrpsee::{
core::{client::Subscription, RpcResult},
proc_macros::rpc,
ws_client::WsClient,
};
use pallet_transaction_payment_rpc_runtime_api::FeeDetails; use pallet_transaction_payment_rpc_runtime_api::FeeDetails;
use sc_rpc_api::{state::ReadProof, system::Health}; use sc_rpc_api::{state::ReadProof, system::Health};
use sp_core::{ use sp_core::{
@@ -100,14 +106,49 @@ pub(crate) trait SubstrateState<C> {
) -> RpcResult<ReadProof<C::Hash>>; ) -> RpcResult<ReadProof<C::Hash>>;
} }
/// RPC methods that we are using for a certain finality gadget.
#[async_trait]
pub trait SubstrateFinalityClient<C: Chain> {
/// Subscribe to finality justifications.
async fn subscribe_justifications(client: &WsClient) -> RpcResult<Subscription<Bytes>>;
}
/// RPC methods of Substrate `grandpa` namespace, that we are using. /// RPC methods of Substrate `grandpa` namespace, that we are using.
#[rpc(client, client_bounds(C: Chain), namespace = "grandpa")] #[rpc(client, client_bounds(C: ChainWithGrandpa), namespace = "grandpa")]
pub(crate) trait SubstrateGrandpa<C> { pub(crate) trait SubstrateGrandpa<C> {
/// Subscribe to GRANDPA justifications. /// Subscribe to GRANDPA justifications.
#[subscription(name = "subscribeJustifications", unsubscribe = "unsubscribeJustifications", item = Bytes)] #[subscription(name = "subscribeJustifications", unsubscribe = "unsubscribeJustifications", item = Bytes)]
fn subscribe_justifications(&self); fn subscribe_justifications(&self);
} }
/// RPC finality methods of Substrate `grandpa` namespace, that we are using.
pub struct SubstrateGrandpaFinalityClient;
#[async_trait]
impl<C: ChainWithGrandpa> SubstrateFinalityClient<C> for SubstrateGrandpaFinalityClient {
async fn subscribe_justifications(client: &WsClient) -> RpcResult<Subscription<Bytes>> {
SubstrateGrandpaClient::<C>::subscribe_justifications(client).await
}
}
// TODO: Use `ChainWithBeefy` instead of `Chain` after #1606 is merged
/// RPC methods of Substrate `beefy` namespace, that we are using.
#[rpc(client, client_bounds(C: Chain), namespace = "beefy")]
pub(crate) trait SubstrateBeefy<C> {
/// Subscribe to BEEFY justifications.
#[subscription(name = "subscribeJustifications", unsubscribe = "unsubscribeJustifications", item = Bytes)]
fn subscribe_justifications(&self);
}
/// RPC finality methods of Substrate `beefy` namespace, that we are using.
pub struct SubstrateBeefyFinalityClient;
// TODO: Use `ChainWithBeefy` instead of `Chain` after #1606 is merged
#[async_trait]
impl<C: Chain> SubstrateFinalityClient<C> for SubstrateBeefyFinalityClient {
async fn subscribe_justifications(client: &WsClient) -> RpcResult<Subscription<Bytes>> {
SubstrateBeefyClient::<C>::subscribe_justifications(client).await
}
}
/// RPC methods of Substrate `system` frame pallet, that we are using. /// RPC methods of Substrate `system` frame pallet, that we are using.
#[rpc(client, client_bounds(C: Chain), namespace = "system")] #[rpc(client, client_bounds(C: Chain), namespace = "system")]
pub(crate) trait SubstrateFrameSystem<C> { pub(crate) trait SubstrateFrameSystem<C> {
@@ -29,18 +29,20 @@ use finality_grandpa::voter_set::VoterSet;
use num_traits::{One, Zero}; use num_traits::{One, Zero};
use relay_substrate_client::{ use relay_substrate_client::{
BlockNumberOf, Chain, ChainWithGrandpa, Client, Error as SubstrateError, HashOf, HeaderOf, BlockNumberOf, Chain, ChainWithGrandpa, Client, Error as SubstrateError, HashOf, HeaderOf,
Subscription, Subscription, SubstrateFinalityClient, SubstrateGrandpaFinalityClient,
}; };
use sp_core::{storage::StorageKey, Bytes}; use sp_core::{storage::StorageKey, Bytes};
use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet; use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet;
use sp_runtime::{traits::Header, ConsensusEngineId}; use sp_runtime::{traits::Header, ConsensusEngineId};
use std::marker::PhantomData; use std::marker::PhantomData;
/// Finality enfine, used by the Substrate chain. /// Finality engine, used by the Substrate chain.
#[async_trait] #[async_trait]
pub trait Engine<C: Chain>: Send { pub trait Engine<C: Chain>: Send {
/// Unique consensus engine identifier. /// Unique consensus engine identifier.
const ID: ConsensusEngineId; const ID: ConsensusEngineId;
/// Type of Finality RPC client used by this engine.
type FinalityClient: SubstrateFinalityClient<C>;
/// Type of finality proofs, used by consensus engine. /// Type of finality proofs, used by consensus engine.
type FinalityProof: FinalityProof<BlockNumberOf<C>> + Decode + Encode; type FinalityProof: FinalityProof<BlockNumberOf<C>> + Decode + Encode;
/// Type of bridge pallet initialization data. /// Type of bridge pallet initialization data.
@@ -57,7 +59,9 @@ pub trait Engine<C: Chain>: Send {
/// Note that we don't care about type of the value - just if it present or not. /// Note that we don't care about type of the value - just if it present or not.
fn is_initialized_key() -> StorageKey; fn is_initialized_key() -> StorageKey;
/// A method to subscribe to encoded finality proofs, given source client. /// A method to subscribe to encoded finality proofs, given source client.
async fn finality_proofs(client: Client<C>) -> Result<Subscription<Bytes>, SubstrateError>; async fn finality_proofs(client: &Client<C>) -> Result<Subscription<Bytes>, SubstrateError> {
client.subscribe_finality_justifications::<Self::FinalityClient>().await
}
/// Prepare initialization data for the finality bridge pallet. /// Prepare initialization data for the finality bridge pallet.
async fn prepare_initialization_data( async fn prepare_initialization_data(
client: Client<C>, client: Client<C>,
@@ -117,6 +121,7 @@ impl<C: ChainWithGrandpa> Grandpa<C> {
#[async_trait] #[async_trait]
impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> { impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> {
const ID: ConsensusEngineId = sp_finality_grandpa::GRANDPA_ENGINE_ID; const ID: ConsensusEngineId = sp_finality_grandpa::GRANDPA_ENGINE_ID;
type FinalityClient = SubstrateGrandpaFinalityClient;
type FinalityProof = GrandpaJustification<HeaderOf<C>>; type FinalityProof = GrandpaJustification<HeaderOf<C>>;
type InitializationData = bp_header_chain::InitializationData<C::Header>; type InitializationData = bp_header_chain::InitializationData<C::Header>;
type OperatingMode = BasicOperatingMode; type OperatingMode = BasicOperatingMode;
@@ -129,10 +134,6 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> {
bp_header_chain::storage_keys::best_finalized_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) bp_header_chain::storage_keys::best_finalized_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME)
} }
async fn finality_proofs(client: Client<C>) -> Result<Subscription<Bytes>, SubstrateError> {
client.subscribe_grandpa_justifications().await
}
/// Prepare initialization data for the GRANDPA verifier pallet. /// Prepare initialization data for the GRANDPA verifier pallet.
async fn prepare_initialization_data( async fn prepare_initialization_data(
source_client: Client<C>, source_client: Client<C>,
@@ -144,8 +145,7 @@ impl<C: ChainWithGrandpa> Engine<C> for Grandpa<C> {
// But now there are problems with this approach - `CurrentSetId` may return invalid value. // But now there are problems with this approach - `CurrentSetId` may return invalid value.
// So here we're waiting for the next justification, read the authorities set and then try // So here we're waiting for the next justification, read the authorities set and then try
// to figure out the set id with bruteforce. // to figure out the set id with bruteforce.
let justifications = source_client let justifications = Self::finality_proofs(&source_client)
.subscribe_grandpa_justifications()
.await .await
.map_err(|err| Error::Subscribe(C::NAME, err))?; .map_err(|err| Error::Subscribe(C::NAME, err))?;
// Read next justification - the header that it finalizes will be used as initial header. // Read next justification - the header that it finalizes will be used as initial header.
@@ -142,7 +142,7 @@ impl<P: SubstrateFinalitySyncPipeline> SourceClient<FinalitySyncPipelineAdapter<
async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> { async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, Error> {
Ok(unfold( Ok(unfold(
P::FinalityEngine::finality_proofs(self.client.clone()).await?, P::FinalityEngine::finality_proofs(&self.client).await?,
move |subscription| async move { move |subscription| async move {
loop { loop {
let log_error = |err| { let log_error = |err| {