Skip to content

Commit 4339091

Browse files
authored
get rid of ChainWithMessages::WeightInfo, because we can't have exact weights for "external chains" (paritytech#1899)
1 parent d7642ff commit 4339091

File tree

9 files changed

+121
-89
lines changed

9 files changed

+121
-89
lines changed

modules/messages/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub use weights::WeightInfo;
4343
pub use weights_ext::{
4444
ensure_able_to_receive_confirmation, ensure_able_to_receive_message,
4545
ensure_weights_are_correct, WeightInfoExt, EXPECTED_DEFAULT_MESSAGE_LENGTH,
46+
EXTRA_STORAGE_PROOF_SIZE,
4647
};
4748

4849
use crate::{

relays/client-bridge-hub-rococo/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,6 @@ impl ChainWithMessages for BridgeHubRococo {
132132
bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
133133
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
134134
bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
135-
136-
// TODO: fix (https://github.com/paritytech/parity-bridges-common/issues/1640)
137-
type WeightInfo = ();
138135
}
139136

140137
#[cfg(test)]

relays/client-bridge-hub-wococo/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,6 @@ impl ChainWithMessages for BridgeHubWococo {
132132
bp_bridge_hub_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
133133
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
134134
bp_bridge_hub_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
135-
136-
// TODO: fix (https://github.com/paritytech/parity-bridges-common/issues/1640)
137-
type WeightInfo = ();
138135
}
139136

140137
#[cfg(test)]

relays/client-millau/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ impl ChainWithMessages for Millau {
5151
bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
5252
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
5353
bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
54-
type WeightInfo = ();
5554
}
5655

5756
impl Chain for Millau {

relays/client-rialto-parachain/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ impl ChainWithMessages for RialtoParachain {
7979
bp_rialto_parachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
8080
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
8181
bp_rialto_parachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
82-
type WeightInfo = ();
8382
}
8483

8584
impl ChainWithTransactions for RialtoParachain {

relays/client-rialto/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ impl ChainWithMessages for Rialto {
6969
bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
7070
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
7171
bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
72-
type WeightInfo = ();
7372
}
7473

7574
impl ChainWithBalances for Rialto {

relays/client-substrate/src/chain.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,6 @@ pub trait ChainWithMessages: Chain {
136136
/// Maximal number of unconfirmed messages in a single confirmation transaction at this
137137
/// `ChainWithMessages`.
138138
const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce;
139-
140-
/// Weights of message pallet calls.
141-
type WeightInfo: pallet_bridge_messages::WeightInfoExt;
142139
}
143140

144141
/// Call type used by the chain.

relays/client-substrate/src/client.rs

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use crate::{
2121
rpc::{
2222
SubstrateAuthorClient, SubstrateChainClient, SubstrateFinalityClient,
2323
SubstrateFrameSystemClient, SubstrateStateClient, SubstrateSystemClient,
24-
SubstrateTransactionPaymentClient,
2524
},
2625
transaction_stall_timeout, AccountKeyPairOf, ConnectionParams, Error, HashOf, HeaderIdOf,
2726
Result, SignParam, TransactionTracker, UnsignedTransaction,
@@ -31,15 +30,16 @@ use async_std::sync::{Arc, Mutex};
3130
use async_trait::async_trait;
3231
use bp_runtime::{HeaderIdProvider, StorageDoubleMapKeyProvider, StorageMapKeyProvider};
3332
use codec::{Decode, Encode};
33+
use frame_support::weights::Weight;
3434
use frame_system::AccountInfo;
3535
use futures::{SinkExt, StreamExt};
3636
use jsonrpsee::{
3737
core::DeserializeOwned,
3838
ws_client::{WsClient as RpcClient, WsClientBuilder as RpcClientBuilder},
3939
};
40-
use num_traits::{Bounded, Saturating, Zero};
40+
use num_traits::{Saturating, Zero};
4141
use pallet_balances::AccountData;
42-
use pallet_transaction_payment::InclusionFee;
42+
use pallet_transaction_payment::RuntimeDispatchInfo;
4343
use relay_utils::{relay_loop::RECONNECT_DELAY, STALL_TIMEOUT};
4444
use sp_core::{
4545
storage::{StorageData, StorageKey},
@@ -51,10 +51,11 @@ use sp_runtime::{
5151
};
5252
use sp_trie::StorageProof;
5353
use sp_version::RuntimeVersion;
54-
use std::{convert::TryFrom, future::Future};
54+
use std::future::Future;
5555

5656
const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities";
5757
const SUB_API_TXPOOL_VALIDATE_TRANSACTION: &str = "TaggedTransactionQueue_validate_transaction";
58+
const SUB_API_TX_PAYMENT_QUERY_INFO: &str = "TransactionPaymentApi_query_info";
5859
const MAX_SUBSCRIPTION_CAPACITY: usize = 4096;
5960

6061
/// The difference between best block number and number of its ancestor, that is enough
@@ -591,33 +592,24 @@ impl<C: Chain> Client<C> {
591592
.await
592593
}
593594

594-
/// Estimate fee that will be spent on given extrinsic.
595-
pub async fn estimate_extrinsic_fee(
595+
/// Returns weight of the given transaction.
596+
pub async fn extimate_extrinsic_weight<SignedTransaction: Encode + Send + 'static>(
596597
&self,
597-
transaction: Bytes,
598-
) -> Result<InclusionFee<C::Balance>> {
598+
transaction: SignedTransaction,
599+
) -> Result<Weight> {
599600
self.jsonrpsee_execute(move |client| async move {
600-
let fee_details =
601-
SubstrateTransactionPaymentClient::<C>::fee_details(&*client, transaction, None)
602-
.await?;
603-
let inclusion_fee = fee_details
604-
.inclusion_fee
605-
.map(|inclusion_fee| InclusionFee {
606-
base_fee: C::Balance::try_from(inclusion_fee.base_fee.into_u256())
607-
.unwrap_or_else(|_| C::Balance::max_value()),
608-
len_fee: C::Balance::try_from(inclusion_fee.len_fee.into_u256())
609-
.unwrap_or_else(|_| C::Balance::max_value()),
610-
adjusted_weight_fee: C::Balance::try_from(
611-
inclusion_fee.adjusted_weight_fee.into_u256(),
612-
)
613-
.unwrap_or_else(|_| C::Balance::max_value()),
614-
})
615-
.unwrap_or_else(|| InclusionFee {
616-
base_fee: Zero::zero(),
617-
len_fee: Zero::zero(),
618-
adjusted_weight_fee: Zero::zero(),
619-
});
620-
Ok(inclusion_fee)
601+
let transaction_len = transaction.encoded_size() as u32;
602+
603+
let call = SUB_API_TX_PAYMENT_QUERY_INFO.to_string();
604+
let data = Bytes((transaction, transaction_len).encode());
605+
606+
let encoded_response =
607+
SubstrateStateClient::<C>::call(&*client, call, data, None).await?;
608+
let dispatch_info =
609+
RuntimeDispatchInfo::<C::Balance>::decode(&mut &encoded_response.0[..])
610+
.map_err(Error::ResponseParseFailed)?;
611+
612+
Ok(dispatch_info.weight)
621613
})
622614
.await
623615
}

relays/lib-substrate-relay/src/messages_lane.rs

Lines changed: 99 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ use crate::{
2525

2626
use async_std::sync::Arc;
2727
use bp_messages::{LaneId, MessageNonce};
28-
use bp_runtime::{AccountIdOf, Chain as _, HeaderIdOf, WeightExtraOps};
28+
use bp_runtime::{
29+
AccountIdOf, Chain as _, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps,
30+
};
2931
use bridge_runtime_common::messages::{
3032
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
3133
};
@@ -35,13 +37,15 @@ use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransact
3537
use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig};
3638
use relay_substrate_client::{
3739
transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain,
38-
ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf,
40+
ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf, SignParam,
41+
UnsignedTransaction,
3942
};
4043
use relay_utils::{
4144
metrics::{GlobalMetrics, MetricsParams, StandaloneMetric},
4245
STALL_TIMEOUT,
4346
};
4447
use sp_core::Pair;
48+
use sp_runtime::traits::Zero;
4549
use std::{convert::TryFrom, fmt::Debug, marker::PhantomData};
4650

4751
/// Substrate -> Substrate messages synchronization pipeline.
@@ -159,25 +163,25 @@ where
159163
AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<P::TargetChain> as Pair>::Public>,
160164
BalanceOf<P::SourceChain>: TryFrom<BalanceOf<P::TargetChain>>,
161165
{
162-
let source_client = params.source_client;
163-
let target_client = params.target_client;
164-
let relayer_id_at_source: AccountIdOf<P::SourceChain> =
165-
params.source_transaction_params.signer.public().into();
166-
167166
// 2/3 is reserved for proofs and tx overhead
168167
let max_messages_size_in_single_batch = P::TargetChain::max_extrinsic_size() / 3;
169168
// we don't know exact weights of the Polkadot runtime. So to guess weights we'll be using
170169
// weights from Rialto and then simply dividing it by x2.
171170
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
172-
crate::messages_lane::select_delivery_transaction_limits::<
173-
<P::TargetChain as ChainWithMessages>::WeightInfo,
174-
>(
171+
select_delivery_transaction_limits_rpc::<P>(
172+
&params,
175173
P::TargetChain::max_extrinsic_weight(),
176174
P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
177-
);
175+
)
176+
.await?;
178177
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
179178
(max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2);
180179

180+
let source_client = params.source_client;
181+
let target_client = params.target_client;
182+
let relayer_id_at_source: AccountIdOf<P::SourceChain> =
183+
params.source_transaction_params.signer.public().into();
184+
181185
log::info!(
182186
target: "bridge",
183187
"Starting {} -> {} messages relay.\n\t\
@@ -437,12 +441,15 @@ macro_rules! generate_receive_message_delivery_proof_call_builder {
437441
};
438442
}
439443

440-
/// Returns maximal number of messages and their maximal cumulative dispatch weight, based
441-
/// on given chain parameters.
442-
pub fn select_delivery_transaction_limits<W: pallet_bridge_messages::WeightInfoExt>(
444+
/// Returns maximal number of messages and their maximal cumulative dispatch weight.
445+
async fn select_delivery_transaction_limits_rpc<P: SubstrateMessageLane>(
446+
params: &MessagesRelayParams<P>,
443447
max_extrinsic_weight: Weight,
444448
max_unconfirmed_messages_at_inbound_lane: MessageNonce,
445-
) -> (MessageNonce, Weight) {
449+
) -> anyhow::Result<(MessageNonce, Weight)>
450+
where
451+
AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
452+
{
446453
// We may try to guess accurate value, based on maximal number of messages and per-message
447454
// weight overhead, but the relay loop isn't using this info in a super-accurate way anyway.
448455
// So just a rough guess: let's say 1/3 of max tx weight is for tx itself and the rest is
@@ -455,13 +462,35 @@ pub fn select_delivery_transaction_limits<W: pallet_bridge_messages::WeightInfoE
455462
let weight_for_delivery_tx = max_extrinsic_weight / 3;
456463
let weight_for_messages_dispatch = max_extrinsic_weight - weight_for_delivery_tx;
457464

458-
let delivery_tx_base_weight = W::receive_messages_proof_overhead() +
459-
W::receive_messages_proof_outbound_lane_state_overhead();
460-
let delivery_tx_weight_rest = weight_for_delivery_tx - delivery_tx_base_weight;
465+
// weight of empty message delivery with outbound lane state
466+
let delivery_tx_with_zero_messages = dummy_messages_delivery_transaction::<P>(params, 0)?;
467+
let delivery_tx_with_zero_messages_weight = params
468+
.target_client
469+
.extimate_extrinsic_weight(delivery_tx_with_zero_messages)
470+
.await
471+
.map_err(|e| {
472+
anyhow::format_err!("Failed to estimate delivery extrinsic weight: {:?}", e)
473+
})?;
474+
475+
// weight of single message delivery with outbound lane state
476+
let delivery_tx_with_one_message = dummy_messages_delivery_transaction::<P>(params, 1)?;
477+
let delivery_tx_with_one_message_weight = params
478+
.target_client
479+
.extimate_extrinsic_weight(delivery_tx_with_one_message)
480+
.await
481+
.map_err(|e| {
482+
anyhow::format_err!("Failed to estimate delivery extrinsic weight: {:?}", e)
483+
})?;
484+
485+
// message overhead is roughly `delivery_tx_with_one_message_weight -
486+
// delivery_tx_with_zero_messages_weight`
487+
let delivery_tx_weight_rest = weight_for_delivery_tx - delivery_tx_with_zero_messages_weight;
488+
let delivery_tx_message_overhead =
489+
delivery_tx_with_one_message_weight.saturating_sub(delivery_tx_with_zero_messages_weight);
461490

462491
let max_number_of_messages = std::cmp::min(
463492
delivery_tx_weight_rest
464-
.min_components_checked_div(W::receive_messages_proof_messages_overhead(1))
493+
.min_components_checked_div(delivery_tx_message_overhead)
465494
.unwrap_or(u64::MAX),
466495
max_unconfirmed_messages_at_inbound_lane,
467496
);
@@ -475,36 +504,58 @@ pub fn select_delivery_transaction_limits<W: pallet_bridge_messages::WeightInfoE
475504
"Relay shall be able to deliver messages with dispatch weight = max_extrinsic_weight / 2",
476505
);
477506

478-
(max_number_of_messages, weight_for_messages_dispatch)
507+
Ok((max_number_of_messages, weight_for_messages_dispatch))
479508
}
480509

481-
#[cfg(test)]
482-
mod tests {
483-
use super::*;
484-
use bp_runtime::Chain;
485-
486-
type RialtoToMillauMessagesWeights =
487-
pallet_bridge_messages::weights::BridgeWeight<rialto_runtime::Runtime>;
488-
489-
#[test]
490-
fn select_delivery_transaction_limits_is_sane() {
491-
// we want to check the `proof_size` component here too. But for Rialto and Millau
492-
// it is set to `u64::MAX` (as for Polkadot and other relay/standalone chains).
493-
// So let's use RialtoParachain limits here - it has `proof_size` limit as all
494-
// Cumulus-based parachains do.
495-
let (max_count, max_weight) =
496-
select_delivery_transaction_limits::<RialtoToMillauMessagesWeights>(
497-
bp_rialto_parachain::RialtoParachain::max_extrinsic_weight(),
498-
bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
499-
);
500-
assert_eq!(
501-
(max_count, max_weight),
502-
// We don't actually care about these values, so feel free to update them whenever test
503-
// fails. The only thing to do before that is to ensure that new values looks sane:
504-
// i.e. weight reserved for messages dispatch allows dispatch of non-trivial messages.
505-
//
506-
// Any significant change in this values should attract additional attention.
507-
(1024, Weight::from_parts(866_600_106_667, 2_271_915)),
510+
/// Returns dummy message delivery transaction with zero messages and `1kb` proof.
511+
fn dummy_messages_delivery_transaction<P: SubstrateMessageLane>(
512+
params: &MessagesRelayParams<P>,
513+
messages: u32,
514+
) -> anyhow::Result<<P::TargetChain as ChainWithTransactions>::SignedTransaction>
515+
where
516+
AccountIdOf<P::SourceChain>: From<<AccountKeyPairOf<P::SourceChain> as Pair>::Public>,
517+
{
518+
// we don't care about any call values here, because all that the estimation RPC does
519+
// is calls `GetDispatchInfo::get_dispatch_info` for the wrapped call. So we only are
520+
// interested in values that affect call weight - e.g. number of messages and the
521+
// storage proof size
522+
523+
let dummy_messages_delivery_call =
524+
P::ReceiveMessagesProofCallBuilder::build_receive_messages_proof_call(
525+
params.source_transaction_params.signer.public().into(),
526+
(
527+
Weight::zero(),
528+
FromBridgedChainMessagesProof {
529+
bridged_header_hash: Default::default(),
530+
// we may use per-chain `EXTRA_STORAGE_PROOF_SIZE`, but since we don't need
531+
// exact values, this global estimation is fine
532+
storage_proof: vec![vec![
533+
42u8;
534+
pallet_bridge_messages::EXTRA_STORAGE_PROOF_SIZE
535+
as usize
536+
]],
537+
lane: Default::default(),
538+
nonces_start: 1,
539+
nonces_end: messages as u64,
540+
},
541+
),
542+
messages,
543+
Weight::zero(),
544+
false,
508545
);
509-
}
546+
P::TargetChain::sign_transaction(
547+
SignParam {
548+
spec_version: 0,
549+
transaction_version: 0,
550+
genesis_hash: Default::default(),
551+
signer: params.target_transaction_params.signer.clone(),
552+
},
553+
UnsignedTransaction {
554+
call: EncodedOrDecodedCall::Decoded(dummy_messages_delivery_call),
555+
nonce: Zero::zero(),
556+
tip: Zero::zero(),
557+
era: TransactionEra::Immortal,
558+
},
559+
)
560+
.map_err(Into::into)
510561
}

0 commit comments

Comments
 (0)