@@ -25,7 +25,9 @@ use crate::{
2525
2626use async_std:: sync:: Arc ;
2727use 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+ } ;
2931use bridge_runtime_common:: messages:: {
3032 source:: FromBridgedChainMessagesDeliveryProof , target:: FromBridgedChainMessagesProof ,
3133} ;
@@ -35,13 +37,15 @@ use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransact
3537use pallet_bridge_messages:: { Call as BridgeMessagesCall , Config as BridgeMessagesConfig } ;
3638use 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} ;
4043use relay_utils:: {
4144 metrics:: { GlobalMetrics , MetricsParams , StandaloneMetric } ,
4245 STALL_TIMEOUT ,
4346} ;
4447use sp_core:: Pair ;
48+ use sp_runtime:: traits:: Zero ;
4549use 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