estimate transaction fee (#1015)

This commit is contained in:
Svyatoslav Nikolsky
2021-06-28 12:13:53 +03:00
committed by Bastian Köcher
parent 165730a2c2
commit db0216dabb
20 changed files with 294 additions and 72 deletions
@@ -127,11 +127,11 @@ impl SubstrateMessageLane for MillauMessagesToRialto {
/// Millau node as messages source.
type MillauSourceClient =
SubstrateMessagesSource<Millau, MillauMessagesToRialto, millau_runtime::WithRialtoMessagesInstance>;
SubstrateMessagesSource<Millau, Rialto, MillauMessagesToRialto, millau_runtime::WithRialtoMessagesInstance>;
/// Rialto node as messages target.
type RialtoTargetClient =
SubstrateMessagesTarget<Rialto, MillauMessagesToRialto, rialto_runtime::WithMillauMessagesInstance>;
SubstrateMessagesTarget<Millau, Rialto, MillauMessagesToRialto, rialto_runtime::WithMillauMessagesInstance>;
/// Run Millau-to-Rialto messages sync.
pub async fn run(
@@ -127,11 +127,11 @@ impl SubstrateMessageLane for RialtoMessagesToMillau {
/// Rialto node as messages source.
type RialtoSourceClient =
SubstrateMessagesSource<Rialto, RialtoMessagesToMillau, rialto_runtime::WithMillauMessagesInstance>;
SubstrateMessagesSource<Rialto, Millau, RialtoMessagesToMillau, rialto_runtime::WithMillauMessagesInstance>;
/// Millau node as messages target.
type MillauTargetClient =
SubstrateMessagesTarget<Millau, RialtoMessagesToMillau, millau_runtime::WithRialtoMessagesInstance>;
SubstrateMessagesTarget<Rialto, Millau, RialtoMessagesToMillau, millau_runtime::WithRialtoMessagesInstance>;
/// Run Rialto-to-Millau messages sync.
pub async fn run(
@@ -124,12 +124,20 @@ impl SubstrateMessageLane for RococoMessagesToWococo {
}
/// Rococo node as messages source.
type RococoSourceClient =
SubstrateMessagesSource<Rococo, RococoMessagesToWococo, relay_rococo_client::runtime::WithWococoMessagesInstance>;
type RococoSourceClient = SubstrateMessagesSource<
Rococo,
Wococo,
RococoMessagesToWococo,
relay_rococo_client::runtime::WithWococoMessagesInstance,
>;
/// Wococo node as messages target.
type WococoTargetClient =
SubstrateMessagesTarget<Wococo, RococoMessagesToWococo, relay_wococo_client::runtime::WithRococoMessagesInstance>;
type WococoTargetClient = SubstrateMessagesTarget<
Rococo,
Wococo,
RococoMessagesToWococo,
relay_wococo_client::runtime::WithRococoMessagesInstance,
>;
/// Run Rococo-to-Wococo messages sync.
pub async fn run(
@@ -124,12 +124,20 @@ impl SubstrateMessageLane for WococoMessagesToRococo {
}
/// Wococo node as messages source.
type WococoSourceClient =
SubstrateMessagesSource<Wococo, WococoMessagesToRococo, relay_wococo_client::runtime::WithRococoMessagesInstance>;
type WococoSourceClient = SubstrateMessagesSource<
Wococo,
Rococo,
WococoMessagesToRococo,
relay_wococo_client::runtime::WithRococoMessagesInstance,
>;
/// Rococo node as messages target.
type RococoTargetClient =
SubstrateMessagesTarget<Rococo, WococoMessagesToRococo, relay_rococo_client::runtime::WithWococoMessagesInstance>;
type RococoTargetClient = SubstrateMessagesTarget<
Wococo,
Rococo,
WococoMessagesToRococo,
relay_rococo_client::runtime::WithWococoMessagesInstance,
>;
/// Run Wococo-to-Rococo messages sync.
pub async fn run(
@@ -19,12 +19,15 @@
//! <BridgedName> chain.
use crate::messages_lane::SubstrateMessageLane;
use crate::messages_target::SubstrateMessagesReceivingProof;
use crate::on_demand_headers::OnDemandHeadersRelay;
use async_trait::async_trait;
use bp_messages::{LaneId, MessageNonce};
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState};
use bp_runtime::{messages::DispatchFeePayment, ChainId};
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
use bridge_runtime_common::messages::{
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
};
use codec::{Decode, Encode};
use frame_support::{traits::Instance, weights::Weight};
use messages_relay::{
@@ -33,6 +36,7 @@ use messages_relay::{
ClientState, MessageDetails, MessageDetailsMap, MessageProofParameters, SourceClient, SourceClientState,
},
};
use num_traits::{Bounded, Zero};
use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf, HeaderIdOf};
use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId};
use sp_core::Bytes;
@@ -45,23 +49,23 @@ use std::{marker::PhantomData, ops::RangeInclusive};
pub type SubstrateMessagesProof<C> = (Weight, FromBridgedChainMessagesProof<HashOf<C>>);
/// Substrate client as Substrate messages source.
pub struct SubstrateMessagesSource<C: Chain, P: SubstrateMessageLane, I> {
client: Client<C>,
pub struct SubstrateMessagesSource<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> {
client: Client<SC>,
lane: P,
lane_id: LaneId,
instance: ChainId,
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>,
target_to_source_headers_relay: Option<OnDemandHeadersRelay<TC>>,
_phantom: PhantomData<I>,
}
impl<C: Chain, P: SubstrateMessageLane, I> SubstrateMessagesSource<C, P, I> {
impl<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> SubstrateMessagesSource<SC, TC, P, I> {
/// Create new Substrate headers source.
pub fn new(
client: Client<C>,
client: Client<SC>,
lane: P,
lane_id: LaneId,
instance: ChainId,
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>,
target_to_source_headers_relay: Option<OnDemandHeadersRelay<TC>>,
) -> Self {
SubstrateMessagesSource {
client,
@@ -74,7 +78,7 @@ impl<C: Chain, P: SubstrateMessageLane, I> SubstrateMessagesSource<C, P, I> {
}
}
impl<C: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesSource<C, P, I> {
impl<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesSource<SC, TC, P, I> {
fn clone(&self) -> Self {
Self {
client: self.client.clone(),
@@ -88,9 +92,10 @@ impl<C: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesSource<C,
}
#[async_trait]
impl<C, P, I> RelayClient for SubstrateMessagesSource<C, P, I>
impl<SC, TC, P, I> RelayClient for SubstrateMessagesSource<SC, TC, P, I>
where
C: Chain,
SC: Chain,
TC: Chain,
P: SubstrateMessageLane,
I: Send + Sync + Instance,
{
@@ -102,20 +107,22 @@ where
}
#[async_trait]
impl<C, P, I> SourceClient<P> for SubstrateMessagesSource<C, P, I>
impl<SC, TC, P, I> SourceClient<P> for SubstrateMessagesSource<SC, TC, P, I>
where
C: Chain,
C::Header: DeserializeOwned,
C::Index: DeserializeOwned,
C::BlockNumber: BlockNumberBase,
SC: Chain<Hash = P::SourceHeaderHash, BlockNumber = P::SourceHeaderNumber, Balance = P::SourceChainBalance>,
SC::Hash: Copy,
SC::BlockNumber: Copy,
SC::Balance: Decode + Bounded,
SC::Header: DeserializeOwned,
SC::Index: DeserializeOwned,
SC::BlockNumber: BlockNumberBase,
TC: Chain<Hash = P::TargetHeaderHash, BlockNumber = P::TargetHeaderNumber>,
P: SubstrateMessageLane<
MessagesProof = SubstrateMessagesProof<C>,
SourceChainBalance = C::Balance,
SourceHeaderNumber = <C::Header as HeaderT>::Number,
SourceHeaderHash = <C::Header as HeaderT>::Hash,
SourceChain = C,
MessagesProof = SubstrateMessagesProof<SC>,
MessagesReceivingProof = SubstrateMessagesReceivingProof<TC>,
SourceChain = SC,
TargetChain = TC,
>,
P::TargetChain: Chain<Hash = P::TargetHeaderHash, BlockNumber = P::TargetHeaderNumber>,
P::TargetHeaderNumber: Decode,
P::TargetHeaderHash: Decode,
I: Send + Sync + Instance,
@@ -180,7 +187,7 @@ where
)
.await?;
make_message_details_map::<C>(
make_message_details_map::<SC>(
Decode::decode(&mut &encoded_response.0[..]).map_err(SubstrateError::ResponseParseFailed)?,
nonces,
)
@@ -242,10 +249,40 @@ where
}
async fn estimate_confirmation_transaction(&self) -> P::SourceChainBalance {
num_traits::Zero::zero() // TODO: https://github.com/paritytech/parity-bridges-common/issues/997
self.client
.estimate_extrinsic_fee(self.lane.make_messages_receiving_proof_transaction(
Zero::zero(),
HeaderId(Default::default(), Default::default()),
prepare_dummy_messages_delivery_proof::<SC, TC>(),
))
.await
.unwrap_or_else(|_| SC::Balance::max_value())
}
}
/// Prepare 'dummy' messages delivery proof that will compose the delivery confirmation transaction.
///
/// We don't care about proof actually being the valid proof, because its validity doesn't
/// affect the call weight - we only care about its size.
fn prepare_dummy_messages_delivery_proof<SC: Chain, TC: Chain>() -> SubstrateMessagesReceivingProof<TC> {
let single_message_confirmation_size =
bp_messages::InboundLaneData::<()>::encoded_size_hint(SC::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, 1, 1)
.unwrap_or(u32::MAX);
let proof_size = TC::STORAGE_PROOF_OVERHEAD.saturating_add(single_message_confirmation_size);
(
UnrewardedRelayersState {
unrewarded_relayer_entries: 1,
messages_in_oldest_entry: 1,
total_messages: 1,
},
FromBridgedChainMessagesDeliveryProof {
bridged_header_hash: Default::default(),
storage_proof: vec![vec![0; proof_size as usize]],
lane: Default::default(),
},
)
}
pub async fn read_client_state<SelfChain, BridgedHeaderHash, BridgedHeaderNumber>(
self_client: &Client<SelfChain>,
best_finalized_header_id_method_name: &str,
@@ -295,7 +332,7 @@ fn make_message_details_map<C: Chain>(
) -> Result<MessageDetailsMap<C::Balance>, SubstrateError> {
let make_missing_nonce_error = |expected_nonce| {
Err(SubstrateError::Custom(format!(
"Missing nonce {} in messages_dispatch_weight call result. Expected all nonces from {:?}",
"Missing nonce {} in message_details call result. Expected all nonces from {:?}",
expected_nonce, nonces,
)))
};
@@ -346,8 +383,7 @@ fn make_message_details_map<C: Chain>(
MessageDetails {
dispatch_weight: details.dispatch_weight,
size: details.size as _,
// TODO: https://github.com/paritytech/parity-bridges-common/issues/997
reward: num_traits::Zero::zero(),
reward: details.delivery_and_dispatch_fee,
dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
},
);
@@ -361,6 +397,9 @@ fn make_message_details_map<C: Chain>(
#[cfg(test)]
mod tests {
use super::*;
use bp_runtime::messages::DispatchFeePayment;
use relay_millau_client::Millau;
use relay_rialto_client::Rialto;
fn message_details_from_rpc(
nonces: RangeInclusive<MessageNonce>,
@@ -469,4 +508,16 @@ mod tests {
Err(SubstrateError::Custom(_))
));
}
#[test]
fn prepare_dummy_messages_delivery_proof_works() {
let expected_minimal_size = Rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE + Millau::STORAGE_PROOF_OVERHEAD;
let dummy_proof = prepare_dummy_messages_delivery_proof::<Rialto, Millau>();
assert!(
dummy_proof.1.encode().len() as u32 > expected_minimal_size,
"Expected proof size at least {}. Got: {}",
expected_minimal_size,
dummy_proof.1.encode().len(),
);
}
}
@@ -19,24 +19,27 @@
//! <BridgedName> chain.
use crate::messages_lane::SubstrateMessageLane;
use crate::messages_source::read_client_state;
use crate::messages_source::{read_client_state, SubstrateMessagesProof};
use crate::on_demand_headers::OnDemandHeadersRelay;
use async_trait::async_trait;
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState};
use bp_runtime::ChainId;
use bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof;
use bridge_runtime_common::messages::{
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
};
use codec::{Decode, Encode};
use frame_support::{traits::Instance, weights::Weight};
use messages_relay::{
message_lane::{SourceHeaderIdOf, TargetHeaderIdOf},
message_lane_loop::{TargetClient, TargetClientState},
};
use num_traits::{Bounded, One, Zero};
use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf};
use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase};
use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId};
use sp_core::Bytes;
use sp_runtime::{traits::Header as HeaderT, DeserializeOwned};
use std::{marker::PhantomData, ops::RangeInclusive};
use sp_runtime::{traits::Header as HeaderT, DeserializeOwned, FixedPointNumber, FixedU128};
use std::{convert::TryFrom, marker::PhantomData, ops::RangeInclusive};
/// Message receiving proof returned by the target Substrate node.
pub type SubstrateMessagesReceivingProof<C> = (
@@ -45,23 +48,23 @@ pub type SubstrateMessagesReceivingProof<C> = (
);
/// Substrate client as Substrate messages target.
pub struct SubstrateMessagesTarget<C: Chain, P: SubstrateMessageLane, I> {
client: Client<C>,
pub struct SubstrateMessagesTarget<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> {
client: Client<TC>,
lane: P,
lane_id: LaneId,
instance: ChainId,
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>,
source_to_target_headers_relay: Option<OnDemandHeadersRelay<SC>>,
_phantom: PhantomData<I>,
}
impl<C: Chain, P: SubstrateMessageLane, I> SubstrateMessagesTarget<C, P, I> {
impl<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> SubstrateMessagesTarget<SC, TC, P, I> {
/// Create new Substrate headers target.
pub fn new(
client: Client<C>,
client: Client<TC>,
lane: P,
lane_id: LaneId,
instance: ChainId,
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>,
source_to_target_headers_relay: Option<OnDemandHeadersRelay<SC>>,
) -> Self {
SubstrateMessagesTarget {
client,
@@ -74,7 +77,7 @@ impl<C: Chain, P: SubstrateMessageLane, I> SubstrateMessagesTarget<C, P, I> {
}
}
impl<C: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesTarget<C, P, I> {
impl<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesTarget<SC, TC, P, I> {
fn clone(&self) -> Self {
Self {
client: self.client.clone(),
@@ -88,9 +91,10 @@ impl<C: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesTarget<C,
}
#[async_trait]
impl<C, P, I> RelayClient for SubstrateMessagesTarget<C, P, I>
impl<SC, TC, P, I> RelayClient for SubstrateMessagesTarget<SC, TC, P, I>
where
C: Chain,
SC: Chain,
TC: Chain,
P: SubstrateMessageLane,
I: Send + Sync + Instance,
{
@@ -102,19 +106,22 @@ where
}
#[async_trait]
impl<C, P, I> TargetClient<P> for SubstrateMessagesTarget<C, P, I>
impl<SC, TC, P, I> TargetClient<P> for SubstrateMessagesTarget<SC, TC, P, I>
where
C: Chain,
C::Header: DeserializeOwned,
C::Index: DeserializeOwned,
<C::Header as HeaderT>::Number: BlockNumberBase,
SC: Chain<Hash = P::SourceHeaderHash, BlockNumber = P::SourceHeaderNumber, Balance = P::SourceChainBalance>,
SC::Balance: TryFrom<TC::Balance> + Bounded,
TC: Chain<Hash = P::TargetHeaderHash, BlockNumber = P::TargetHeaderNumber>,
TC::Hash: Copy,
TC::BlockNumber: Copy,
TC::Header: DeserializeOwned,
TC::Index: DeserializeOwned,
<TC::Header as HeaderT>::Number: BlockNumberBase,
P: SubstrateMessageLane<
TargetChain = C,
MessagesReceivingProof = SubstrateMessagesReceivingProof<C>,
TargetHeaderNumber = <C::Header as HeaderT>::Number,
TargetHeaderHash = <C::Header as HeaderT>::Hash,
MessagesProof = SubstrateMessagesProof<SC>,
MessagesReceivingProof = SubstrateMessagesReceivingProof<TC>,
SourceChain = SC,
TargetChain = TC,
>,
P::SourceChain: Chain<Hash = P::SourceHeaderHash, BlockNumber = P::SourceHeaderNumber>,
P::SourceHeaderNumber: Decode,
P::SourceHeaderHash: Decode,
I: Send + Sync + Instance,
@@ -229,10 +236,93 @@ where
async fn estimate_delivery_transaction_in_source_tokens(
&self,
_nonces: RangeInclusive<MessageNonce>,
_total_dispatch_weight: Weight,
_total_size: u32,
nonces: RangeInclusive<MessageNonce>,
total_dispatch_weight: Weight,
total_size: u32,
) -> P::SourceChainBalance {
num_traits::Zero::zero() // TODO: https://github.com/paritytech/parity-bridges-common/issues/997
// TODO: use actual rate (https://github.com/paritytech/parity-bridges-common/issues/997)
convert_target_tokens_to_source_tokens::<SC, TC>(
FixedU128::one(),
self.client
.estimate_extrinsic_fee(self.lane.make_messages_delivery_transaction(
Zero::zero(),
HeaderId(Default::default(), Default::default()),
nonces.clone(),
prepare_dummy_messages_proof::<SC>(nonces, total_dispatch_weight, total_size),
))
.await
.unwrap_or_else(|_| TC::Balance::max_value()),
)
}
}
/// Prepare 'dummy' messages proof that will compose the delivery transaction.
///
/// We don't care about proof actually being the valid proof, because its validity doesn't
/// affect the call weight - we only care about its size.
fn prepare_dummy_messages_proof<SC: Chain>(
nonces: RangeInclusive<MessageNonce>,
total_dispatch_weight: Weight,
total_size: u32,
) -> SubstrateMessagesProof<SC> {
(
total_dispatch_weight,
FromBridgedChainMessagesProof {
bridged_header_hash: Default::default(),
storage_proof: vec![vec![0; SC::STORAGE_PROOF_OVERHEAD.saturating_add(total_size) as usize]],
lane: Default::default(),
nonces_start: *nonces.start(),
nonces_end: *nonces.end(),
},
)
}
/// Given delivery transaction fee in target chain tokens and conversion rate to the source
/// chain tokens, compute transaction cost in source chain tokens.
fn convert_target_tokens_to_source_tokens<SC: Chain, TC: Chain>(
target_to_source_conversion_rate: FixedU128,
target_transaction_fee: TC::Balance,
) -> SC::Balance
where
SC::Balance: TryFrom<TC::Balance>,
{
SC::Balance::try_from(target_to_source_conversion_rate.saturating_mul_int(target_transaction_fee))
.unwrap_or_else(|_| SC::Balance::max_value())
}
#[cfg(test)]
mod tests {
use super::*;
use relay_millau_client::Millau;
use relay_rialto_client::Rialto;
#[test]
fn prepare_dummy_messages_proof_works() {
const DISPATCH_WEIGHT: Weight = 1_000_000;
const SIZE: u32 = 1_000;
let dummy_proof = prepare_dummy_messages_proof::<Rialto>(1..=10, DISPATCH_WEIGHT, SIZE);
assert_eq!(dummy_proof.0, DISPATCH_WEIGHT);
assert!(
dummy_proof.1.encode().len() as u32 > SIZE,
"Expected proof size at least {}. Got: {}",
SIZE,
dummy_proof.1.encode().len(),
);
}
#[test]
fn convert_target_tokens_to_source_tokens_works() {
assert_eq!(
convert_target_tokens_to_source_tokens::<Rialto, Millau>((150, 100).into(), 1_000),
1_500
);
assert_eq!(
convert_target_tokens_to_source_tokens::<Rialto, Millau>((50, 100).into(), 1_000),
500
);
assert_eq!(
convert_target_tokens_to_source_tokens::<Rialto, Millau>((100, 100).into(), 1_000),
1_000
);
}
}
+2
View File
@@ -36,6 +36,8 @@ impl ChainBase for Kusama {
impl Chain for Kusama {
const NAME: &'static str = "Kusama";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
type AccountId = bp_kusama::AccountId;
type Index = bp_kusama::Nonce;
+1
View File
@@ -13,6 +13,7 @@ relay-utils = { path = "../utils" }
# Supported Chains
bp-millau = { path = "../../primitives/chain-millau" }
millau-runtime = { path = "../../bin/millau/runtime" }
# Substrate Dependencies
+2
View File
@@ -39,6 +39,8 @@ impl ChainBase for Millau {
impl Chain for Millau {
const NAME: &'static str = "Millau";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
type AccountId = millau_runtime::AccountId;
type Index = millau_runtime::Index;
@@ -36,6 +36,8 @@ impl ChainBase for Polkadot {
impl Chain for Polkadot {
const NAME: &'static str = "Polkadot";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
type AccountId = bp_polkadot::AccountId;
type Index = bp_polkadot::Nonce;
+1
View File
@@ -13,6 +13,7 @@ relay-utils = { path = "../utils" }
# Bridge dependencies
bp-rialto = { path = "../../primitives/chain-rialto" }
rialto-runtime = { path = "../../bin/rialto/runtime" }
# Substrate Dependencies
+2
View File
@@ -39,6 +39,8 @@ impl ChainBase for Rialto {
impl Chain for Rialto {
const NAME: &'static str = "Rialto";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
type AccountId = rialto_runtime::AccountId;
type Index = rialto_runtime::Index;
+2
View File
@@ -44,6 +44,8 @@ impl ChainBase for Rococo {
impl Chain for Rococo {
const NAME: &'static str = "Rococo";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
type AccountId = bp_rococo::AccountId;
type Index = bp_rococo::Index;
@@ -29,9 +29,12 @@ relay-utils = { path = "../utils" }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" }
+22 -4
View File
@@ -17,14 +17,15 @@
use bp_runtime::Chain as ChainBase;
use frame_support::Parameter;
use jsonrpsee_ws_client::{DeserializeOwned, Serialize};
use num_traits::{CheckedSub, SaturatingAdd, Zero};
use num_traits::{Bounded, CheckedSub, SaturatingAdd, Zero};
use sp_core::{storage::StorageKey, Pair};
use sp_runtime::{
generic::SignedBlock,
traits::{
AtLeast32Bit, Block as BlockT, Dispatchable, MaybeDisplay, MaybeSerialize, MaybeSerializeDeserialize, Member,
AtLeast32Bit, AtLeast32BitUnsigned, Block as BlockT, Dispatchable, MaybeDisplay, MaybeSerialize,
MaybeSerializeDeserialize, Member,
},
EncodedJustification,
EncodedJustification, FixedPointOperand,
};
use std::{fmt::Debug, time::Duration};
@@ -37,6 +38,10 @@ pub trait Chain: ChainBase + Clone {
/// How often blocks are produced on that chain. It's suggested to set this value
/// to match the block time of the chain.
const AVERAGE_BLOCK_INTERVAL: Duration;
/// Maximal expected storage proof overhead (in bytes).
const STORAGE_PROOF_OVERHEAD: u32;
/// Maximal size (in bytes) of SCALE-encoded account id on this chain.
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32;
/// The user account identifier type for the runtime.
type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + Default;
@@ -58,7 +63,20 @@ pub trait Chain: ChainBase + Clone {
///
/// The chain may suport multiple tokens, but this particular type is for token that is used
/// to pay for transaction dispatch, to reward different relayers (headers, messages), etc.
type Balance: Parameter + Member + DeserializeOwned + Clone + Copy + CheckedSub + PartialOrd + SaturatingAdd + Zero;
type Balance: AtLeast32BitUnsigned
+ FixedPointOperand
+ Parameter
+ Parameter
+ Member
+ DeserializeOwned
+ Clone
+ Copy
+ Bounded
+ CheckedSub
+ PartialOrd
+ SaturatingAdd
+ Zero
+ std::convert::TryFrom<sp_core::U256>;
}
/// Substrate-based chain with `frame_system::Config::AccountData` set to
+23 -1
View File
@@ -25,12 +25,14 @@ use codec::Decode;
use frame_system::AccountInfo;
use jsonrpsee_ws_client::{traits::SubscriptionClient, v2::params::JsonRpcParams, DeserializeOwned};
use jsonrpsee_ws_client::{Subscription, WsClient as RpcClient, WsClientBuilder as RpcClientBuilder};
use num_traits::Zero;
use num_traits::{Bounded, Zero};
use pallet_balances::AccountData;
use pallet_transaction_payment::InclusionFee;
use relay_utils::relay_loop::RECONNECT_DELAY;
use sp_core::{storage::StorageKey, Bytes};
use sp_trie::StorageProof;
use sp_version::RuntimeVersion;
use std::convert::TryFrom;
const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities";
const MAX_SUBSCRIPTION_CAPACITY: usize = 4096;
@@ -258,6 +260,26 @@ impl<C: Chain> Client<C> {
Ok(tx_hash)
}
/// Estimate fee that will be spent on given extrinsic.
pub async fn estimate_extrinsic_fee(&self, transaction: Bytes) -> Result<C::Balance> {
let fee_details = Substrate::<C>::payment_query_fee_details(&*self.client, transaction, None).await?;
let inclusion_fee = fee_details
.inclusion_fee
.map(|inclusion_fee| {
InclusionFee {
base_fee: C::Balance::try_from(inclusion_fee.base_fee.into_u256())
.unwrap_or_else(|_| C::Balance::max_value()),
len_fee: C::Balance::try_from(inclusion_fee.len_fee.into_u256())
.unwrap_or_else(|_| C::Balance::max_value()),
adjusted_weight_fee: C::Balance::try_from(inclusion_fee.adjusted_weight_fee.into_u256())
.unwrap_or_else(|_| C::Balance::max_value()),
}
.inclusion_fee()
})
.unwrap_or_else(Zero::zero);
Ok(inclusion_fee)
}
/// Get the GRANDPA authority set at given block.
pub async fn grandpa_authorities_set(&self, block: C::Hash) -> Result<OpaqueGrandpaAuthoritiesSet> {
let call = SUB_API_GRANDPA_AUTHORITIES.to_string();
@@ -185,6 +185,8 @@ mod tests {
impl Chain for TestChain {
const NAME: &'static str = "Test";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1);
const STORAGE_PROOF_OVERHEAD: u32 = 0;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0;
type AccountId = u32;
type Index = u32;
@@ -18,11 +18,13 @@
use crate::chain::Chain;
use pallet_transaction_payment_rpc_runtime_api::FeeDetails;
use sc_rpc_api::{state::ReadProof, system::Health};
use sp_core::{
storage::{StorageData, StorageKey},
Bytes,
};
use sp_rpc::number::NumberOrHex;
use sp_version::RuntimeVersion;
jsonrpsee_proc_macros::rpc_client_api! {
@@ -49,5 +51,7 @@ jsonrpsee_proc_macros::rpc_client_api! {
fn state_prove_storage(keys: Vec<StorageKey>, hash: Option<C::Hash>) -> ReadProof<C::Hash>;
#[rpc(method = "state_getRuntimeVersion", positional_params)]
fn state_runtime_version() -> RuntimeVersion;
#[rpc(method = "payment_queryFeeDetails", positional_params)]
fn payment_query_fee_details(extrinsic: Bytes, at_block: Option<C::Hash>) -> FeeDetails<NumberOrHex>;
}
}
+2
View File
@@ -42,6 +42,8 @@ impl ChainBase for Westend {
impl Chain for Westend {
const NAME: &'static str = "Westend";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
type AccountId = bp_westend::AccountId;
type Index = bp_westend::Nonce;
+2
View File
@@ -44,6 +44,8 @@ impl ChainBase for Wococo {
impl Chain for Wococo {
const NAME: &'static str = "Wococo";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE;
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
type AccountId = bp_wococo::AccountId;
type Index = bp_wococo::Index;