diff --git a/bridges/bin/rialto-parachain/node/src/chain_spec.rs b/bridges/bin/rialto-parachain/node/src/chain_spec.rs index 4a7865b18542edc402c526c174732fb78549b3d5..a0306514c0391fd6718d0b1c4d8a6e221e5e93d6 100644 --- a/bridges/bin/rialto-parachain/node/src/chain_spec.rs +++ b/bridges/bin/rialto-parachain/node/src/chain_spec.rs @@ -122,10 +122,7 @@ pub fn development_config(id: ParaId) -> ChainSpec { move || { testnet_genesis( get_account_id_from_seed::<sr25519::Public>(SUDO_ACCOUNT), - DEV_AUTHORITIES_ACCOUNTS - .into_iter() - .map(|x| get_from_seed::<AuraId>(x)) - .collect(), + DEV_AUTHORITIES_ACCOUNTS.into_iter().map(get_from_seed::<AuraId>).collect(), endowed_accounts(), id, ) @@ -157,10 +154,7 @@ pub fn local_testnet_config(id: ParaId) -> ChainSpec { move || { testnet_genesis( get_account_id_from_seed::<sr25519::Public>(SUDO_ACCOUNT), - LOCAL_AUTHORITIES_ACCOUNTS - .into_iter() - .map(|x| get_from_seed::<AuraId>(x)) - .collect(), + LOCAL_AUTHORITIES_ACCOUNTS.into_iter().map(get_from_seed::<AuraId>).collect(), endowed_accounts(), id, ) diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 7589e70d703aef1c00749fe78a2c655d658a5149..7ca17fbd5a178d2ea8511c1599642b026ac5003c 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -183,7 +183,7 @@ impl Size for PreComputedSize { } /// Era of specific transaction. -#[derive(RuntimeDebug, Clone, Copy)] +#[derive(RuntimeDebug, Clone, Copy, PartialEq)] pub enum TransactionEra<BlockNumber, BlockHash> { /// Transaction is immortal. Immortal, @@ -207,6 +207,14 @@ impl<BlockNumber: Copy + Into<u64>, BlockHash: Copy> TransactionEra<BlockNumber, TransactionEra::Immortal } + /// Returns mortality period if transaction is mortal. + pub fn mortality_period(&self) -> Option<u32> { + match *self { + TransactionEra::Immortal => None, + TransactionEra::Mortal(_, period) => Some(period), + } + } + /// Returns era that is used by FRAME-based runtimes. pub fn frame_era(&self) -> sp_runtime::generic::Era { match *self { diff --git a/bridges/primitives/test-utils/src/keyring.rs b/bridges/primitives/test-utils/src/keyring.rs index 2436d79339236d884ae203d24b759826c062354a..f827c729434ecc7e1df4400e6583b24945e6806e 100644 --- a/bridges/primitives/test-utils/src/keyring.rs +++ b/bridges/primitives/test-utils/src/keyring.rs @@ -43,7 +43,7 @@ impl Account { pub fn secret(&self) -> SecretKey { let data = self.0.encode(); let mut bytes = [0_u8; 32]; - bytes[0..data.len()].copy_from_slice(&*data); + bytes[0..data.len()].copy_from_slice(&data); SecretKey::from_bytes(&bytes) .expect("A static array of the correct length is a known good.") } diff --git a/bridges/relays/bin-substrate/src/chains/mod.rs b/bridges/relays/bin-substrate/src/chains/mod.rs index d3c1290d98dc4a6f63203e9d995058ecad7fd499..c1e963a63ec7c5f3192ae8c24a887dd295eea987 100644 --- a/bridges/relays/bin-substrate/src/chains/mod.rs +++ b/bridges/relays/bin-substrate/src/chains/mod.rs @@ -71,14 +71,15 @@ mod tests { fn rialto_tx_extra_bytes_constant_is_correct() { let rialto_call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark { remark: vec![] }); - let rialto_tx = Rialto::sign_transaction(SignParam { - spec_version: 1, - transaction_version: 1, - genesis_hash: Default::default(), - signer: sp_keyring::AccountKeyring::Alice.pair(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(rialto_call.clone().into(), 0), - }) + let rialto_tx = Rialto::sign_transaction( + SignParam { + spec_version: 1, + transaction_version: 1, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + }, + UnsignedTransaction::new(rialto_call.clone().into(), 0), + ) .unwrap(); let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); assert!( @@ -93,14 +94,15 @@ mod tests { fn millau_tx_extra_bytes_constant_is_correct() { let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark { remark: vec![] }); - let millau_tx = Millau::sign_transaction(SignParam { - spec_version: 0, - transaction_version: 0, - genesis_hash: Default::default(), - signer: sp_keyring::AccountKeyring::Alice.pair(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(millau_call.clone().into(), 0), - }) + let millau_tx = Millau::sign_transaction( + SignParam { + spec_version: 0, + transaction_version: 0, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + }, + UnsignedTransaction::new(millau_call.clone().into(), 0), + ) .unwrap(); let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); assert!( diff --git a/bridges/relays/bin-substrate/src/cli/init_bridge.rs b/bridges/relays/bin-substrate/src/cli/init_bridge.rs index 150c55d9c6c67f250c39a079cf763ea9561f7991..218130dbe562e6be5e405363f98009ad1272240e 100644 --- a/bridges/relays/bin-substrate/src/cli/init_bridge.rs +++ b/bridges/relays/bin-substrate/src/cli/init_bridge.rs @@ -26,11 +26,8 @@ use crate::{ cli::{bridge::CliBridgeBase, chain_schema::*}, }; use bp_runtime::Chain as ChainBase; -use codec::Encode; -use relay_substrate_client::{ - AccountKeyPairOf, Chain, SignParam, TransactionSignScheme, UnsignedTransaction, -}; -use sp_core::{Bytes, Pair}; +use relay_substrate_client::{AccountKeyPairOf, Chain, SignParam, UnsignedTransaction}; +use sp_core::Pair; use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; use substrate_relay_helper::finality::engine::{Engine, Grandpa as GrandpaFinalityEngine}; @@ -82,20 +79,16 @@ where source_client, target_client.clone(), target_sign.public().into(), + SignParam { + spec_version, + transaction_version, + genesis_hash: *target_client.genesis_hash(), + signer: target_sign, + }, move |transaction_nonce, initialization_data| { - Ok(Bytes( - Self::Target::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *target_client.genesis_hash(), - signer: target_sign, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - Self::encode_init_bridge(initialization_data).into(), - transaction_nonce, - ), - })? - .encode(), + Ok(UnsignedTransaction::new( + Self::encode_init_bridge(initialization_data).into(), + transaction_nonce, )) }, ) diff --git a/bridges/relays/bin-substrate/src/cli/mod.rs b/bridges/relays/bin-substrate/src/cli/mod.rs index e35548c347c4247762aacfe9369af49dec875684..44bfce9f384ec82edb59b1203118a6e60078152e 100644 --- a/bridges/relays/bin-substrate/src/cli/mod.rs +++ b/bridges/relays/bin-substrate/src/cli/mod.rs @@ -223,13 +223,6 @@ impl std::fmt::Display for HexBytes { } } -impl HexBytes { - /// Encode given object and wrap into nicely formatted bytes. - pub fn encode<T: Encode>(t: &T) -> Self { - Self(t.encode()) - } -} - /// Prometheus metrics params. #[derive(Clone, Debug, PartialEq, StructOpt)] pub struct PrometheusParams { diff --git a/bridges/relays/bin-substrate/src/cli/register_parachain.rs b/bridges/relays/bin-substrate/src/cli/register_parachain.rs index 9573cde30319f5135bfbefd8969374b2c588917c..890436537795cb62b0c55aa5abbd29a40281714d 100644 --- a/bridges/relays/bin-substrate/src/cli/register_parachain.rs +++ b/bridges/relays/bin-substrate/src/cli/register_parachain.rs @@ -27,13 +27,13 @@ use polkadot_runtime_common::{ }; use polkadot_runtime_parachains::paras::ParaLifecycle; use relay_substrate_client::{ - AccountIdOf, CallOf, Chain, Client, HashOf, SignParam, Subscription, TransactionSignScheme, - TransactionStatusOf, UnsignedTransaction, + AccountIdOf, CallOf, Chain, Client, HashOf, SignParam, Subscription, TransactionStatusOf, + UnsignedTransaction, }; use rialto_runtime::SudoCall; use sp_core::{ storage::{well_known_keys::CODE, StorageKey}, - Bytes, Pair, + Pair, }; use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; @@ -120,20 +120,16 @@ impl RegisterParachain { relay_client .submit_and_watch_signed_extrinsic( relay_sudo_account.clone(), + SignParam::<Relaychain> { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: reserve_parachain_signer, + }, move |_, transaction_nonce| { - Ok(Bytes( - Relaychain::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: relay_genesis_hash, - signer: reserve_parachain_signer, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - reserve_parachain_id_call.into(), - transaction_nonce, - ), - })? - .encode(), + Ok(UnsignedTransaction::new( + reserve_parachain_id_call.into(), + transaction_nonce, )) }, ) @@ -169,20 +165,16 @@ impl RegisterParachain { relay_client .submit_and_watch_signed_extrinsic( relay_sudo_account.clone(), + SignParam::<Relaychain> { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: register_parathread_signer, + }, move |_, transaction_nonce| { - Ok(Bytes( - Relaychain::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: relay_genesis_hash, - signer: register_parathread_signer, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - register_parathread_call.into(), - transaction_nonce, - ), - })? - .encode(), + Ok(UnsignedTransaction::new( + register_parathread_call.into(), + transaction_nonce, )) }, ) @@ -231,22 +223,18 @@ impl RegisterParachain { .into(); let force_lease_signer = relay_sign.clone(); relay_client - .submit_signed_extrinsic(relay_sudo_account.clone(), move |_, transaction_nonce| { - Ok(Bytes( - Relaychain::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: relay_genesis_hash, - signer: force_lease_signer, - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new( - force_lease_call.into(), - transaction_nonce, - ), - })? - .encode(), - )) - }) + .submit_signed_extrinsic( + relay_sudo_account, + SignParam::<Relaychain> { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: force_lease_signer, + }, + move |_, transaction_nonce| { + Ok(UnsignedTransaction::new(force_lease_call.into(), transaction_nonce)) + }, + ) .await?; log::info!(target: "bridge", "Registered parachain leases: {:?}. Waiting for onboarding", para_id); diff --git a/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs b/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs index dad1afbf146d1c1302c0e114ca3f40daaec6523b..ac479986ed8fb1c4950699d88de83eec74abf7c5 100644 --- a/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs +++ b/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs @@ -425,14 +425,15 @@ async fn update_transaction_tip<C: Chain, S: TransactionSignScheme<Chain = C>>( current_priority = client .validate_transaction( at_block.1, - S::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *client.genesis_hash(), - signer: transaction_params.signer.clone(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: unsigned_tx.clone(), - })?, + S::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: *client.genesis_hash(), + signer: transaction_params.signer.clone(), + }, + unsigned_tx.clone(), + )?, ) .await?? .priority; @@ -448,17 +449,18 @@ async fn update_transaction_tip<C: Chain, S: TransactionSignScheme<Chain = C>>( Ok(( old_tip != unsigned_tx.tip, - S::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *client.genesis_hash(), - signer: transaction_params.signer.clone(), - era: relay_substrate_client::TransactionEra::new( + S::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: *client.genesis_hash(), + signer: transaction_params.signer.clone(), + }, + unsigned_tx.era(relay_substrate_client::TransactionEra::new( at_block, transaction_params.mortality, - ), - unsigned: unsigned_tx, - })?, + )), + )?, )) } diff --git a/bridges/relays/bin-substrate/src/cli/send_message.rs b/bridges/relays/bin-substrate/src/cli/send_message.rs index a45235f0bec28be617335cc2a3d8164dcad0c058..79d1efee6387990a006330c3316fc3fb854e9487 100644 --- a/bridges/relays/bin-substrate/src/cli/send_message.rs +++ b/bridges/relays/bin-substrate/src/cli/send_message.rs @@ -26,7 +26,7 @@ use crate::{ chain_schema::*, encode_message::{self, CliEncodeMessage, RawMessage}, estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride}, - Balance, CliChain, HexBytes, HexLaneId, + Balance, CliChain, HexLaneId, }, }; use async_trait::async_trait; @@ -146,55 +146,50 @@ where let (spec_version, transaction_version) = source_client.simple_runtime_version().await?; let estimated_transaction_fee = source_client .estimate_extrinsic_fee(Bytes( - Self::Source::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: source_genesis_hash, - signer: source_sign.clone(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(send_message_call.clone(), 0), - })? + Self::Source::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: source_genesis_hash, + signer: source_sign.clone(), + }, + UnsignedTransaction::new(send_message_call.clone(), 0), + )? .encode(), )) .await?; source_client - .submit_signed_extrinsic(source_sign.public().into(), move |_, transaction_nonce| { - let signed_source_call = Self::Source::sign_transaction(SignParam { + .submit_signed_extrinsic( + source_sign.public().into(), + SignParam::<Self::Source> { spec_version, transaction_version, genesis_hash: source_genesis_hash, signer: source_sign.clone(), - era: relay_substrate_client::TransactionEra::immortal(), - unsigned: UnsignedTransaction::new(send_message_call, transaction_nonce), - })? - .encode(); - - log::info!( - target: "bridge", - "Sending message to {}. Lane: {:?}. Size: {}. Fee: {}", - Self::Target::NAME, - lane, - payload_len, - fee, - ); - log::info!( - target: "bridge", - "The source account ({:?}) balance will be reduced by (at most) {} (message fee) - + {} (tx fee ) = {} {} tokens", AccountId32::from(source_sign.public()), - fee.0, - estimated_transaction_fee.inclusion_fee(), - fee.0.saturating_add(estimated_transaction_fee.inclusion_fee().into()), - Self::Source::NAME, - ); - log::info!( - target: "bridge", - "Signed {} Call: {:?}", - Self::Source::NAME, - HexBytes::encode(&signed_source_call) - ); + }, + move |_, transaction_nonce| { + let unsigned = UnsignedTransaction::new(send_message_call, transaction_nonce); + log::info!( + target: "bridge", + "Sending message to {}. Lane: {:?}. Size: {}. Fee: {}", + Self::Target::NAME, + lane, + payload_len, + fee, + ); + log::info!( + target: "bridge", + "The source account ({:?}) balance will be reduced by (at most) {} (message fee) + + {} (tx fee ) = {} {} tokens", AccountId32::from(source_sign.public()), + fee.0, + estimated_transaction_fee.inclusion_fee(), + fee.0.saturating_add(estimated_transaction_fee.inclusion_fee().into()), + Self::Source::NAME, + ); - Ok(Bytes(signed_source_call)) - }) + Ok(unsigned) + }, + ) .await?; Ok(()) @@ -230,7 +225,7 @@ fn decode_xcm(message: RawMessage) -> anyhow::Result<xcm::VersionedXcm<()>> { #[cfg(test)] mod tests { use super::*; - use crate::cli::ExplicitOrMaximal; + use crate::cli::{ExplicitOrMaximal, HexBytes}; #[test] fn send_raw_rialto_to_millau() { diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs index 36b7cb792b436728a1af9724e79983e9f6030f71..7bab3669c4d02f4bbda01ee27dc910e9b216ec0e 100644 --- a/bridges/relays/client-millau/src/lib.rs +++ b/bridges/relays/client-millau/src/lib.rs @@ -102,18 +102,21 @@ impl TransactionSignScheme for Millau { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = millau_runtime::UncheckedExtrinsic; - fn sign_transaction(param: SignParam<Self>) -> Result<Self::SignedTransaction, SubstrateError> { + fn sign_transaction( + param: SignParam<Self>, + unsigned: UnsignedTransaction<Self::Chain>, + ) -> Result<Self::SignedTransaction, SubstrateError> { let raw_payload = SignedPayload::from_raw( - param.unsigned.call, + unsigned.call.clone(), ( frame_system::CheckNonZeroSender::<millau_runtime::Runtime>::new(), frame_system::CheckSpecVersion::<millau_runtime::Runtime>::new(), frame_system::CheckTxVersion::<millau_runtime::Runtime>::new(), frame_system::CheckGenesis::<millau_runtime::Runtime>::new(), - frame_system::CheckEra::<millau_runtime::Runtime>::from(param.era.frame_era()), - frame_system::CheckNonce::<millau_runtime::Runtime>::from(param.unsigned.nonce), + frame_system::CheckEra::<millau_runtime::Runtime>::from(unsigned.era.frame_era()), + frame_system::CheckNonce::<millau_runtime::Runtime>::from(unsigned.nonce), frame_system::CheckWeight::<millau_runtime::Runtime>::new(), - pallet_transaction_payment::ChargeTransactionPayment::<millau_runtime::Runtime>::from(param.unsigned.tip), + pallet_transaction_payment::ChargeTransactionPayment::<millau_runtime::Runtime>::from(unsigned.tip), millau_runtime::BridgeRejectObsoleteHeadersAndMessages, ), ( @@ -121,7 +124,7 @@ impl TransactionSignScheme for Millau { param.spec_version, param.transaction_version, param.genesis_hash, - param.era.signed_payload(param.genesis_hash), + unsigned.era.signed_payload(param.genesis_hash), (), (), (), @@ -155,13 +158,17 @@ impl TransactionSignScheme for Millau { fn parse_transaction(tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self::Chain>> { let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { - call: tx.function.into(), - nonce: Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.5.encode()[..]).ok()?.into(), - tip: Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.7.encode()[..]) - .ok()? - .into(), - }) + Some( + UnsignedTransaction::new( + tx.function.into(), + Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.5.encode()[..]).ok()?.into(), + ) + .tip( + Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.7.encode()[..]) + .ok()? + .into(), + ), + ) } } @@ -185,15 +192,17 @@ mod tests { .into(), nonce: 777, tip: 888, - }; - let signed_transaction = Millau::sign_transaction(SignParam { - spec_version: 42, - transaction_version: 50000, - genesis_hash: [42u8; 64].into(), - signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), era: TransactionEra::immortal(), - unsigned: unsigned.clone(), - }) + }; + let signed_transaction = Millau::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 64].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) .unwrap(); let parsed_transaction = Millau::parse_transaction(signed_transaction).unwrap(); assert_eq!(parsed_transaction, unsigned); diff --git a/bridges/relays/client-rialto-parachain/src/lib.rs b/bridges/relays/client-rialto-parachain/src/lib.rs index a6f34201ca5f5ff115cab0764e292bd22410a4b2..c678a21420fd4f03f0eb3553bf1e0a100c66c6dd 100644 --- a/bridges/relays/client-rialto-parachain/src/lib.rs +++ b/bridges/relays/client-rialto-parachain/src/lib.rs @@ -101,31 +101,32 @@ impl TransactionSignScheme for RialtoParachain { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = rialto_parachain_runtime::UncheckedExtrinsic; - fn sign_transaction(param: SignParam<Self>) -> Result<Self::SignedTransaction, SubstrateError> { + fn sign_transaction( + param: SignParam<Self>, + unsigned: UnsignedTransaction<Self::Chain>, + ) -> Result<Self::SignedTransaction, SubstrateError> { let raw_payload = SignedPayload::from_raw( - param.unsigned.call, + unsigned.call, ( frame_system::CheckNonZeroSender::<rialto_parachain_runtime::Runtime>::new(), frame_system::CheckSpecVersion::<rialto_parachain_runtime::Runtime>::new(), frame_system::CheckTxVersion::<rialto_parachain_runtime::Runtime>::new(), frame_system::CheckGenesis::<rialto_parachain_runtime::Runtime>::new(), frame_system::CheckEra::<rialto_parachain_runtime::Runtime>::from( - param.era.frame_era(), - ), - frame_system::CheckNonce::<rialto_parachain_runtime::Runtime>::from( - param.unsigned.nonce, + unsigned.era.frame_era(), ), + frame_system::CheckNonce::<rialto_parachain_runtime::Runtime>::from(unsigned.nonce), frame_system::CheckWeight::<rialto_parachain_runtime::Runtime>::new(), pallet_transaction_payment::ChargeTransactionPayment::< rialto_parachain_runtime::Runtime, - >::from(param.unsigned.tip), + >::from(unsigned.tip), ), ( (), param.spec_version, param.transaction_version, param.genesis_hash, - param.era.signed_payload(param.genesis_hash), + unsigned.era.signed_payload(param.genesis_hash), (), (), (), diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs index 733ca9d1465701f0214e59cc4de6fcccadb577de..b2984336cd265f7c13df5b8ef42619c15e62fff1 100644 --- a/bridges/relays/client-rialto/src/lib.rs +++ b/bridges/relays/client-rialto/src/lib.rs @@ -109,25 +109,28 @@ impl TransactionSignScheme for Rialto { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = rialto_runtime::UncheckedExtrinsic; - fn sign_transaction(param: SignParam<Self>) -> Result<Self::SignedTransaction, SubstrateError> { + fn sign_transaction( + param: SignParam<Self>, + unsigned: UnsignedTransaction<Self::Chain>, + ) -> Result<Self::SignedTransaction, SubstrateError> { let raw_payload = SignedPayload::from_raw( - param.unsigned.call, + unsigned.call.clone(), ( frame_system::CheckNonZeroSender::<rialto_runtime::Runtime>::new(), frame_system::CheckSpecVersion::<rialto_runtime::Runtime>::new(), frame_system::CheckTxVersion::<rialto_runtime::Runtime>::new(), frame_system::CheckGenesis::<rialto_runtime::Runtime>::new(), - frame_system::CheckEra::<rialto_runtime::Runtime>::from(param.era.frame_era()), - frame_system::CheckNonce::<rialto_runtime::Runtime>::from(param.unsigned.nonce), + frame_system::CheckEra::<rialto_runtime::Runtime>::from(unsigned.era.frame_era()), + frame_system::CheckNonce::<rialto_runtime::Runtime>::from(unsigned.nonce), frame_system::CheckWeight::<rialto_runtime::Runtime>::new(), - pallet_transaction_payment::ChargeTransactionPayment::<rialto_runtime::Runtime>::from(param.unsigned.tip), + pallet_transaction_payment::ChargeTransactionPayment::<rialto_runtime::Runtime>::from(unsigned.tip), ), ( (), param.spec_version, param.transaction_version, param.genesis_hash, - param.era.signed_payload(param.genesis_hash), + unsigned.era.signed_payload(param.genesis_hash), (), (), (), @@ -158,13 +161,17 @@ impl TransactionSignScheme for Rialto { fn parse_transaction(tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self::Chain>> { let extra = &tx.signature.as_ref()?.2; - Some(UnsignedTransaction { - call: tx.function.into(), - nonce: Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.5.encode()[..]).ok()?.into(), - tip: Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.7.encode()[..]) - .ok()? - .into(), - }) + Some( + UnsignedTransaction::new( + tx.function.into(), + Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.5.encode()[..]).ok()?.into(), + ) + .tip( + Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.7.encode()[..]) + .ok()? + .into(), + ), + ) } } @@ -188,15 +195,17 @@ mod tests { .into(), nonce: 777, tip: 888, - }; - let signed_transaction = Rialto::sign_transaction(SignParam { - spec_version: 42, - transaction_version: 50000, - genesis_hash: [42u8; 32].into(), - signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), era: TransactionEra::immortal(), - unsigned: unsigned.clone(), - }) + }; + let signed_transaction = Rialto::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 32].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) .unwrap(); let parsed_transaction = Rialto::parse_transaction(signed_transaction).unwrap(); assert_eq!(parsed_transaction, unsigned); diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs index adfecff4eed185abc8e063d97f681905231a3436..132b86ad0b7bd25479f6251609d008f093709e2f 100644 --- a/bridges/relays/client-substrate/src/chain.rs +++ b/bridges/relays/client-substrate/src/chain.rs @@ -15,7 +15,9 @@ // along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>. use bp_messages::MessageNonce; -use bp_runtime::{Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEraOf}; +use bp_runtime::{ + Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEra, TransactionEraOf, +}; use codec::{Codec, Encode}; use frame_support::weights::{Weight, WeightToFeePolynomial}; use jsonrpsee::core::{DeserializeOwned, Serialize}; @@ -158,12 +160,14 @@ pub struct UnsignedTransaction<C: Chain> { pub nonce: C::Index, /// Tip included into transaction. pub tip: C::Balance, + /// Transaction era used by the chain. + pub era: TransactionEraOf<C>, } impl<C: Chain> UnsignedTransaction<C> { - /// Create new unsigned transaction with given call, nonce and zero tip. + /// Create new unsigned transaction with given call, nonce, era and zero tip. pub fn new(call: EncodedOrDecodedCall<C::Call>, nonce: C::Index) -> Self { - Self { call, nonce, tip: Zero::zero() } + Self { call, nonce, era: TransactionEra::Immortal, tip: Zero::zero() } } /// Set transaction tip. @@ -172,13 +176,20 @@ impl<C: Chain> UnsignedTransaction<C> { self.tip = tip; self } + + /// Set transaction era. + #[must_use] + pub fn era(mut self, era: TransactionEraOf<C>) -> Self { + self.era = era; + self + } } /// Account key pair used by transactions signing scheme. pub type AccountKeyPairOf<S> = <S as TransactionSignScheme>::AccountKeyPair; /// Substrate-based chain transactions signing scheme. -pub trait TransactionSignScheme { +pub trait TransactionSignScheme: 'static { /// Chain that this scheme is to be used. type Chain: Chain; /// Type of key pairs used to sign transactions. @@ -187,7 +198,10 @@ pub trait TransactionSignScheme { type SignedTransaction: Clone + Debug + Codec + Send + 'static; /// Create transaction for given runtime call, signed by given account. - fn sign_transaction(param: SignParam<Self>) -> Result<Self::SignedTransaction, crate::Error> + fn sign_transaction( + param: SignParam<Self>, + unsigned: UnsignedTransaction<Self::Chain>, + ) -> Result<Self::SignedTransaction, crate::Error> where Self: Sized; @@ -213,10 +227,6 @@ pub struct SignParam<T: TransactionSignScheme> { pub genesis_hash: <T::Chain as ChainBase>::Hash, /// Signer account pub signer: T::AccountKeyPair, - /// Transaction era used by the chain. - pub era: TransactionEraOf<T::Chain>, - /// Transaction before it is signed. - pub unsigned: UnsignedTransaction<T::Chain>, } impl<Block: BlockT> BlockWithJustification<Block::Header> for SignedBlock<Block> { diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs index c6fd07c5ae5999626fe81171afc5c4596faf9187..38e2a8b106c667d4e50c759d75f2b44f4c3f405c 100644 --- a/bridges/relays/client-substrate/src/client.rs +++ b/bridges/relays/client-substrate/src/client.rs @@ -17,13 +17,14 @@ //! Substrate node client. use crate::{ - chain::{Chain, ChainWithBalances, TransactionStatusOf}, + chain::{Chain, ChainWithBalances}, rpc::{ SubstrateAuthorClient, SubstrateChainClient, SubstrateFrameSystemClient, SubstrateGrandpaClient, SubstrateStateClient, SubstrateSystemClient, SubstrateTransactionPaymentClient, }, - ConnectionParams, Error, HashOf, HeaderIdOf, Result, + ConnectionParams, Error, HashOf, HeaderIdOf, Result, SignParam, TransactionSignScheme, + TransactionStatusOf, UnsignedTransaction, }; use async_std::sync::{Arc, Mutex}; @@ -403,10 +404,13 @@ impl<C: Chain> Client<C> { /// if all client instances are clones of the same initial `Client`. /// /// Note: The given transaction needs to be SCALE encoded beforehand. - pub async fn submit_signed_extrinsic( + pub async fn submit_signed_extrinsic<S: TransactionSignScheme<Chain = C> + 'static>( &self, extrinsic_signer: C::AccountId, - prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Result<Bytes> + Send + 'static, + signing_data: SignParam<S>, + prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Result<UnsignedTransaction<C>> + + Send + + 'static, ) -> Result<C::Hash> { let _guard = self.submit_signed_extrinsic_lock.lock().await; let transaction_nonce = self.next_account_index(extrinsic_signer).await?; @@ -421,12 +425,14 @@ impl<C: Chain> Client<C> { self.jsonrpsee_execute(move |client| async move { let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?; - let tx_hash = SubstrateAuthorClient::<C>::submit_extrinsic(&*client, extrinsic) - .await - .map_err(|e| { - log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); - e - })?; + let signed_extrinsic = S::sign_transaction(signing_data, extrinsic)?.encode(); + let tx_hash = + SubstrateAuthorClient::<C>::submit_extrinsic(&*client, Bytes(signed_extrinsic)) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); Ok(tx_hash) }) @@ -435,10 +441,15 @@ impl<C: Chain> Client<C> { /// Does exactly the same as `submit_signed_extrinsic`, but keeps watching for extrinsic status /// after submission. - pub async fn submit_and_watch_signed_extrinsic( + pub async fn submit_and_watch_signed_extrinsic< + S: TransactionSignScheme<Chain = C> + 'static, + >( &self, extrinsic_signer: C::AccountId, - prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Result<Bytes> + Send + 'static, + signing_data: SignParam<S>, + prepare_extrinsic: impl FnOnce(HeaderIdOf<C>, C::Index) -> Result<UnsignedTransaction<C>> + + Send + + 'static, ) -> Result<Subscription<TransactionStatusOf<C>>> { let _guard = self.submit_signed_extrinsic_lock.lock().await; let transaction_nonce = self.next_account_index(extrinsic_signer).await?; @@ -447,14 +458,17 @@ impl<C: Chain> Client<C> { let subscription = self .jsonrpsee_execute(move |client| async move { let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?; - let tx_hash = C::Hasher::hash(&extrinsic.0); - let subscription = - SubstrateAuthorClient::<C>::submit_and_watch_extrinsic(&*client, extrinsic) - .await - .map_err(|e| { - log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); - e - })?; + let signed_extrinsic = S::sign_transaction(signing_data, extrinsic)?.encode(); + let tx_hash = C::Hasher::hash(&signed_extrinsic); + let subscription = SubstrateAuthorClient::<C>::submit_and_watch_extrinsic( + &*client, + Bytes(signed_extrinsic), + ) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); Ok(subscription) }) diff --git a/bridges/relays/finality/src/finality_loop_tests.rs b/bridges/relays/finality/src/finality_loop_tests.rs index 330d166098ca3567305397d9d88641348ef50aa3..b7f7bc80029fa4dd499472cf407ec4787202dccf 100644 --- a/bridges/relays/finality/src/finality_loop_tests.rs +++ b/bridges/relays/finality/src/finality_loop_tests.rs @@ -127,7 +127,7 @@ impl SourceClient<TestFinalitySyncPipeline> for TestSourceClient { async fn best_finalized_block_number(&self) -> Result<TestNumber, TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); Ok(data.source_best_block_number) } @@ -136,13 +136,13 @@ impl SourceClient<TestFinalitySyncPipeline> for TestSourceClient { number: TestNumber, ) -> Result<(TestSourceHeader, Option<TestFinalityProof>), TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); data.source_headers.get(&number).cloned().ok_or(TestError::NonConnection) } async fn finality_proofs(&self) -> Result<Self::FinalityProofsStream, TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); Ok(futures::stream::iter(data.source_proofs.clone()).boxed()) } } @@ -168,7 +168,7 @@ impl TargetClient<TestFinalitySyncPipeline> for TestTargetClient { &self, ) -> Result<HeaderId<TestHash, TestNumber>, TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); Ok(data.target_best_block_id) } @@ -178,7 +178,7 @@ impl TargetClient<TestFinalitySyncPipeline> for TestTargetClient { proof: TestFinalityProof, ) -> Result<(), TestError> { let mut data = self.data.lock(); - (self.on_method_call)(&mut *data); + (self.on_method_call)(&mut data); data.target_best_block_id = HeaderId(header.number(), header.hash()); data.target_headers.push((header, proof)); Ok(()) diff --git a/bridges/relays/lib-substrate-relay/src/conversion_rate_update.rs b/bridges/relays/lib-substrate-relay/src/conversion_rate_update.rs index c7e241626945db1c55420f0ac21195fb318360a4..ed13f4e5b35ff2f275db373c84e4e3253a9a68ec 100644 --- a/bridges/relays/lib-substrate-relay/src/conversion_rate_update.rs +++ b/bridges/relays/lib-substrate-relay/src/conversion_rate_update.rs @@ -18,13 +18,12 @@ use crate::{messages_lane::SubstrateMessageLane, TransactionParams}; -use codec::Encode; use relay_substrate_client::{ transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, CallOf, Chain, Client, SignParam, TransactionEra, TransactionSignScheme, UnsignedTransaction, }; use relay_utils::metrics::F64SharedRef; -use sp_core::{Bytes, Pair}; +use sp_core::Pair; use std::time::{Duration, Instant}; /// Duration between updater iterations. @@ -272,19 +271,19 @@ where updated_rate, )?; client - .submit_signed_extrinsic(signer_id, move |best_block_id, transaction_nonce| { - Ok(Bytes( - Sign::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash, - signer: transaction_params.signer, - era: TransactionEra::new(best_block_id, transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) - }) + .submit_signed_extrinsic( + signer_id, + SignParam::<Sign> { + spec_version, + transaction_version, + genesis_hash, + signer: transaction_params.signer, + }, + move |best_block_id, transaction_nonce| { + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) + }, + ) .await .map(drop) .map_err(|err| anyhow::format_err!("{:?}", err)) diff --git a/bridges/relays/lib-substrate-relay/src/error.rs b/bridges/relays/lib-substrate-relay/src/error.rs index 64ed3a4fd49c60989d169911d2539b5eeac05751..b41870a181d933e896540c27232ce2cc6ac082bb 100644 --- a/bridges/relays/lib-substrate-relay/src/error.rs +++ b/bridges/relays/lib-substrate-relay/src/error.rs @@ -53,7 +53,7 @@ pub enum Error<Hash: Debug + MaybeDisplay, HeaderNumber: Debug + MaybeDisplay> { #[error("Failed to decode {0} GRANDPA authorities set at header {1}: {2:?}")] DecodeAuthorities(&'static str, Hash, codec::Error), /// Failed to retrieve header by the hash from the source chain. - #[error("Failed to retrieve {0} header with hash {1}: {:?}")] + #[error("Failed to retrieve {0} header with hash {1}: {2:?}")] RetrieveHeader(&'static str, Hash, client::Error), /// Failed to submit signed extrinsic from to the target chain. #[error( diff --git a/bridges/relays/lib-substrate-relay/src/finality/initialize.rs b/bridges/relays/lib-substrate-relay/src/finality/initialize.rs index be1719b4ae033e5b8f217d33a824acb9ce9cbe5b..e25743180ee9ed8692ffc78c2b5d8a8885bf4db8 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/initialize.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/initialize.rs @@ -23,18 +23,28 @@ use crate::{error::Error, finality::engine::Engine}; -use relay_substrate_client::{Chain, Client, Error as SubstrateError}; -use sp_core::Bytes; +use relay_substrate_client::{ + Chain, Client, Error as SubstrateError, SignParam, TransactionSignScheme, UnsignedTransaction, +}; use sp_runtime::traits::Header as HeaderT; /// Submit headers-bridge initialization transaction. -pub async fn initialize<E: Engine<SourceChain>, SourceChain: Chain, TargetChain: Chain, F>( +pub async fn initialize< + E: Engine<SourceChain>, + SourceChain: Chain, + TargetChain: Chain + TransactionSignScheme<Chain = TargetChain>, + F, +>( source_client: Client<SourceChain>, target_client: Client<TargetChain>, target_transactions_signer: TargetChain::AccountId, + target_signing_data: SignParam<TargetChain>, prepare_initialize_transaction: F, ) where - F: FnOnce(TargetChain::Index, E::InitializationData) -> Result<Bytes, SubstrateError> + F: FnOnce( + TargetChain::Index, + E::InitializationData, + ) -> Result<UnsignedTransaction<TargetChain>, SubstrateError> + Send + 'static, { @@ -42,6 +52,7 @@ pub async fn initialize<E: Engine<SourceChain>, SourceChain: Chain, TargetChain: source_client, target_client, target_transactions_signer, + target_signing_data, prepare_initialize_transaction, ) .await; @@ -66,17 +77,26 @@ pub async fn initialize<E: Engine<SourceChain>, SourceChain: Chain, TargetChain: } /// Craft and submit initialization transaction, returning any error that may occur. -async fn do_initialize<E: Engine<SourceChain>, SourceChain: Chain, TargetChain: Chain, F>( +async fn do_initialize< + E: Engine<SourceChain>, + SourceChain: Chain, + TargetChain: Chain + TransactionSignScheme<Chain = TargetChain>, + F, +>( source_client: Client<SourceChain>, target_client: Client<TargetChain>, target_transactions_signer: TargetChain::AccountId, + target_signing_data: SignParam<TargetChain>, prepare_initialize_transaction: F, ) -> Result< Option<TargetChain::Hash>, Error<SourceChain::Hash, <SourceChain::Header as HeaderT>::Number>, > where - F: FnOnce(TargetChain::Index, E::InitializationData) -> Result<Bytes, SubstrateError> + F: FnOnce( + TargetChain::Index, + E::InitializationData, + ) -> Result<UnsignedTransaction<TargetChain>, SubstrateError> + Send + 'static, { @@ -103,10 +123,15 @@ where ); let initialization_tx_hash = target_client - .submit_signed_extrinsic(target_transactions_signer, move |_, transaction_nonce| { - prepare_initialize_transaction(transaction_nonce, initialization_data) - }) + .submit_signed_extrinsic( + target_transactions_signer, + target_signing_data, + move |_, transaction_nonce| { + prepare_initialize_transaction(transaction_nonce, initialization_data) + }, + ) .await .map_err(|err| Error::SubmitTransaction(TargetChain::NAME, err))?; + Ok(Some(initialization_tx_hash)) } diff --git a/bridges/relays/lib-substrate-relay/src/finality/mod.rs b/bridges/relays/lib-substrate-relay/src/finality/mod.rs index 736937ba0724dcfd77198f99815f7cd470ab0fac..3144a1016ea5c58a0f9e2ba05281e4be8d352f46 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/mod.rs @@ -194,7 +194,7 @@ where stall_timeout: transaction_stall_timeout( transaction_params.mortality, P::TargetChain::AVERAGE_BLOCK_INTERVAL, - crate::STALL_TIMEOUT, + relay_utils::STALL_TIMEOUT, ), only_mandatory_headers, }, diff --git a/bridges/relays/lib-substrate-relay/src/finality/target.rs b/bridges/relays/lib-substrate-relay/src/finality/target.rs index f9859937ff3421934fe05d02d2b2a5ef1df72fb0..351f21cec80a97673bf788a69aa0a1c635f581ac 100644 --- a/bridges/relays/lib-substrate-relay/src/finality/target.rs +++ b/bridges/relays/lib-substrate-relay/src/finality/target.rs @@ -25,14 +25,13 @@ use crate::{ }; use async_trait::async_trait; -use codec::Encode; use finality_relay::TargetClient; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, Chain, Client, Error, HeaderIdOf, HeaderOf, SignParam, SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, }; use relay_utils::relay_loop::Client as RelayClient; -use sp_core::{Bytes, Pair}; +use sp_core::Pair; /// Substrate client as Substrate finality target. pub struct SubstrateFinalityTarget<P: SubstrateFinalitySyncPipeline> { @@ -119,18 +118,15 @@ where self.client .submit_signed_extrinsic( self.transaction_params.signer.public().into(), + SignParam::<P::TransactionSignScheme> { + spec_version, + transaction_version, + genesis_hash, + signer: transaction_params.signer.clone(), + }, move |best_block_id, transaction_nonce| { - Ok(Bytes( - P::TransactionSignScheme::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash, - signer: transaction_params.signer.clone(), - era: TransactionEra::new(best_block_id, transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) }, ) .await diff --git a/bridges/relays/lib-substrate-relay/src/lib.rs b/bridges/relays/lib-substrate-relay/src/lib.rs index 1af4f67a7caf50cec83eabd1d5a232d7ccf849b1..f4f1aae9d29d198479cb7e0b1d543cb3dc2dd6a2 100644 --- a/bridges/relays/lib-substrate-relay/src/lib.rs +++ b/bridges/relays/lib-substrate-relay/src/lib.rs @@ -18,8 +18,6 @@ #![warn(missing_docs)] -use std::time::Duration; - pub mod conversion_rate_update; pub mod error; pub mod finality; @@ -31,15 +29,6 @@ pub mod messages_target; pub mod on_demand; pub mod parachains; -/// Default relay loop stall timeout. If transactions generated by relay are immortal, then -/// this timeout is used. -/// -/// There are no any strict requirements on block time in Substrate. But we assume here that all -/// Substrate-based chains will be designed to produce relatively fast (compared to the slowest -/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine -/// transaction, or remove it from the pool. -pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); - /// Transaction creation parameters. #[derive(Clone, Debug)] pub struct TransactionParams<TS> { diff --git a/bridges/relays/lib-substrate-relay/src/messages_lane.rs b/bridges/relays/lib-substrate-relay/src/messages_lane.rs index 050fa3ee1ae38c2a96bfa8a679125050be16d4c2..18e150e3617ddbb754ab5a91e711805bacb1cfee 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_lane.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_lane.rs @@ -22,7 +22,7 @@ use crate::{ messages_source::{SubstrateMessagesProof, SubstrateMessagesSource}, messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget}, on_demand::OnDemandRelay, - TransactionParams, STALL_TIMEOUT, + TransactionParams, }; use async_std::sync::Arc; @@ -39,7 +39,7 @@ use relay_substrate_client::{ transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithMessages, Client, HashOf, TransactionSignScheme, }; -use relay_utils::metrics::MetricsParams; +use relay_utils::{metrics::MetricsParams, STALL_TIMEOUT}; use sp_core::Pair; use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs index f032ec3c0c082c557bb50120ffa636dda2c54dfb..5de9e30dd0ea2028b5e8b170490ade6d2ad075f8 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs @@ -346,11 +346,14 @@ where self.source_client .submit_signed_extrinsic( self.transaction_params.signer.public().into(), + SignParam::<P::SourceTransactionSignScheme> { + spec_version, + transaction_version, + genesis_hash, + signer: self.transaction_params.signer.clone(), + }, move |best_block_id, transaction_nonce| { make_messages_delivery_proof_transaction::<P>( - spec_version, - transaction_version, - &genesis_hash, &transaction_params, best_block_id, transaction_nonce, @@ -377,18 +380,24 @@ where Err(_) => return BalanceOf::<P::SourceChain>::max_value(), }; async { - let dummy_tx = make_messages_delivery_proof_transaction::<P>( - runtime_version.spec_version, - runtime_version.transaction_version, - self.source_client.genesis_hash(), - &self.transaction_params, - HeaderId(Default::default(), Default::default()), - Zero::zero(), - prepare_dummy_messages_delivery_proof::<P::SourceChain, P::TargetChain>(), - false, - )?; + let dummy_tx = P::SourceTransactionSignScheme::sign_transaction( + SignParam::<P::SourceTransactionSignScheme> { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + genesis_hash: *self.source_client.genesis_hash(), + signer: self.transaction_params.signer.clone(), + }, + make_messages_delivery_proof_transaction::<P>( + &self.transaction_params, + HeaderId(Default::default(), Default::default()), + Zero::zero(), + prepare_dummy_messages_delivery_proof::<P::SourceChain, P::TargetChain>(), + false, + )?, + )? + .encode(); self.source_client - .estimate_extrinsic_fee(dummy_tx) + .estimate_extrinsic_fee(Bytes(dummy_tx)) .await .map(|fee| fee.inclusion_fee()) } @@ -418,17 +427,13 @@ where } /// Make messages delivery proof transaction from given proof. -#[allow(clippy::too_many_arguments)] fn make_messages_delivery_proof_transaction<P: SubstrateMessageLane>( - spec_version: u32, - transaction_version: u32, - source_genesis_hash: &HashOf<P::SourceChain>, source_transaction_params: &TransactionParams<AccountKeyPairOf<P::SourceTransactionSignScheme>>, source_best_block_id: HeaderIdOf<P::SourceChain>, transaction_nonce: IndexOf<P::SourceChain>, proof: SubstrateMessagesDeliveryProof<P::TargetChain>, trace_call: bool, -) -> Result<Bytes, SubstrateError> +) -> Result<UnsignedTransaction<P::SourceChain>, SubstrateError> where P::SourceTransactionSignScheme: TransactionSignScheme<Chain = P::SourceChain>, { @@ -436,17 +441,8 @@ where P::ReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call( proof, trace_call, ); - Ok(Bytes( - P::SourceTransactionSignScheme::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *source_genesis_hash, - signer: source_transaction_params.signer.clone(), - era: TransactionEra::new(source_best_block_id, source_transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(source_best_block_id, source_transaction_params.mortality))) } /// Prepare 'dummy' messages delivery proof that will compose the delivery confirmation transaction. diff --git a/bridges/relays/lib-substrate-relay/src/messages_target.rs b/bridges/relays/lib-substrate-relay/src/messages_target.rs index b315dfed4bb508af775683608ba5ae7f6ab1a9a4..d88b0539153dd6148898f51f2933ba4635b12bac 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_target.rs @@ -255,11 +255,14 @@ where self.target_client .submit_signed_extrinsic( self.transaction_params.signer.public().into(), + SignParam::<P::TargetTransactionSignScheme> { + spec_version, + transaction_version, + genesis_hash, + signer: self.transaction_params.signer.clone(), + }, move |best_block_id, transaction_nonce| { make_messages_delivery_transaction::<P>( - spec_version, - transaction_version, - &genesis_hash, &transaction_params, best_block_id, transaction_nonce, @@ -299,23 +302,29 @@ where let (spec_version, transaction_version) = self.target_client.simple_runtime_version().await?; // Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight. - let delivery_tx = make_messages_delivery_transaction::<P>( - spec_version, - transaction_version, - self.target_client.genesis_hash(), - &self.transaction_params, - HeaderId(Default::default(), Default::default()), - Zero::zero(), - self.relayer_id_at_source.clone(), - nonces.clone(), - prepare_dummy_messages_proof::<P::SourceChain>( + let delivery_tx = P::TargetTransactionSignScheme::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: Default::default(), + signer: self.transaction_params.signer.clone(), + }, + make_messages_delivery_transaction::<P>( + &self.transaction_params, + HeaderId(Default::default(), Default::default()), + Zero::zero(), + self.relayer_id_at_source.clone(), nonces.clone(), - total_dispatch_weight, - total_size, - ), - false, - )?; - let delivery_tx_fee = self.target_client.estimate_extrinsic_fee(delivery_tx).await?; + prepare_dummy_messages_proof::<P::SourceChain>( + nonces.clone(), + total_dispatch_weight, + total_size, + ), + false, + )?, + )? + .encode(); + let delivery_tx_fee = self.target_client.estimate_extrinsic_fee(Bytes(delivery_tx)).await?; let inclusion_fee_in_target_tokens = delivery_tx_fee.inclusion_fee(); // The pre-dispatch cost of delivery transaction includes additional fee to cover dispatch @@ -340,24 +349,30 @@ where let (spec_version, transaction_version) = self.target_client.simple_runtime_version().await?; let larger_dispatch_weight = total_dispatch_weight.saturating_add(WEIGHT_DIFFERENCE); - let dummy_tx = make_messages_delivery_transaction::<P>( - spec_version, - transaction_version, - self.target_client.genesis_hash(), - &self.transaction_params, - HeaderId(Default::default(), Default::default()), - Zero::zero(), - self.relayer_id_at_source.clone(), - nonces.clone(), - prepare_dummy_messages_proof::<P::SourceChain>( + let dummy_tx = P::TargetTransactionSignScheme::sign_transaction( + SignParam { + spec_version, + transaction_version, + genesis_hash: Default::default(), + signer: self.transaction_params.signer.clone(), + }, + make_messages_delivery_transaction::<P>( + &self.transaction_params, + HeaderId(Default::default(), Default::default()), + Zero::zero(), + self.relayer_id_at_source.clone(), nonces.clone(), - larger_dispatch_weight, - total_size, - ), - false, - )?; + prepare_dummy_messages_proof::<P::SourceChain>( + nonces.clone(), + larger_dispatch_weight, + total_size, + ), + false, + )?, + )? + .encode(); let larger_delivery_tx_fee = - self.target_client.estimate_extrinsic_fee(dummy_tx).await?; + self.target_client.estimate_extrinsic_fee(Bytes(dummy_tx)).await?; compute_prepaid_messages_refund::<P::TargetChain>( total_prepaid_nonces, @@ -406,11 +421,7 @@ where } /// Make messages delivery transaction from given proof. -#[allow(clippy::too_many_arguments)] fn make_messages_delivery_transaction<P: SubstrateMessageLane>( - spec_version: u32, - transaction_version: u32, - target_genesis_hash: &HashOf<P::TargetChain>, target_transaction_params: &TransactionParams<AccountKeyPairOf<P::TargetTransactionSignScheme>>, target_best_block_id: HeaderIdOf<P::TargetChain>, transaction_nonce: IndexOf<P::TargetChain>, @@ -418,7 +429,7 @@ fn make_messages_delivery_transaction<P: SubstrateMessageLane>( nonces: RangeInclusive<MessageNonce>, proof: SubstrateMessagesProof<P::SourceChain>, trace_call: bool, -) -> Result<Bytes, SubstrateError> +) -> Result<UnsignedTransaction<P::TargetChain>, SubstrateError> where P::TargetTransactionSignScheme: TransactionSignScheme<Chain = P::TargetChain>, { @@ -431,17 +442,8 @@ where dispatch_weight, trace_call, ); - Ok(Bytes( - P::TargetTransactionSignScheme::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash: *target_genesis_hash, - signer: target_transaction_params.signer.clone(), - era: TransactionEra::new(target_best_block_id, target_transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(target_best_block_id, target_transaction_params.mortality))) } /// Prepare 'dummy' messages proof that will compose the delivery transaction. diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs b/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs index 749205ef9b3cd85e4fc1e454e829f8d51438ab59..09e7a41a0c7253b88825747a02878495a2db185e 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/headers.rs @@ -28,6 +28,7 @@ use relay_substrate_client::{ }; use relay_utils::{ metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, MaybeConnectionError, + STALL_TIMEOUT, }; use crate::{ @@ -37,7 +38,7 @@ use crate::{ SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT, }, on_demand::OnDemandRelay, - TransactionParams, STALL_TIMEOUT, + TransactionParams, }; /// On-demand Substrate <-> Substrate header finality relay. diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs index dc400115502eba68a32319bf371e8248348d256a..577312e16c109e9887f7784cd4e2a7c3e498b088 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -263,7 +263,7 @@ async fn background_task<P: SubstrateParachainsPipeline>( let stall_timeout = relay_substrate_client::transaction_stall_timeout( target_transactions_mortality, P::TargetChain::AVERAGE_BLOCK_INTERVAL, - crate::STALL_TIMEOUT, + relay_utils::STALL_TIMEOUT, ); log::info!( diff --git a/bridges/relays/lib-substrate-relay/src/parachains/target.rs b/bridges/relays/lib-substrate-relay/src/parachains/target.rs index a96c0ba0ab692ceb27a31ca408e473cae094fbc9..355dd394c2188d00611932f51ac655ce594fd45e 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/target.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/target.rs @@ -29,7 +29,7 @@ use bp_parachains::{ }; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_runtime::HeaderIdProvider; -use codec::{Decode, Encode}; +use codec::Decode; use parachains_relay::{ parachains_loop::TargetClient, parachains_loop_metrics::ParachainsLoopMetrics, }; @@ -141,7 +141,7 @@ where .and_then(|maybe_encoded_head| match maybe_encoded_head { Some(encoded_head) => HeaderOf::<P::SourceParachain>::decode(&mut &encoded_head.0[..]) - .map(|head| Some(head)) + .map(Some) .map_err(Self::Error::ResponseParseFailed), None => Ok(None), }) @@ -182,18 +182,15 @@ where self.client .submit_signed_extrinsic( self.transaction_params.signer.public().into(), + SignParam::<P::TransactionSignScheme> { + spec_version, + transaction_version, + genesis_hash, + signer: transaction_params.signer, + }, move |best_block_id, transaction_nonce| { - Ok(Bytes( - P::TransactionSignScheme::sign_transaction(SignParam { - spec_version, - transaction_version, - genesis_hash, - signer: transaction_params.signer, - era: TransactionEra::new(best_block_id, transaction_params.mortality), - unsigned: UnsignedTransaction::new(call.into(), transaction_nonce), - })? - .encode(), - )) + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) }, ) .await diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs index 2e700deb9a6bf59398afbb0dcad9ac107a3d0b89..bd7a7de8290b9100656368aadac39632ee92fca0 100644 --- a/bridges/relays/messages/src/message_lane_loop.rs +++ b/bridges/relays/messages/src/message_lane_loop.rs @@ -94,7 +94,7 @@ pub struct MessageDeliveryParams<Strategy: RelayStrategy> { } /// Message details. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MessageDetails<SourceChainBalance> { /// Message dispatch weight. pub dispatch_weight: Weight, @@ -224,7 +224,7 @@ pub trait TargetClient<P: MessageLane>: RelayClient { } /// State of the client. -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct ClientState<SelfHeaderId, PeerHeaderId> { /// The best header id of this chain. pub best_self: SelfHeaderId, @@ -560,7 +560,7 @@ pub(crate) mod tests { async fn reconnect(&mut self) -> Result<(), TestError> { { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); data.is_source_reconnected = true; } Ok(()) @@ -571,7 +571,7 @@ pub(crate) mod tests { impl SourceClient<TestMessageLane> for TestSourceClient { async fn state(&self) -> Result<SourceClientState<TestMessageLane>, TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_source_fails { return Err(TestError) } @@ -583,7 +583,7 @@ pub(crate) mod tests { id: SourceHeaderIdOf<TestMessageLane>, ) -> Result<(SourceHeaderIdOf<TestMessageLane>, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_source_fails { return Err(TestError) } @@ -595,7 +595,7 @@ pub(crate) mod tests { id: SourceHeaderIdOf<TestMessageLane>, ) -> Result<(SourceHeaderIdOf<TestMessageLane>, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); Ok((id, data.source_latest_confirmed_received_nonce)) } @@ -629,7 +629,7 @@ pub(crate) mod tests { TestError, > { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); Ok(( id, nonces.clone(), @@ -650,7 +650,7 @@ pub(crate) mod tests { proof: TestMessagesReceivingProof, ) -> Result<(), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); data.source_state.best_self = HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1); data.source_state.best_finalized_self = data.source_state.best_self; @@ -663,7 +663,7 @@ pub(crate) mod tests { let mut data = self.data.lock(); data.target_to_source_header_required = Some(id); data.target_to_source_header_requirements.push(id); - (self.tick)(&mut *data); + (self.tick)(&mut data); } async fn estimate_confirmation_transaction(&self) -> TestSourceChainBalance { @@ -693,7 +693,7 @@ pub(crate) mod tests { async fn reconnect(&mut self) -> Result<(), TestError> { { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); data.is_target_reconnected = true; } Ok(()) @@ -704,7 +704,7 @@ pub(crate) mod tests { impl TargetClient<TestMessageLane> for TestTargetClient { async fn state(&self) -> Result<TargetClientState<TestMessageLane>, TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -716,7 +716,7 @@ pub(crate) mod tests { id: TargetHeaderIdOf<TestMessageLane>, ) -> Result<(TargetHeaderIdOf<TestMessageLane>, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -743,7 +743,7 @@ pub(crate) mod tests { id: TargetHeaderIdOf<TestMessageLane>, ) -> Result<(TargetHeaderIdOf<TestMessageLane>, MessageNonce), TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -764,7 +764,7 @@ pub(crate) mod tests { proof: TestMessagesProof, ) -> Result<RangeInclusive<MessageNonce>, TestError> { let mut data = self.data.lock(); - (self.tick)(&mut *data); + (self.tick)(&mut data); if data.is_target_fails { return Err(TestError) } @@ -784,7 +784,7 @@ pub(crate) mod tests { let mut data = self.data.lock(); data.source_to_target_header_required = Some(id); data.source_to_target_header_requirements.push(id); - (self.tick)(&mut *data); + (self.tick)(&mut data); } async fn estimate_delivery_transaction_in_source_tokens( diff --git a/bridges/relays/utils/src/lib.rs b/bridges/relays/utils/src/lib.rs index 603011819bc6ff78b49ffc3c0f99e05137813fb6..8e8870ac188f661741b3cf4f0c1124c4ca316de2 100644 --- a/bridges/relays/utils/src/lib.rs +++ b/bridges/relays/utils/src/lib.rs @@ -25,6 +25,15 @@ use futures::future::FutureExt; use std::time::Duration; use thiserror::Error; +/// Default relay loop stall timeout. If transactions generated by relay are immortal, then +/// this timeout is used. +/// +/// There are no any strict requirements on block time in Substrate. But we assume here that all +/// Substrate-based chains will be designed to produce relatively fast (compared to the slowest +/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine +/// transaction, or remove it from the pool. +pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); + /// Max delay after connection-unrelated error happened before we'll try the /// same request again. pub const MAX_BACKOFF_INTERVAL: Duration = Duration::from_secs(60);