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. /// Millau node as messages source.
type MillauSourceClient = type MillauSourceClient =
SubstrateMessagesSource<Millau, MillauMessagesToRialto, millau_runtime::WithRialtoMessagesInstance>; SubstrateMessagesSource<Millau, Rialto, MillauMessagesToRialto, millau_runtime::WithRialtoMessagesInstance>;
/// Rialto node as messages target. /// Rialto node as messages target.
type RialtoTargetClient = type RialtoTargetClient =
SubstrateMessagesTarget<Rialto, MillauMessagesToRialto, rialto_runtime::WithMillauMessagesInstance>; SubstrateMessagesTarget<Millau, Rialto, MillauMessagesToRialto, rialto_runtime::WithMillauMessagesInstance>;
/// Run Millau-to-Rialto messages sync. /// Run Millau-to-Rialto messages sync.
pub async fn run( pub async fn run(
@@ -127,11 +127,11 @@ impl SubstrateMessageLane for RialtoMessagesToMillau {
/// Rialto node as messages source. /// Rialto node as messages source.
type RialtoSourceClient = type RialtoSourceClient =
SubstrateMessagesSource<Rialto, RialtoMessagesToMillau, rialto_runtime::WithMillauMessagesInstance>; SubstrateMessagesSource<Rialto, Millau, RialtoMessagesToMillau, rialto_runtime::WithMillauMessagesInstance>;
/// Millau node as messages target. /// Millau node as messages target.
type MillauTargetClient = type MillauTargetClient =
SubstrateMessagesTarget<Millau, RialtoMessagesToMillau, millau_runtime::WithRialtoMessagesInstance>; SubstrateMessagesTarget<Rialto, Millau, RialtoMessagesToMillau, millau_runtime::WithRialtoMessagesInstance>;
/// Run Rialto-to-Millau messages sync. /// Run Rialto-to-Millau messages sync.
pub async fn run( pub async fn run(
@@ -124,12 +124,20 @@ impl SubstrateMessageLane for RococoMessagesToWococo {
} }
/// Rococo node as messages source. /// Rococo node as messages source.
type RococoSourceClient = type RococoSourceClient = SubstrateMessagesSource<
SubstrateMessagesSource<Rococo, RococoMessagesToWococo, relay_rococo_client::runtime::WithWococoMessagesInstance>; Rococo,
Wococo,
RococoMessagesToWococo,
relay_rococo_client::runtime::WithWococoMessagesInstance,
>;
/// Wococo node as messages target. /// Wococo node as messages target.
type WococoTargetClient = type WococoTargetClient = SubstrateMessagesTarget<
SubstrateMessagesTarget<Wococo, RococoMessagesToWococo, relay_wococo_client::runtime::WithRococoMessagesInstance>; Rococo,
Wococo,
RococoMessagesToWococo,
relay_wococo_client::runtime::WithRococoMessagesInstance,
>;
/// Run Rococo-to-Wococo messages sync. /// Run Rococo-to-Wococo messages sync.
pub async fn run( pub async fn run(
@@ -124,12 +124,20 @@ impl SubstrateMessageLane for WococoMessagesToRococo {
} }
/// Wococo node as messages source. /// Wococo node as messages source.
type WococoSourceClient = type WococoSourceClient = SubstrateMessagesSource<
SubstrateMessagesSource<Wococo, WococoMessagesToRococo, relay_wococo_client::runtime::WithRococoMessagesInstance>; Wococo,
Rococo,
WococoMessagesToRococo,
relay_wococo_client::runtime::WithRococoMessagesInstance,
>;
/// Rococo node as messages target. /// Rococo node as messages target.
type RococoTargetClient = type RococoTargetClient = SubstrateMessagesTarget<
SubstrateMessagesTarget<Rococo, WococoMessagesToRococo, relay_rococo_client::runtime::WithWococoMessagesInstance>; Wococo,
Rococo,
WococoMessagesToRococo,
relay_rococo_client::runtime::WithWococoMessagesInstance,
>;
/// Run Wococo-to-Rococo messages sync. /// Run Wococo-to-Rococo messages sync.
pub async fn run( pub async fn run(
@@ -19,12 +19,15 @@
//! <BridgedName> chain. //! <BridgedName> chain.
use crate::messages_lane::SubstrateMessageLane; use crate::messages_lane::SubstrateMessageLane;
use crate::messages_target::SubstrateMessagesReceivingProof;
use crate::on_demand_headers::OnDemandHeadersRelay; use crate::on_demand_headers::OnDemandHeadersRelay;
use async_trait::async_trait; use async_trait::async_trait;
use bp_messages::{LaneId, MessageNonce}; use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState};
use bp_runtime::{messages::DispatchFeePayment, ChainId}; 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 codec::{Decode, Encode};
use frame_support::{traits::Instance, weights::Weight}; use frame_support::{traits::Instance, weights::Weight};
use messages_relay::{ use messages_relay::{
@@ -33,6 +36,7 @@ use messages_relay::{
ClientState, MessageDetails, MessageDetailsMap, MessageProofParameters, SourceClient, SourceClientState, ClientState, MessageDetails, MessageDetailsMap, MessageProofParameters, SourceClient, SourceClientState,
}, },
}; };
use num_traits::{Bounded, Zero};
use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf, HeaderIdOf}; use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf, HeaderIdOf};
use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId}; use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId};
use sp_core::Bytes; use sp_core::Bytes;
@@ -45,23 +49,23 @@ use std::{marker::PhantomData, ops::RangeInclusive};
pub type SubstrateMessagesProof<C> = (Weight, FromBridgedChainMessagesProof<HashOf<C>>); pub type SubstrateMessagesProof<C> = (Weight, FromBridgedChainMessagesProof<HashOf<C>>);
/// Substrate client as Substrate messages source. /// Substrate client as Substrate messages source.
pub struct SubstrateMessagesSource<C: Chain, P: SubstrateMessageLane, I> { pub struct SubstrateMessagesSource<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> {
client: Client<C>, client: Client<SC>,
lane: P, lane: P,
lane_id: LaneId, lane_id: LaneId,
instance: ChainId, instance: ChainId,
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>, target_to_source_headers_relay: Option<OnDemandHeadersRelay<TC>>,
_phantom: PhantomData<I>, _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. /// Create new Substrate headers source.
pub fn new( pub fn new(
client: Client<C>, client: Client<SC>,
lane: P, lane: P,
lane_id: LaneId, lane_id: LaneId,
instance: ChainId, instance: ChainId,
target_to_source_headers_relay: Option<OnDemandHeadersRelay<P::TargetChain>>, target_to_source_headers_relay: Option<OnDemandHeadersRelay<TC>>,
) -> Self { ) -> Self {
SubstrateMessagesSource { SubstrateMessagesSource {
client, 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 { fn clone(&self) -> Self {
Self { Self {
client: self.client.clone(), client: self.client.clone(),
@@ -88,9 +92,10 @@ impl<C: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesSource<C,
} }
#[async_trait] #[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 where
C: Chain, SC: Chain,
TC: Chain,
P: SubstrateMessageLane, P: SubstrateMessageLane,
I: Send + Sync + Instance, I: Send + Sync + Instance,
{ {
@@ -102,20 +107,22 @@ where
} }
#[async_trait] #[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 where
C: Chain, SC: Chain<Hash = P::SourceHeaderHash, BlockNumber = P::SourceHeaderNumber, Balance = P::SourceChainBalance>,
C::Header: DeserializeOwned, SC::Hash: Copy,
C::Index: DeserializeOwned, SC::BlockNumber: Copy,
C::BlockNumber: BlockNumberBase, SC::Balance: Decode + Bounded,
SC::Header: DeserializeOwned,
SC::Index: DeserializeOwned,
SC::BlockNumber: BlockNumberBase,
TC: Chain<Hash = P::TargetHeaderHash, BlockNumber = P::TargetHeaderNumber>,
P: SubstrateMessageLane< P: SubstrateMessageLane<
MessagesProof = SubstrateMessagesProof<C>, MessagesProof = SubstrateMessagesProof<SC>,
SourceChainBalance = C::Balance, MessagesReceivingProof = SubstrateMessagesReceivingProof<TC>,
SourceHeaderNumber = <C::Header as HeaderT>::Number, SourceChain = SC,
SourceHeaderHash = <C::Header as HeaderT>::Hash, TargetChain = TC,
SourceChain = C,
>, >,
P::TargetChain: Chain<Hash = P::TargetHeaderHash, BlockNumber = P::TargetHeaderNumber>,
P::TargetHeaderNumber: Decode, P::TargetHeaderNumber: Decode,
P::TargetHeaderHash: Decode, P::TargetHeaderHash: Decode,
I: Send + Sync + Instance, I: Send + Sync + Instance,
@@ -180,7 +187,7 @@ where
) )
.await?; .await?;
make_message_details_map::<C>( make_message_details_map::<SC>(
Decode::decode(&mut &encoded_response.0[..]).map_err(SubstrateError::ResponseParseFailed)?, Decode::decode(&mut &encoded_response.0[..]).map_err(SubstrateError::ResponseParseFailed)?,
nonces, nonces,
) )
@@ -242,10 +249,40 @@ where
} }
async fn estimate_confirmation_transaction(&self) -> P::SourceChainBalance { 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>( pub async fn read_client_state<SelfChain, BridgedHeaderHash, BridgedHeaderNumber>(
self_client: &Client<SelfChain>, self_client: &Client<SelfChain>,
best_finalized_header_id_method_name: &str, best_finalized_header_id_method_name: &str,
@@ -295,7 +332,7 @@ fn make_message_details_map<C: Chain>(
) -> Result<MessageDetailsMap<C::Balance>, SubstrateError> { ) -> Result<MessageDetailsMap<C::Balance>, SubstrateError> {
let make_missing_nonce_error = |expected_nonce| { let make_missing_nonce_error = |expected_nonce| {
Err(SubstrateError::Custom(format!( 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, expected_nonce, nonces,
))) )))
}; };
@@ -346,8 +383,7 @@ fn make_message_details_map<C: Chain>(
MessageDetails { MessageDetails {
dispatch_weight: details.dispatch_weight, dispatch_weight: details.dispatch_weight,
size: details.size as _, size: details.size as _,
// TODO: https://github.com/paritytech/parity-bridges-common/issues/997 reward: details.delivery_and_dispatch_fee,
reward: num_traits::Zero::zero(),
dispatch_fee_payment: DispatchFeePayment::AtSourceChain, dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
}, },
); );
@@ -361,6 +397,9 @@ fn make_message_details_map<C: Chain>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use bp_runtime::messages::DispatchFeePayment;
use relay_millau_client::Millau;
use relay_rialto_client::Rialto;
fn message_details_from_rpc( fn message_details_from_rpc(
nonces: RangeInclusive<MessageNonce>, nonces: RangeInclusive<MessageNonce>,
@@ -469,4 +508,16 @@ mod tests {
Err(SubstrateError::Custom(_)) 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. //! <BridgedName> chain.
use crate::messages_lane::SubstrateMessageLane; 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 crate::on_demand_headers::OnDemandHeadersRelay;
use async_trait::async_trait; use async_trait::async_trait;
use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState}; use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState};
use bp_runtime::ChainId; 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 codec::{Decode, Encode};
use frame_support::{traits::Instance, weights::Weight}; use frame_support::{traits::Instance, weights::Weight};
use messages_relay::{ use messages_relay::{
message_lane::{SourceHeaderIdOf, TargetHeaderIdOf}, message_lane::{SourceHeaderIdOf, TargetHeaderIdOf},
message_lane_loop::{TargetClient, TargetClientState}, message_lane_loop::{TargetClient, TargetClientState},
}; };
use num_traits::{Bounded, One, Zero};
use relay_substrate_client::{Chain, Client, Error as SubstrateError, HashOf}; 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_core::Bytes;
use sp_runtime::{traits::Header as HeaderT, DeserializeOwned}; use sp_runtime::{traits::Header as HeaderT, DeserializeOwned, FixedPointNumber, FixedU128};
use std::{marker::PhantomData, ops::RangeInclusive}; use std::{convert::TryFrom, marker::PhantomData, ops::RangeInclusive};
/// Message receiving proof returned by the target Substrate node. /// Message receiving proof returned by the target Substrate node.
pub type SubstrateMessagesReceivingProof<C> = ( pub type SubstrateMessagesReceivingProof<C> = (
@@ -45,23 +48,23 @@ pub type SubstrateMessagesReceivingProof<C> = (
); );
/// Substrate client as Substrate messages target. /// Substrate client as Substrate messages target.
pub struct SubstrateMessagesTarget<C: Chain, P: SubstrateMessageLane, I> { pub struct SubstrateMessagesTarget<SC: Chain, TC: Chain, P: SubstrateMessageLane, I> {
client: Client<C>, client: Client<TC>,
lane: P, lane: P,
lane_id: LaneId, lane_id: LaneId,
instance: ChainId, instance: ChainId,
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>, source_to_target_headers_relay: Option<OnDemandHeadersRelay<SC>>,
_phantom: PhantomData<I>, _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. /// Create new Substrate headers target.
pub fn new( pub fn new(
client: Client<C>, client: Client<TC>,
lane: P, lane: P,
lane_id: LaneId, lane_id: LaneId,
instance: ChainId, instance: ChainId,
source_to_target_headers_relay: Option<OnDemandHeadersRelay<P::SourceChain>>, source_to_target_headers_relay: Option<OnDemandHeadersRelay<SC>>,
) -> Self { ) -> Self {
SubstrateMessagesTarget { SubstrateMessagesTarget {
client, 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 { fn clone(&self) -> Self {
Self { Self {
client: self.client.clone(), client: self.client.clone(),
@@ -88,9 +91,10 @@ impl<C: Chain, P: SubstrateMessageLane, I> Clone for SubstrateMessagesTarget<C,
} }
#[async_trait] #[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 where
C: Chain, SC: Chain,
TC: Chain,
P: SubstrateMessageLane, P: SubstrateMessageLane,
I: Send + Sync + Instance, I: Send + Sync + Instance,
{ {
@@ -102,19 +106,22 @@ where
} }
#[async_trait] #[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 where
C: Chain, SC: Chain<Hash = P::SourceHeaderHash, BlockNumber = P::SourceHeaderNumber, Balance = P::SourceChainBalance>,
C::Header: DeserializeOwned, SC::Balance: TryFrom<TC::Balance> + Bounded,
C::Index: DeserializeOwned, TC: Chain<Hash = P::TargetHeaderHash, BlockNumber = P::TargetHeaderNumber>,
<C::Header as HeaderT>::Number: BlockNumberBase, TC::Hash: Copy,
TC::BlockNumber: Copy,
TC::Header: DeserializeOwned,
TC::Index: DeserializeOwned,
<TC::Header as HeaderT>::Number: BlockNumberBase,
P: SubstrateMessageLane< P: SubstrateMessageLane<
TargetChain = C, MessagesProof = SubstrateMessagesProof<SC>,
MessagesReceivingProof = SubstrateMessagesReceivingProof<C>, MessagesReceivingProof = SubstrateMessagesReceivingProof<TC>,
TargetHeaderNumber = <C::Header as HeaderT>::Number, SourceChain = SC,
TargetHeaderHash = <C::Header as HeaderT>::Hash, TargetChain = TC,
>, >,
P::SourceChain: Chain<Hash = P::SourceHeaderHash, BlockNumber = P::SourceHeaderNumber>,
P::SourceHeaderNumber: Decode, P::SourceHeaderNumber: Decode,
P::SourceHeaderHash: Decode, P::SourceHeaderHash: Decode,
I: Send + Sync + Instance, I: Send + Sync + Instance,
@@ -229,10 +236,93 @@ where
async fn estimate_delivery_transaction_in_source_tokens( async fn estimate_delivery_transaction_in_source_tokens(
&self, &self,
_nonces: RangeInclusive<MessageNonce>, nonces: RangeInclusive<MessageNonce>,
_total_dispatch_weight: Weight, total_dispatch_weight: Weight,
_total_size: u32, total_size: u32,
) -> P::SourceChainBalance { ) -> 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 { impl Chain for Kusama {
const NAME: &'static str = "Kusama"; const NAME: &'static str = "Kusama";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); 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 AccountId = bp_kusama::AccountId;
type Index = bp_kusama::Nonce; type Index = bp_kusama::Nonce;
+1
View File
@@ -13,6 +13,7 @@ relay-utils = { path = "../utils" }
# Supported Chains # Supported Chains
bp-millau = { path = "../../primitives/chain-millau" }
millau-runtime = { path = "../../bin/millau/runtime" } millau-runtime = { path = "../../bin/millau/runtime" }
# Substrate Dependencies # Substrate Dependencies
+2
View File
@@ -39,6 +39,8 @@ impl ChainBase for Millau {
impl Chain for Millau { impl Chain for Millau {
const NAME: &'static str = "Millau"; const NAME: &'static str = "Millau";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); 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 AccountId = millau_runtime::AccountId;
type Index = millau_runtime::Index; type Index = millau_runtime::Index;
@@ -36,6 +36,8 @@ impl ChainBase for Polkadot {
impl Chain for Polkadot { impl Chain for Polkadot {
const NAME: &'static str = "Polkadot"; const NAME: &'static str = "Polkadot";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); 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 AccountId = bp_polkadot::AccountId;
type Index = bp_polkadot::Nonce; type Index = bp_polkadot::Nonce;
+1
View File
@@ -13,6 +13,7 @@ relay-utils = { path = "../utils" }
# Bridge dependencies # Bridge dependencies
bp-rialto = { path = "../../primitives/chain-rialto" }
rialto-runtime = { path = "../../bin/rialto/runtime" } rialto-runtime = { path = "../../bin/rialto/runtime" }
# Substrate Dependencies # Substrate Dependencies
+2
View File
@@ -39,6 +39,8 @@ impl ChainBase for Rialto {
impl Chain for Rialto { impl Chain for Rialto {
const NAME: &'static str = "Rialto"; const NAME: &'static str = "Rialto";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); 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 AccountId = rialto_runtime::AccountId;
type Index = rialto_runtime::Index; type Index = rialto_runtime::Index;
+2
View File
@@ -44,6 +44,8 @@ impl ChainBase for Rococo {
impl Chain for Rococo { impl Chain for Rococo {
const NAME: &'static str = "Rococo"; const NAME: &'static str = "Rococo";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); 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 AccountId = bp_rococo::AccountId;
type Index = bp_rococo::Index; type Index = bp_rococo::Index;
@@ -29,9 +29,12 @@ relay-utils = { path = "../utils" }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-system = { 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-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" } sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { 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-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-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-storage = { 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" } 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 bp_runtime::Chain as ChainBase;
use frame_support::Parameter; use frame_support::Parameter;
use jsonrpsee_ws_client::{DeserializeOwned, Serialize}; 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_core::{storage::StorageKey, Pair};
use sp_runtime::{ use sp_runtime::{
generic::SignedBlock, generic::SignedBlock,
traits::{ 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}; 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 /// How often blocks are produced on that chain. It's suggested to set this value
/// to match the block time of the chain. /// to match the block time of the chain.
const AVERAGE_BLOCK_INTERVAL: Duration; 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. /// The user account identifier type for the runtime.
type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + Default; 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 /// 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. /// 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 /// 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 frame_system::AccountInfo;
use jsonrpsee_ws_client::{traits::SubscriptionClient, v2::params::JsonRpcParams, DeserializeOwned}; use jsonrpsee_ws_client::{traits::SubscriptionClient, v2::params::JsonRpcParams, DeserializeOwned};
use jsonrpsee_ws_client::{Subscription, WsClient as RpcClient, WsClientBuilder as RpcClientBuilder}; 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_balances::AccountData;
use pallet_transaction_payment::InclusionFee;
use relay_utils::relay_loop::RECONNECT_DELAY; use relay_utils::relay_loop::RECONNECT_DELAY;
use sp_core::{storage::StorageKey, Bytes}; use sp_core::{storage::StorageKey, Bytes};
use sp_trie::StorageProof; use sp_trie::StorageProof;
use sp_version::RuntimeVersion; use sp_version::RuntimeVersion;
use std::convert::TryFrom;
const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities"; const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities";
const MAX_SUBSCRIPTION_CAPACITY: usize = 4096; const MAX_SUBSCRIPTION_CAPACITY: usize = 4096;
@@ -258,6 +260,26 @@ impl<C: Chain> Client<C> {
Ok(tx_hash) 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. /// Get the GRANDPA authority set at given block.
pub async fn grandpa_authorities_set(&self, block: C::Hash) -> Result<OpaqueGrandpaAuthoritiesSet> { pub async fn grandpa_authorities_set(&self, block: C::Hash) -> Result<OpaqueGrandpaAuthoritiesSet> {
let call = SUB_API_GRANDPA_AUTHORITIES.to_string(); let call = SUB_API_GRANDPA_AUTHORITIES.to_string();
@@ -185,6 +185,8 @@ mod tests {
impl Chain for TestChain { impl Chain for TestChain {
const NAME: &'static str = "Test"; const NAME: &'static str = "Test";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1); 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 AccountId = u32;
type Index = u32; type Index = u32;
@@ -18,11 +18,13 @@
use crate::chain::Chain; use crate::chain::Chain;
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::{
storage::{StorageData, StorageKey}, storage::{StorageData, StorageKey},
Bytes, Bytes,
}; };
use sp_rpc::number::NumberOrHex;
use sp_version::RuntimeVersion; use sp_version::RuntimeVersion;
jsonrpsee_proc_macros::rpc_client_api! { 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>; fn state_prove_storage(keys: Vec<StorageKey>, hash: Option<C::Hash>) -> ReadProof<C::Hash>;
#[rpc(method = "state_getRuntimeVersion", positional_params)] #[rpc(method = "state_getRuntimeVersion", positional_params)]
fn state_runtime_version() -> RuntimeVersion; 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 { impl Chain for Westend {
const NAME: &'static str = "Westend"; const NAME: &'static str = "Westend";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); 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 AccountId = bp_westend::AccountId;
type Index = bp_westend::Nonce; type Index = bp_westend::Nonce;
+2
View File
@@ -44,6 +44,8 @@ impl ChainBase for Wococo {
impl Chain for Wococo { impl Chain for Wococo {
const NAME: &'static str = "Wococo"; const NAME: &'static str = "Wococo";
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); 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 AccountId = bp_wococo::AccountId;
type Index = bp_wococo::Index; type Index = bp_wococo::Index;