diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 835a8cf1318f..e3c05d1bebbc 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -93,7 +93,6 @@ runtime-benchmarks = [ "pallet-bridge-messages/runtime-benchmarks", "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", - "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index 035077408c40..2722f6f1c6d1 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -105,48 +105,43 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { ($call:ty, $account_id:ty, $($filter_call:ty),*) => { #[derive(Clone, codec::Decode, Default, codec::Encode, Eq, PartialEq, sp_runtime::RuntimeDebug, scale_info::TypeInfo)] pub struct BridgeRejectObsoleteHeadersAndMessages; - impl sp_runtime::traits::TransactionExtensionBase for BridgeRejectObsoleteHeadersAndMessages { + impl sp_runtime::traits::SignedExtension for BridgeRejectObsoleteHeadersAndMessages { const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages"; - type Implicit = (); - } - impl sp_runtime::traits::TransactionExtension<$call, Context> for BridgeRejectObsoleteHeadersAndMessages { + type AccountId = $account_id; + type Call = $call; + type AdditionalSigned = (); type Pre = (); - type Val = (); + + fn additional_signed(&self) -> sp_std::result::Result< + (), + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(()) + } fn validate( &self, - origin: <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, - call: &$call, - _info: &sp_runtime::traits::DispatchInfoOf<$call>, + _who: &Self::AccountId, + call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl codec::Encode, - ) -> Result< - ( - sp_runtime::transaction_validity::ValidTransaction, - Self::Val, - <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, - ), sp_runtime::transaction_validity::TransactionValidityError - > { - let tx_validity = sp_runtime::transaction_validity::ValidTransaction::default(); + ) -> sp_runtime::transaction_validity::TransactionValidity { + let valid = sp_runtime::transaction_validity::ValidTransaction::default(); $( - let call_filter_validity = <$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?; - let tx_validity = tx_validity.combine_with(call_filter_validity); + let valid = valid + .combine_with(<$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?); )* - Ok((tx_validity, (), origin)) + Ok(valid) } - fn prepare( + fn pre_dispatch( self, - _val: Self::Val, - _origin: &<$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, - _call: &$call, - _info: &sp_runtime::traits::DispatchInfoOf<$call>, - _len: usize, - _context: &Context, + who: &Self::AccountId, + call: &Self::Call, + info: &sp_runtime::traits::DispatchInfoOf, + len: usize, ) -> Result { - Ok(()) + self.validate(who, call, info, len).map(drop) } } }; @@ -155,14 +150,12 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { #[cfg(test)] mod tests { use crate::BridgeRuntimeFilterCall; - use codec::Encode; - use frame_support::assert_err; + use frame_support::{assert_err, assert_ok}; use sp_runtime::{ - traits::DispatchTransaction, + traits::SignedExtension, transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, }; - #[derive(Encode)] pub struct MockCall { data: u32, } @@ -213,20 +206,17 @@ mod tests { ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate_only((), &MockCall { data: 1 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 1 }, &(), 0), InvalidTransaction::Custom(1) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate_only((), &MockCall { data: 2 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 2 }, &(), 0), InvalidTransaction::Custom(2) ); - assert_eq!( - BridgeRejectObsoleteHeadersAndMessages - .validate_only((), &MockCall { data: 3 }, &(), 0) - .unwrap() - .0, + assert_ok!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 3 }, &(), 0), ValidTransaction { priority: 3, ..Default::default() } ) } diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index f147f1404f06..deee4524e858 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -141,7 +141,7 @@ parameter_types! { pub const ReserveId: [u8; 8] = *b"brdgrlrs"; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Hash = ThisChainHash; type Hashing = ThisChainHasher; @@ -158,13 +158,13 @@ impl pallet_utility::Config for TestRuntime { type WeightInfo = (); } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; } -#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig as pallet_transaction_payment::DefaultConfig)] +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for TestRuntime { type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; @@ -177,6 +177,7 @@ impl pallet_transaction_payment::Config for TestRuntime { MinimumMultiplier, MaximumMultiplier, >; + type RuntimeEvent = RuntimeEvent; } impl pallet_bridge_grandpa::Config for TestRuntime { diff --git a/bridges/bin/runtime-common/src/priority_calculator.rs b/bridges/bin/runtime-common/src/priority_calculator.rs index 0c53018330ea..c2737128e342 100644 --- a/bridges/bin/runtime-common/src/priority_calculator.rs +++ b/bridges/bin/runtime-common/src/priority_calculator.rs @@ -128,7 +128,7 @@ mod integrity_tests { Runtime::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, { - // esimate priority of transaction that delivers one message and has large tip + // estimate priority of transaction that delivers one message and has large tip let maximal_messages_in_delivery_transaction = Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); let small_with_tip_priority = @@ -169,15 +169,12 @@ mod integrity_tests { // nodes to the proof (x0.5 because we expect some nodes to be reused) let estimated_message_size = 512; // let's say all our messages have the same dispatch weight - let estimated_message_dispatch_weight = >::WeightInfo::message_dispatch_weight( - estimated_message_size - ); + let estimated_message_dispatch_weight = + Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); // messages proof argument size is (for every message) messages size + some additional // trie nodes. Some of them are reused by different messages, so let's take 2/3 of default // "overhead" constant - let messages_proof_size = >::WeightInfo::expected_extra_storage_proof_size() + let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() .saturating_mul(2) .saturating_div(3) .saturating_add(estimated_message_size) @@ -185,7 +182,7 @@ mod integrity_tests { // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(messages_proof_size); - let transaction_weight = >::WeightInfo::receive_messages_proof_weight( + let transaction_weight = Runtime::WeightInfo::receive_messages_proof_weight( &PreComputedSize(transaction_size as _), messages as _, estimated_message_dispatch_weight.saturating_mul(messages), diff --git a/bridges/bin/runtime-common/src/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/refund_relayer_extension.rs index b912f8445ac1..8e901d72821f 100644 --- a/bridges/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/refund_relayer_extension.rs @@ -16,7 +16,7 @@ //! Signed extension that refunds relayer if he has delivered some new messages. //! It also refunds transaction cost if the transaction is an `utility.batchAll()` -//! with calls that are: delivering new messsage and all necessary underlying headers +//! with calls that are: delivering new message and all necessary underlying headers //! (parachain or relay chain). use crate::messages_call_ext::{ @@ -48,12 +48,9 @@ use pallet_transaction_payment::{Config as TransactionPaymentConfig, OnChargeTra use pallet_utility::{Call as UtilityCall, Config as UtilityConfig, Pallet as UtilityPallet}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{ - AsSystemOriginSigner, DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, - TransactionExtension, TransactionExtensionBase, ValidateResult, Zero, - }, + traits::{DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, SignedExtension, Zero}, transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidityError, ValidTransactionBuilder, + TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, }, DispatchResult, FixedPointOperand, RuntimeDebug, }; @@ -242,8 +239,8 @@ pub enum RelayerAccountAction { Slash(AccountId, RewardsAccountParams), } -/// Everything common among our refund transaction extensions. -pub trait RefundTransactionExtension: +/// Everything common among our refund signed extensions. +pub trait RefundSignedExtension: 'static + Clone + Codec + sp_std::fmt::Debug + Default + Eq + PartialEq + Send + Sync + TypeInfo where >::BridgedChain: @@ -459,8 +456,8 @@ where } } -/// Adapter that allow implementing `sp_runtime::traits::TransactionExtension` for any -/// `RefundTransactionExtension`. +/// Adapter that allow implementing `sp_runtime::traits::SignedExtension` for any +/// `RefundSignedExtension`. #[derive( DefaultNoBound, CloneNoBound, @@ -471,13 +468,12 @@ where RuntimeDebugNoBound, TypeInfo, )] -pub struct RefundTransactionExtensionAdapter(T) +pub struct RefundSignedExtensionAdapter(T) where >::BridgedChain: Chain; -impl TransactionExtensionBase - for RefundTransactionExtensionAdapter +impl SignedExtension for RefundSignedExtensionAdapter where >::BridgedChain: Chain, @@ -487,35 +483,22 @@ where + MessagesCallSubType::Instance>, { const IDENTIFIER: &'static str = T::Id::STR; - type Implicit = (); -} - -impl TransactionExtension, Context> - for RefundTransactionExtensionAdapter -where - >::BridgedChain: - Chain, - CallOf: Dispatchable - + IsSubType, T::Runtime>> - + GrandpaCallSubType - + MessagesCallSubType::Instance>, - as Dispatchable>::RuntimeOrigin: - AsSystemOriginSigner> + Clone, -{ + type AccountId = AccountIdOf; + type Call = CallOf; + type AdditionalSigned = (); type Pre = Option>>; - type Val = Option; + + fn additional_signed(&self) -> Result<(), TransactionValidityError> { + Ok(()) + } fn validate( &self, - origin: as Dispatchable>::RuntimeOrigin, - call: &CallOf, - _info: &DispatchInfoOf>, + who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &mut Context, - _self_implicit: Self::Implicit, - _inherited_implication: &impl Encode, - ) -> ValidateResult> { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + ) -> TransactionValidity { // this is the only relevant line of code for the `pre_dispatch` // // we're not calling `validate` from `pre_dispatch` directly because of performance @@ -528,12 +511,12 @@ where // we only boost priority of presumably correct message delivery transactions let bundled_messages = match T::bundled_messages_for_priority_boost(parsed_call.as_ref()) { Some(bundled_messages) => bundled_messages, - None => return Ok((Default::default(), parsed_call, origin)), + None => return Ok(Default::default()), }; // we only boost priority if relayer has staked required balance if !RelayersPallet::::is_registration_active(who) { - return Ok((Default::default(), parsed_call, origin)) + return Ok(Default::default()) } // compute priority boost @@ -552,21 +535,20 @@ where priority_boost, ); - let validity = valid_transaction.build()?; - Ok((validity, parsed_call, origin)) + valid_transaction.build() } - fn prepare( + fn pre_dispatch( self, - val: Self::Val, - origin: & as Dispatchable>::RuntimeOrigin, - _call: &CallOf, - _info: &DispatchInfoOf>, + who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, _len: usize, - _context: &Context, ) -> Result { - let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - Ok(val.map(|call_info| { + // this is a relevant piece of `validate` that we need here (in `pre_dispatch`) + let parsed_call = T::parse_and_check_for_obsolete_call(call)?; + + Ok(parsed_call.map(|call_info| { log::trace!( target: "runtime::bridge", "{} via {:?} parsed bridge transaction in pre-dispatch: {:?}", @@ -579,14 +561,13 @@ where } fn post_dispatch( - pre: Self::Pre, - info: &DispatchInfoOf>, - post_info: &PostDispatchInfoOf>, + pre: Option, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - _context: &Context, ) -> Result<(), TransactionValidityError> { - let call_result = T::analyze_call_result(Some(pre), info, post_info, len, result); + let call_result = T::analyze_call_result(pre, info, post_info, len, result); match call_result { RelayerAccountAction::None => (), @@ -614,7 +595,7 @@ where } } -/// Transaction extension that refunds a relayer for new messages coming from a parachain. +/// Signed extension that refunds a relayer for new messages coming from a parachain. /// /// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) /// with message delivery transaction. Batch may deliver either both relay chain header and @@ -655,7 +636,7 @@ pub struct RefundBridgedParachainMessages, ); -impl RefundTransactionExtension +impl RefundSignedExtension for RefundBridgedParachainMessages where Self: 'static + Send + Sync, @@ -749,13 +730,13 @@ where } } -/// Transaction extension that refunds a relayer for new messages coming from a standalone (GRANDPA) +/// Signed extension that refunds a relayer for new messages coming from a standalone (GRANDPA) /// chain. /// /// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) /// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages proof -/// verification. +/// parachain head, or just parachain head. Corresponding headers must be used in messages +/// proof verification. /// /// Extension does not refund transaction tip due to security reasons. #[derive( @@ -790,7 +771,7 @@ pub struct RefundBridgedGrandpaMessages, ); -impl RefundTransactionExtension +impl RefundSignedExtension for RefundBridgedGrandpaMessages where Self: 'static + Send + Sync, @@ -888,8 +869,8 @@ mod tests { Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, }; use sp_runtime::{ - traits::{ConstU64, DispatchTransaction, Header as HeaderT}, - transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + traits::{ConstU64, Header as HeaderT}, + transaction_validity::{InvalidTransaction, ValidTransaction}, DispatchError, }; @@ -918,7 +899,7 @@ mod tests { ConstU64<1>, StrTestExtension, >; - type TestGrandpaExtension = RefundTransactionExtensionAdapter; + type TestGrandpaExtension = RefundSignedExtensionAdapter; type TestExtensionProvider = RefundBridgedParachainMessages< TestRuntime, DefaultRefundableParachainId<(), TestParachain>, @@ -927,7 +908,7 @@ mod tests { ConstU64<1>, StrTestExtension, >; - type TestExtension = RefundTransactionExtensionAdapter; + type TestExtension = RefundSignedExtensionAdapter; fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { let test_stake: ThisChainBalance = TestStake::get(); @@ -1426,28 +1407,14 @@ mod tests { fn run_validate(call: RuntimeCall) -> TransactionValidity { let extension: TestExtension = - RefundTransactionExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension - .validate_only( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|res| res.0) + RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_grandpa_validate(call: RuntimeCall) -> TransactionValidity { let extension: TestGrandpaExtension = - RefundTransactionExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension - .validate_only( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|res| res.0) + RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_validate_ignore_priority(call: RuntimeCall) -> TransactionValidity { @@ -1461,30 +1428,16 @@ mod tests { call: RuntimeCall, ) -> Result>, TransactionValidityError> { let extension: TestExtension = - RefundTransactionExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension - .validate_and_prepare( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|(pre, _)| pre) + RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn run_grandpa_pre_dispatch( call: RuntimeCall, ) -> Result>, TransactionValidityError> { let extension: TestGrandpaExtension = - RefundTransactionExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension - .validate_and_prepare( - Some(relayer_account_at_this_chain()).into(), - &call, - &DispatchInfo::default(), - 0, - ) - .map(|(pre, _)| pre) + RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) } fn dispatch_info() -> DispatchInfo { @@ -1507,12 +1460,11 @@ mod tests { dispatch_result: DispatchResult, ) { let post_dispatch_result = TestExtension::post_dispatch( - pre_dispatch_data, + Some(pre_dispatch_data), &dispatch_info(), &post_dispatch_info(), 1024, &dispatch_result, - &(), ); assert_eq!(post_dispatch_result, Ok(())); } diff --git a/bridges/modules/grandpa/README.md b/bridges/modules/grandpa/README.md index 43ee5c316d1b..992bd2cc4722 100644 --- a/bridges/modules/grandpa/README.md +++ b/bridges/modules/grandpa/README.md @@ -27,7 +27,7 @@ for provided header. There are two main things in GRANDPA that help building light clients: - there's no need to import all headers of the bridged chain. Light client may import finalized headers or just - some of finalized headders that it consider useful. While the validators set stays the same, the client may + some of finalized headers that it consider useful. While the validators set stays the same, the client may import any header that is finalized by this set; - when validators set changes, the GRANDPA gadget adds next set to the header. So light client doesn't need to diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index e41e89341b31..4318d663a2e1 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -42,7 +42,7 @@ construct_runtime! { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; } diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs index af9212053985..ec63f15b94b5 100644 --- a/bridges/modules/messages/src/mock.rs +++ b/bridges/modules/messages/src/mock.rs @@ -77,14 +77,14 @@ frame_support::construct_runtime! { pub type DbWeight = RocksDbWeight; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; type AccountData = pallet_balances::AccountData; type DbWeight = DbWeight; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index 143f11d98637..3af3fd3e7639 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -161,7 +161,7 @@ construct_runtime! { } } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; } diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 667b10e5c125..3124787896c3 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -59,14 +59,14 @@ parameter_types! { pub const Lease: BlockNumber = 8; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; type AccountData = pallet_balances::AccountData; type DbWeight = DbWeight; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type ReserveIdentifier = [u8; 8]; type AccountStore = System; diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 6dbfba5f6fdc..54e10966d51b 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -64,7 +64,7 @@ parameter_types! { pub UnknownXcmVersionLocation: Location = Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(9999)]); } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index e40e1f9fb651..4c09bce56d73 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -64,7 +64,7 @@ parameter_types! { pub const ExistentialDeposit: Balance = 1; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type AccountId = AccountId; type AccountData = pallet_balances::AccountData; @@ -72,7 +72,7 @@ impl frame_system::Config for TestRuntime { type Lookup = IdentityLookup; } -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for TestRuntime { type AccountStore = System; } diff --git a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs index f186f6427ae7..c49aa4b85639 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-cumulus/src/lib.rs @@ -26,7 +26,7 @@ pub use bp_polkadot_core::{ }; use bp_messages::*; -use bp_polkadot_core::SuffixedCommonTransactionExtension; +use bp_polkadot_core::SuffixedCommonSignedExtension; use bp_runtime::extensions::{ BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, }; @@ -164,7 +164,7 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// Signed extension that is used by all bridge hubs. -pub type TransactionExtension = SuffixedCommonTransactionExtension<( +pub type SignedExtension = SuffixedCommonSignedExtension<( BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, )>; diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs index 992ef1bd7a10..c4e697fbe952 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -107,5 +107,5 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Rococo BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_complex_message_confirmation_transaction` + `33%`) - pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 5_380_904_835; + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 5_380_829_647; } diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index 253a1010e83d..e3b4d0520f61 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -59,8 +59,8 @@ impl ChainWithGrandpa for Kusama { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The TransactionExtension used by Kusama. -pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; +// The SignedExtension used by Kusama. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; /// Name of the parachains pallet in the Kusama runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs index 73dd122bd153..f2eebf931247 100644 --- a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs @@ -25,7 +25,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, extensions::{ CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, - CheckWeight, GenericTransactionExtension, GenericTransactionExtensionSchema, + CheckWeight, GenericSignedExtension, GenericSignedExtensionSchema, }, Chain, ChainId, TransactionEra, }; @@ -37,12 +37,7 @@ use frame_support::{ }; use frame_system::limits; use scale_info::TypeInfo; -use sp_runtime::{ - impl_tx_ext_default, - traits::{Dispatchable, TransactionExtensionBase}, - transaction_validity::TransactionValidityError, - Perbill, -}; +use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill}; // This chain reuses most of Polkadot primitives. pub use bp_polkadot_core::{ @@ -76,10 +71,10 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// This signed extension is used to ensure that the chain transactions are signed by proper -pub type ValidateSigned = GenericTransactionExtensionSchema<(), ()>; +pub type ValidateSigned = GenericSignedExtensionSchema<(), ()>; /// Signed extension schema, used by Polkadot Bulletin. -pub type TransactionExtensionSchema = GenericTransactionExtension<( +pub type SignedExtensionSchema = GenericSignedExtension<( ( CheckNonZeroSender, CheckSpecVersion, @@ -92,30 +87,34 @@ pub type TransactionExtensionSchema = GenericTransactionExtension<( ValidateSigned, )>; -/// Transaction extension, used by Polkadot Bulletin. +/// Signed extension, used by Polkadot Bulletin. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct TransactionExtension(TransactionExtensionSchema); +pub struct SignedExtension(SignedExtensionSchema); -impl TransactionExtensionBase for TransactionExtension { +impl sp_runtime::traits::SignedExtension for SignedExtension { const IDENTIFIER: &'static str = "Not needed."; - type Implicit = ::Implicit; + type AccountId = (); + type Call = (); + type AdditionalSigned = + ::AdditionalSigned; + type Pre = (); - fn implicit(&self) -> Result { - ::implicit(&self.0) + fn additional_signed(&self) -> Result { + self.0.additional_signed() } -} -impl sp_runtime::traits::TransactionExtension for TransactionExtension -where - C: Dispatchable, -{ - type Pre = (); - type Val = (); - - impl_tx_ext_default!(C; Context; validate prepare); + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } } -impl TransactionExtension { +impl SignedExtension { /// Create signed extension from its components. pub fn from_params( spec_version: u32, @@ -124,7 +123,7 @@ impl TransactionExtension { genesis_hash: Hash, nonce: Nonce, ) -> Self { - Self(GenericTransactionExtension::new( + Self(GenericSignedExtension::new( ( ( (), // non-zero sender diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index e5e2e7c3a042..fc5e10308a8e 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Polkadot { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -/// The TransactionExtension used by Polkadot. -pub type TransactionExtension = SuffixedCommonTransactionExtension; +/// The SignedExtension used by Polkadot. +pub type SignedExtension = SuffixedCommonSignedExtension; /// Name of the parachains pallet in the Polkadot runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs index 267c6b2b1f02..f1b256f0f090 100644 --- a/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -59,8 +59,8 @@ impl ChainWithGrandpa for Rococo { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The TransactionExtension used by Rococo. -pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; +// The SignedExtension used by Rococo. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index afa02e8ee541..f03fd2160a70 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -59,8 +59,8 @@ impl ChainWithGrandpa for Westend { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The TransactionExtension used by Westend. -pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; +// The SignedExtension used by Westend. +pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index dd3912429d66..4851ce14c0da 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", optional = true } scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } -serde = { default-features = false, features = ["derive"], optional = true, workspace = true } +serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Bridge Dependencies diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index d59b99db4b58..df2836495bbe 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -24,8 +24,8 @@ use bp_runtime::{ self, extensions::{ ChargeTransactionPayment, CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, - CheckSpecVersion, CheckTxVersion, CheckWeight, GenericTransactionExtension, - TransactionExtensionSchema, + CheckSpecVersion, CheckTxVersion, CheckWeight, GenericSignedExtension, + SignedExtensionSchema, }, EncodedOrDecodedCall, StorageMapKeyProvider, TransactionEra, }; @@ -229,12 +229,8 @@ pub type SignedBlock = generic::SignedBlock; pub type Balance = u128; /// Unchecked Extrinsic type. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic< - AccountAddress, - EncodedOrDecodedCall, - Signature, - TransactionExt, ->; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic, Signature, SignedExt>; /// Account address, used by the Polkadot-like chain. pub type Address = MultiAddress; @@ -279,7 +275,7 @@ impl AccountInfoStorageMapKeyProvider { } /// Extra signed extension data that is used by most chains. -pub type CommonTransactionExtra = ( +pub type CommonSignedExtra = ( CheckNonZeroSender, CheckSpecVersion, CheckTxVersion, @@ -290,12 +286,12 @@ pub type CommonTransactionExtra = ( ChargeTransactionPayment, ); -/// Extra transaction extension data that starts with `CommonTransactionExtra`. -pub type SuffixedCommonTransactionExtension = - GenericTransactionExtension<(CommonTransactionExtra, Suffix)>; +/// Extra signed extension data that starts with `CommonSignedExtra`. +pub type SuffixedCommonSignedExtension = + GenericSignedExtension<(CommonSignedExtra, Suffix)>; -/// Helper trait to define some extra methods on `SuffixedCommonTransactionExtension`. -pub trait SuffixedCommonTransactionExtensionExt { +/// Helper trait to define some extra methods on `SuffixedCommonSignedExtension`. +pub trait SuffixedCommonSignedExtensionExt { /// Create signed extension from its components. fn from_params( spec_version: u32, @@ -304,7 +300,7 @@ pub trait SuffixedCommonTransactionExtensionExt Self; /// Return transaction nonce. @@ -314,10 +310,9 @@ pub trait SuffixedCommonTransactionExtensionExt Balance; } -impl SuffixedCommonTransactionExtensionExt - for SuffixedCommonTransactionExtension +impl SuffixedCommonSignedExtensionExt for SuffixedCommonSignedExtension where - Suffix: TransactionExtensionSchema, + Suffix: SignedExtensionSchema, { fn from_params( spec_version: u32, @@ -326,9 +321,9 @@ where genesis_hash: Hash, nonce: Nonce, tip: Balance, - extra: (Suffix::Payload, Suffix::Implicit), + extra: (Suffix::Payload, Suffix::AdditionalSigned), ) -> Self { - GenericTransactionExtension::new( + GenericSignedExtension::new( ( ( (), // non-zero sender @@ -370,7 +365,7 @@ where } /// Signed extension that is used by most chains. -pub type CommonTransactionExtension = SuffixedCommonTransactionExtension<()>; +pub type CommonSignedExtension = SuffixedCommonSignedExtension<()>; #[cfg(test)] mod tests { diff --git a/bridges/primitives/runtime/src/extensions.rs b/bridges/primitives/runtime/src/extensions.rs index a31e7b5bb47a..d896bc92efff 100644 --- a/bridges/primitives/runtime/src/extensions.rs +++ b/bridges/primitives/runtime/src/extensions.rs @@ -20,138 +20,135 @@ use codec::{Compact, Decode, Encode}; use impl_trait_for_tuples::impl_for_tuples; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ - impl_tx_ext_default, - traits::{Dispatchable, TransactionExtension, TransactionExtensionBase}, + traits::{DispatchInfoOf, SignedExtension}, transaction_validity::TransactionValidityError, }; use sp_std::{fmt::Debug, marker::PhantomData}; -/// Trait that describes some properties of a `TransactionExtension` that are needed in order to -/// send a transaction to the chain. -pub trait TransactionExtensionSchema: - Encode + Decode + Debug + Eq + Clone + StaticTypeInfo -{ +/// Trait that describes some properties of a `SignedExtension` that are needed in order to send a +/// transaction to the chain. +pub trait SignedExtensionSchema: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo { /// A type of the data encoded as part of the transaction. type Payload: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; /// Parameters which are part of the payload used to produce transaction signature, /// but don't end up in the transaction itself (i.e. inherent part of the runtime). - type Implicit: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; + type AdditionalSigned: Encode + Debug + Eq + Clone + StaticTypeInfo; } -impl TransactionExtensionSchema for () { +impl SignedExtensionSchema for () { type Payload = (); - type Implicit = (); + type AdditionalSigned = (); } -/// An implementation of `TransactionExtensionSchema` using generic params. +/// An implementation of `SignedExtensionSchema` using generic params. #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)] -pub struct GenericTransactionExtensionSchema(PhantomData<(P, S)>); +pub struct GenericSignedExtensionSchema(PhantomData<(P, S)>); -impl TransactionExtensionSchema for GenericTransactionExtensionSchema +impl SignedExtensionSchema for GenericSignedExtensionSchema where P: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, - S: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, + S: Encode + Debug + Eq + Clone + StaticTypeInfo, { type Payload = P; - type Implicit = S; + type AdditionalSigned = S; } -/// The `TransactionExtensionSchema` for `frame_system::CheckNonZeroSender`. -pub type CheckNonZeroSender = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `frame_system::CheckNonZeroSender`. +pub type CheckNonZeroSender = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `frame_system::CheckSpecVersion`. -pub type CheckSpecVersion = GenericTransactionExtensionSchema<(), u32>; +/// The `SignedExtensionSchema` for `frame_system::CheckSpecVersion`. +pub type CheckSpecVersion = GenericSignedExtensionSchema<(), u32>; -/// The `TransactionExtensionSchema` for `frame_system::CheckTxVersion`. -pub type CheckTxVersion = GenericTransactionExtensionSchema<(), u32>; +/// The `SignedExtensionSchema` for `frame_system::CheckTxVersion`. +pub type CheckTxVersion = GenericSignedExtensionSchema<(), u32>; -/// The `TransactionExtensionSchema` for `frame_system::CheckGenesis`. -pub type CheckGenesis = GenericTransactionExtensionSchema<(), Hash>; +/// The `SignedExtensionSchema` for `frame_system::CheckGenesis`. +pub type CheckGenesis = GenericSignedExtensionSchema<(), Hash>; -/// The `TransactionExtensionSchema` for `frame_system::CheckEra`. -pub type CheckEra = GenericTransactionExtensionSchema; +/// The `SignedExtensionSchema` for `frame_system::CheckEra`. +pub type CheckEra = GenericSignedExtensionSchema; -/// The `TransactionExtensionSchema` for `frame_system::CheckNonce`. -pub type CheckNonce = GenericTransactionExtensionSchema, ()>; +/// The `SignedExtensionSchema` for `frame_system::CheckNonce`. +pub type CheckNonce = GenericSignedExtensionSchema, ()>; -/// The `TransactionExtensionSchema` for `frame_system::CheckWeight`. -pub type CheckWeight = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `frame_system::CheckWeight`. +pub type CheckWeight = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. -pub type ChargeTransactionPayment = - GenericTransactionExtensionSchema, ()>; +/// The `SignedExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. +pub type ChargeTransactionPayment = GenericSignedExtensionSchema, ()>; -/// The `TransactionExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. -pub type PrevalidateAttests = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. +pub type PrevalidateAttests = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. -pub type BridgeRejectObsoleteHeadersAndMessages = GenericTransactionExtensionSchema<(), ()>; +/// The `SignedExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. +pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<(), ()>; -/// The `TransactionExtensionSchema` for `RefundBridgedParachainMessages`. +/// The `SignedExtensionSchema` for `RefundBridgedParachainMessages`. /// This schema is dedicated for `RefundBridgedParachainMessages` signed extension as /// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (), /// ())` is the same. So runtime can contains any kind of tuple: /// `(BridgeRefundBridgeHubRococoMessages)` /// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWestendMessages)` /// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)` -pub type RefundBridgedParachainMessagesSchema = GenericTransactionExtensionSchema<(), ()>; +pub type RefundBridgedParachainMessagesSchema = GenericSignedExtensionSchema<(), ()>; #[impl_for_tuples(1, 12)] -impl TransactionExtensionSchema for Tuple { +impl SignedExtensionSchema for Tuple { for_tuples!( type Payload = ( #( Tuple::Payload ),* ); ); - for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); ); + for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); } /// A simplified version of signed extensions meant for producing signed transactions /// and signed payloads in the client code. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct GenericTransactionExtension { +pub struct GenericSignedExtension { /// A payload that is included in the transaction. pub payload: S::Payload, #[codec(skip)] // It may be set to `None` if extensions are decoded. We are never reconstructing transactions - // (and it makes no sense to do that) => decoded version of `TransactionExtensions` is only - // used to read fields of the `payload`. And when resigning transaction, we're reconstructing - // `TransactionExtensions` from scratch. - implicit: Option, + // (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to + // read fields of the `payload`. And when resigning transaction, we're reconstructing + // `SignedExtensions` from scratch. + additional_signed: Option, } -impl GenericTransactionExtension { - /// Create new `GenericTransactionExtension` object. - pub fn new(payload: S::Payload, implicit: Option) -> Self { - Self { payload, implicit } +impl GenericSignedExtension { + /// Create new `GenericSignedExtension` object. + pub fn new(payload: S::Payload, additional_signed: Option) -> Self { + Self { payload, additional_signed } } } -impl TransactionExtensionBase for GenericTransactionExtension +impl SignedExtension for GenericSignedExtension where - S: TransactionExtensionSchema, + S: SignedExtensionSchema, S::Payload: Send + Sync, - S::Implicit: Send + Sync, + S::AdditionalSigned: Send + Sync, { const IDENTIFIER: &'static str = "Not needed."; - type Implicit = S::Implicit; + type AccountId = (); + type Call = (); + type AdditionalSigned = S::AdditionalSigned; + type Pre = (); - fn implicit(&self) -> Result { + fn additional_signed(&self) -> Result { // we shall not ever see this error in relay, because we are never signing decoded // transactions. Instead we're constructing and signing new transactions. So the error code // is kinda random here - self.implicit - .clone() - .ok_or(frame_support::unsigned::TransactionValidityError::Unknown( + self.additional_signed.clone().ok_or( + frame_support::unsigned::TransactionValidityError::Unknown( frame_support::unsigned::UnknownTransaction::Custom(0xFF), - )) + ), + ) } -} -impl TransactionExtension for GenericTransactionExtension -where - C: Dispatchable, - S: TransactionExtensionSchema, - S::Payload: Send + Sync, - S::Implicit: Send + Sync, -{ - type Pre = (); - type Val = (); - impl_tx_ext_default!(C; Context; validate prepare); + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } } diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml index d5873752e22f..2b89ce4f1989 100644 --- a/bridges/relays/bin-substrate/Cargo.toml +++ b/bridges/relays/bin-substrate/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] anyhow = "1.0" async-std = "1.9.0" -async-trait = "0.1" +async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.1.5" } env_logger = "0.11" futures = "0.3.30" diff --git a/bridges/relays/client-bridge-hub-kusama/src/lib.rs b/bridges/relays/client-bridge-hub-kusama/src/lib.rs index 80f621dee302..43dd53d2d83a 100644 --- a/bridges/relays/client-bridge-hub-kusama/src/lib.rs +++ b/bridges/relays/client-bridge-hub-kusama/src/lib.rs @@ -18,8 +18,8 @@ pub mod codegen_runtime; -use bp_bridge_hub_kusama::{TransactionExtension, AVERAGE_BLOCK_INTERVAL}; -use bp_polkadot::SuffixedCommonTransactionExtensionExt; +use bp_bridge_hub_kusama::{SignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_polkadot::SuffixedCommonSignedExtensionExt; use codec::Encode; use relay_substrate_client::{ calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, @@ -37,8 +37,7 @@ pub type RuntimeCall = runtime_types::bridge_hub_kusama_runtime::RuntimeCall; pub type BridgeMessagesCall = runtime_types::pallet_bridge_messages::pallet::Call; pub type BridgeGrandpaCall = runtime_types::pallet_bridge_grandpa::pallet::Call; pub type BridgeParachainCall = runtime_types::pallet_bridge_parachains::pallet::Call; -type UncheckedExtrinsic = - bp_bridge_hub_kusama::UncheckedExtrinsic; +type UncheckedExtrinsic = bp_bridge_hub_kusama::UncheckedExtrinsic; type UtilityCall = runtime_types::pallet_utility::pallet::Call; /// Kusama chain definition @@ -88,7 +87,7 @@ impl ChainWithTransactions for BridgeHubKusama { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - TransactionExtension::from_params( + SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-bridge-hub-polkadot/src/lib.rs b/bridges/relays/client-bridge-hub-polkadot/src/lib.rs index ed147e92d5bd..88b69065f842 100644 --- a/bridges/relays/client-bridge-hub-polkadot/src/lib.rs +++ b/bridges/relays/client-bridge-hub-polkadot/src/lib.rs @@ -18,8 +18,8 @@ pub mod codegen_runtime; -use bp_bridge_hub_polkadot::{TransactionExtension, AVERAGE_BLOCK_INTERVAL}; -use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; +use bp_bridge_hub_polkadot::{SignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_polkadot_core::SuffixedCommonSignedExtensionExt; use codec::Encode; use relay_substrate_client::{ calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, @@ -41,8 +41,7 @@ pub type BridgeKusamaMessagesCall = runtime_types::pallet_bridge_messages::palle pub type BridgePolkadotBulletinGrandpaCall = runtime_types::pallet_bridge_grandpa::pallet::Call; pub type BridgeKusamaGrandpaCall = runtime_types::pallet_bridge_grandpa::pallet::Call; pub type BridgeParachainCall = runtime_types::pallet_bridge_parachains::pallet::Call; -type UncheckedExtrinsic = - bp_bridge_hub_polkadot::UncheckedExtrinsic; +type UncheckedExtrinsic = bp_bridge_hub_polkadot::UncheckedExtrinsic; type UtilityCall = runtime_types::pallet_utility::pallet::Call; /// Polkadot chain definition @@ -92,7 +91,7 @@ impl ChainWithTransactions for BridgeHubPolkadot { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - TransactionExtension::from_params( + SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-bridge-hub-rococo/src/lib.rs b/bridges/relays/client-bridge-hub-rococo/src/lib.rs index 169135646d94..cae9e4f77a50 100644 --- a/bridges/relays/client-bridge-hub-rococo/src/lib.rs +++ b/bridges/relays/client-bridge-hub-rococo/src/lib.rs @@ -18,8 +18,8 @@ pub mod codegen_runtime; -use bp_bridge_hub_rococo::{TransactionExtension, AVERAGE_BLOCK_INTERVAL}; -use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; +use bp_bridge_hub_rococo::{SignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_polkadot_core::SuffixedCommonSignedExtensionExt; use codec::Encode; use relay_substrate_client::{ calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, @@ -39,8 +39,7 @@ pub type BridgeBulletinMessagesCall = runtime_types::pallet_bridge_messages::pal pub type BridgeGrandpaCall = runtime_types::pallet_bridge_grandpa::pallet::Call; pub type BridgeBulletinGrandpaCall = runtime_types::pallet_bridge_grandpa::pallet::Call2; pub type BridgeParachainCall = runtime_types::pallet_bridge_parachains::pallet::Call; -type UncheckedExtrinsic = - bp_bridge_hub_rococo::UncheckedExtrinsic; +type UncheckedExtrinsic = bp_bridge_hub_rococo::UncheckedExtrinsic; type UtilityCall = runtime_types::pallet_utility::pallet::Call; /// Rococo chain definition @@ -90,7 +89,7 @@ impl ChainWithTransactions for BridgeHubRococo { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - TransactionExtension::from_params( + SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-bridge-hub-westend/src/lib.rs b/bridges/relays/client-bridge-hub-westend/src/lib.rs index 5e4462f863aa..049fa4649609 100644 --- a/bridges/relays/client-bridge-hub-westend/src/lib.rs +++ b/bridges/relays/client-bridge-hub-westend/src/lib.rs @@ -18,8 +18,8 @@ pub mod codegen_runtime; -use bp_bridge_hub_westend::{TransactionExtension, AVERAGE_BLOCK_INTERVAL}; -use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; +use bp_bridge_hub_westend::{SignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_polkadot_core::SuffixedCommonSignedExtensionExt; use codec::Encode; use relay_substrate_client::{ calls::UtilityCall as MockUtilityCall, Chain, ChainWithBalances, ChainWithMessages, @@ -37,8 +37,7 @@ pub type RuntimeCall = runtime_types::bridge_hub_westend_runtime::RuntimeCall; pub type BridgeMessagesCall = runtime_types::pallet_bridge_messages::pallet::Call; pub type BridgeGrandpaCall = runtime_types::pallet_bridge_grandpa::pallet::Call; pub type BridgeParachainCall = runtime_types::pallet_bridge_parachains::pallet::Call; -type UncheckedExtrinsic = - bp_bridge_hub_westend::UncheckedExtrinsic; +type UncheckedExtrinsic = bp_bridge_hub_westend::UncheckedExtrinsic; type UtilityCall = runtime_types::pallet_utility::pallet::Call; /// Westend chain definition @@ -88,7 +87,7 @@ impl ChainWithTransactions for BridgeHubWestend { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - TransactionExtension::from_params( + SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-kusama/src/lib.rs b/bridges/relays/client-kusama/src/lib.rs index a953a383e129..24a6adfe95d4 100644 --- a/bridges/relays/client-kusama/src/lib.rs +++ b/bridges/relays/client-kusama/src/lib.rs @@ -19,7 +19,7 @@ pub mod codegen_runtime; use bp_kusama::{AccountInfoStorageMapKeyProvider, KUSAMA_SYNCED_HEADERS_GRANDPA_INFO_METHOD}; -use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; +use bp_polkadot_core::SuffixedCommonSignedExtensionExt; use codec::Encode; use relay_substrate_client::{ Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions, @@ -84,7 +84,7 @@ impl RelayChain for Kusama { impl ChainWithTransactions for Kusama { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = - bp_polkadot_core::UncheckedExtrinsic; + bp_polkadot_core::UncheckedExtrinsic; fn sign_transaction( param: SignParam, @@ -92,7 +92,7 @@ impl ChainWithTransactions for Kusama { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_kusama::TransactionExtension::from_params( + bp_kusama::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-polkadot-bulletin/src/lib.rs b/bridges/relays/client-polkadot-bulletin/src/lib.rs index a6cdd8ee675c..1f18b25a9054 100644 --- a/bridges/relays/client-polkadot-bulletin/src/lib.rs +++ b/bridges/relays/client-polkadot-bulletin/src/lib.rs @@ -100,10 +100,8 @@ impl ChainWithBalances for PolkadotBulletin { impl ChainWithTransactions for PolkadotBulletin { type AccountKeyPair = sp_core::sr25519::Pair; - type SignedTransaction = bp_polkadot_bulletin::UncheckedExtrinsic< - Self::Call, - bp_polkadot_bulletin::TransactionExtension, - >; + type SignedTransaction = + bp_polkadot_bulletin::UncheckedExtrinsic; fn sign_transaction( param: SignParam, @@ -111,7 +109,7 @@ impl ChainWithTransactions for PolkadotBulletin { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_polkadot_bulletin::TransactionExtension::from_params( + bp_polkadot_bulletin::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-polkadot/src/lib.rs b/bridges/relays/client-polkadot/src/lib.rs index af75f0dbb871..9b655528b6e4 100644 --- a/bridges/relays/client-polkadot/src/lib.rs +++ b/bridges/relays/client-polkadot/src/lib.rs @@ -19,7 +19,7 @@ mod codegen_runtime; use bp_polkadot::{AccountInfoStorageMapKeyProvider, POLKADOT_SYNCED_HEADERS_GRANDPA_INFO_METHOD}; -use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; +use bp_polkadot_core::SuffixedCommonSignedExtensionExt; use codec::Encode; use relay_substrate_client::{ Chain, ChainWithBalances, ChainWithGrandpa, ChainWithRuntimeVersion, ChainWithTransactions, @@ -84,7 +84,7 @@ impl RelayChain for Polkadot { impl ChainWithTransactions for Polkadot { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = - bp_polkadot_core::UncheckedExtrinsic; + bp_polkadot_core::UncheckedExtrinsic; fn sign_transaction( param: SignParam, @@ -92,7 +92,7 @@ impl ChainWithTransactions for Polkadot { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_polkadot::TransactionExtension::from_params( + bp_polkadot::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-rococo/src/lib.rs b/bridges/relays/client-rococo/src/lib.rs index 5fad80d5c988..575660504b3a 100644 --- a/bridges/relays/client-rococo/src/lib.rs +++ b/bridges/relays/client-rococo/src/lib.rs @@ -18,7 +18,7 @@ pub mod codegen_runtime; -use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; +use bp_polkadot_core::SuffixedCommonSignedExtensionExt; use bp_rococo::ROCOCO_SYNCED_HEADERS_GRANDPA_INFO_METHOD; use codec::Encode; use relay_substrate_client::{ @@ -84,7 +84,7 @@ impl RelayChain for Rococo { impl ChainWithTransactions for Rococo { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = - bp_polkadot_core::UncheckedExtrinsic; + bp_polkadot_core::UncheckedExtrinsic; fn sign_transaction( param: SignParam, @@ -92,7 +92,7 @@ impl ChainWithTransactions for Rococo { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_rococo::TransactionExtension::from_params( + bp_rococo::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/client-substrate/Cargo.toml b/bridges/relays/client-substrate/Cargo.toml index ea02a0ad2015..48895eff39da 100644 --- a/bridges/relays/client-substrate/Cargo.toml +++ b/bridges/relays/client-substrate/Cargo.toml @@ -10,7 +10,7 @@ workspace = true [dependencies] async-std = { version = "1.6.5", features = ["attributes"] } -async-trait = "0.1" +async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.1.5" } futures = "0.3.30" jsonrpsee = { version = "0.17", features = ["macros", "ws-client"] } diff --git a/bridges/relays/client-westend/src/lib.rs b/bridges/relays/client-westend/src/lib.rs index 737c6c08519e..42206baecf8f 100644 --- a/bridges/relays/client-westend/src/lib.rs +++ b/bridges/relays/client-westend/src/lib.rs @@ -18,7 +18,7 @@ pub mod codegen_runtime; -use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; +use bp_polkadot_core::SuffixedCommonSignedExtensionExt; use bp_westend::WESTEND_SYNCED_HEADERS_GRANDPA_INFO_METHOD; use codec::Encode; use relay_substrate_client::{ @@ -84,7 +84,7 @@ impl ChainWithBalances for Westend { impl ChainWithTransactions for Westend { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = - bp_polkadot_core::UncheckedExtrinsic; + bp_polkadot_core::UncheckedExtrinsic; fn sign_transaction( param: SignParam, @@ -92,7 +92,7 @@ impl ChainWithTransactions for Westend { ) -> Result { let raw_payload = SignedPayload::new( unsigned.call, - bp_westend::TransactionExtension::from_params( + bp_westend::SignedExtension::from_params( param.spec_version, param.transaction_version, unsigned.era, diff --git a/bridges/relays/equivocation/Cargo.toml b/bridges/relays/equivocation/Cargo.toml index 0b4a7e983a3a..23dd4a087f97 100644 --- a/bridges/relays/equivocation/Cargo.toml +++ b/bridges/relays/equivocation/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] async-std = { version = "1.6.5", features = ["attributes"] } -async-trait = "0.1" +async-trait = "0.1.74" bp-header-chain = { path = "../../primitives/header-chain" } finality-relay = { path = "../finality" } frame-support = { git = "https://github.com/paritytech/polkadot-sdk", branch = "master" } diff --git a/bridges/relays/finality/Cargo.toml b/bridges/relays/finality/Cargo.toml index 9e8bf56f53aa..80159b4db62a 100644 --- a/bridges/relays/finality/Cargo.toml +++ b/bridges/relays/finality/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] async-std = "1.6.5" -async-trait = "0.1" +async-trait = "0.1.74" backoff = "0.4" bp-header-chain = { path = "../../primitives/header-chain" } futures = "0.3.30" diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml index d85e2762a4e3..27c5ee02c759 100644 --- a/bridges/relays/lib-substrate-relay/Cargo.toml +++ b/bridges/relays/lib-substrate-relay/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] anyhow = "1.0" async-std = "1.9.0" -async-trait = "0.1" +async-trait = "0.1.74" codec = { package = "parity-scale-codec", version = "3.1.5" } futures = "0.3.30" hex = "0.4" diff --git a/bridges/relays/messages/Cargo.toml b/bridges/relays/messages/Cargo.toml index 3367e4bbd443..699649dd619d 100644 --- a/bridges/relays/messages/Cargo.toml +++ b/bridges/relays/messages/Cargo.toml @@ -10,7 +10,7 @@ workspace = true [dependencies] async-std = { version = "1.6.5", features = ["attributes"] } -async-trait = "0.1" +async-trait = "0.1.74" env_logger = "0.11" futures = "0.3.30" hex = "0.4" diff --git a/bridges/relays/parachains/Cargo.toml b/bridges/relays/parachains/Cargo.toml index 9dc35343b48c..d2eea9eb6a77 100644 --- a/bridges/relays/parachains/Cargo.toml +++ b/bridges/relays/parachains/Cargo.toml @@ -10,7 +10,7 @@ workspace = true [dependencies] async-std = "1.6.5" -async-trait = "0.1" +async-trait = "0.1.74" futures = "0.3.30" log = { workspace = true } relay-utils = { path = "../utils" } diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml index ed6093318a0d..81574a685514 100644 --- a/bridges/relays/utils/Cargo.toml +++ b/bridges/relays/utils/Cargo.toml @@ -12,7 +12,7 @@ workspace = true ansi_term = "0.12" anyhow = "1.0" async-std = "1.6.5" -async-trait = "0.1" +async-trait = "0.1.74" backoff = "0.4" isahc = "1.2" env_logger = "0.11.3" diff --git a/bridges/testing/README.md b/bridges/testing/README.md new file mode 100644 index 000000000000..bd467a410d01 --- /dev/null +++ b/bridges/testing/README.md @@ -0,0 +1,31 @@ +# Bridges Tests for Local Rococo <> Westend Bridge + +This folder contains [zombienet](https://github.com/paritytech/zombienet/) based integration tests for both +onchain and offchain bridges code. Due to some +[technical difficulties](https://github.com/paritytech/parity-bridges-common/pull/2649#issue-1965339051), we +are using native zombienet provider, which means that you need to build some binaries locally. + +To start those tests, you need to: + +- download latest [zombienet release](https://github.com/paritytech/zombienet/releases); + +- build Polkadot binary by running `cargo build -p polkadot --release --features fast-runtime` command in the +[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; + +- build Polkadot Parachain binary by running `cargo build -p polkadot-parachain-bin --release` command in the +[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; + +- ensure that you have [`node`](https://nodejs.org/en) installed. Additionally, we'll need globally installed +`polkadot/api-cli` package (use `npm install -g @polkadot/api-cli@beta` to install it); + +- build Substrate relay by running `cargo build -p substrate-relay --release` command in the +[`parity-bridges-common`](https://github.com/paritytech/parity-bridges-common) repository clone. + +- copy fresh `substrate-relay` binary, built in previous point, to the `~/local_bridge_testing/bin/substrate-relay`; + +- change the `POLKADOT_SDK_PATH` and `ZOMBIENET_BINARY_PATH` (and ensure that the nearby variables +have correct values) in the `./run-tests.sh`. + +After that, you could run tests with the `./run-tests.sh` command. Hopefully, it'll show the +"All tests have completed successfully" message in the end. Otherwise, it'll print paths to zombienet +process logs, which, in turn, may be used to track locations of all spinned relay and parachain nodes. diff --git a/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml b/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml new file mode 100644 index 000000000000..52271f944213 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/bridge_hub_rococo_local_network.toml @@ -0,0 +1,88 @@ +[settings] +node_spawn_timeout = 240 + +[relaychain] +default_command = "{{POLKADOT_BINARY}}" +default_args = [ "-lparachain=debug,xcm=trace" ] +chain = "rococo-local" + + [[relaychain.nodes]] + name = "alice-rococo-validator" + validator = true + rpc_port = 9932 + ws_port = 9942 + balance = 2000000000000 + + [[relaychain.nodes]] + name = "bob-rococo-validator" + validator = true + rpc_port = 9933 + ws_port = 9943 + balance = 2000000000000 + + [[relaychain.nodes]] + name = "charlie-rococo-validator" + validator = true + rpc_port = 9934 + ws_port = 9944 + balance = 2000000000000 + +[[parachains]] +id = 1013 +chain = "bridge-hub-rococo-local" +cumulus_based = true + + # run alice as parachain collator + [[parachains.collators]] + name = "bridge-hub-rococo-collator1" + validator = true + command = "{{POLKADOT_PARACHAIN_BINARY}}" + rpc_port = 8933 + ws_port = 8943 + args = [ + "-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" + ] + + # run bob as parachain collator + [[parachains.collators]] + name = "bridge-hub-rococo-collator2" + validator = true + command = "{{POLKADOT_PARACHAIN_BINARY}}" + rpc_port = 8934 + ws_port = 8944 + args = [ + "-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" + ] + +[[parachains]] +id = 1000 +chain = "asset-hub-rococo-local" +cumulus_based = true + + [[parachains.collators]] + name = "asset-hub-rococo-collator1" + rpc_port = 9911 + ws_port = 9910 + command = "{{POLKADOT_PARACHAIN_BINARY}}" + args = [ + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + ] + + [[parachains.collators]] + name = "asset-hub-rococo-collator2" + command = "{{POLKADOT_PARACHAIN_BINARY}}" + args = [ + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + ] + +#[[hrmp_channels]] +#sender = 1000 +#recipient = 1013 +#max_capacity = 4 +#max_message_size = 524288 +# +#[[hrmp_channels]] +#sender = 1013 +#recipient = 1000 +#max_capacity = 4 +#max_message_size = 524288 diff --git a/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml b/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml new file mode 100644 index 000000000000..f2550bcc9959 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/bridge_hub_westend_local_network.toml @@ -0,0 +1,88 @@ +[settings] +node_spawn_timeout = 240 + +[relaychain] +default_command = "{{POLKADOT_BINARY}}" +default_args = [ "-lparachain=debug,xcm=trace" ] +chain = "westend-local" + + [[relaychain.nodes]] + name = "alice-westend-validator" + validator = true + rpc_port = 9935 + ws_port = 9945 + balance = 2000000000000 + + [[relaychain.nodes]] + name = "bob-westend-validator" + validator = true + rpc_port = 9936 + ws_port = 9946 + balance = 2000000000000 + + [[relaychain.nodes]] + name = "charlie-westend-validator" + validator = true + rpc_port = 9937 + ws_port = 9947 + balance = 2000000000000 + +[[parachains]] +id = 1002 +chain = "bridge-hub-westend-local" +cumulus_based = true + + # run alice as parachain collator + [[parachains.collators]] + name = "bridge-hub-westend-collator1" + validator = true + command = "{{POLKADOT_PARACHAIN_BINARY}}" + rpc_port = 8935 + ws_port = 8945 + args = [ + "-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" + ] + + # run bob as parachain collator + [[parachains.collators]] + name = "bridge-hub-westend-collator2" + validator = true + command = "{{POLKADOT_PARACHAIN_BINARY}}" + rpc_port = 8936 + ws_port = 8946 + args = [ + "-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm=trace" + ] + +[[parachains]] +id = 1000 +chain = "asset-hub-westend-local" +cumulus_based = true + + [[parachains.collators]] + name = "asset-hub-westend-collator1" + rpc_port = 9011 + ws_port = 9010 + command = "{{POLKADOT_PARACHAIN_BINARY}}" + args = [ + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + ] + + [[parachains.collators]] + name = "asset-hub-westend-collator2" + command = "{{POLKADOT_PARACHAIN_BINARY}}" + args = [ + "-lparachain=debug,xcm=trace,runtime::bridge-transfer=trace" + ] + +#[[hrmp_channels]] +#sender = 1000 +#recipient = 1002 +#max_capacity = 4 +#max_message_size = 524288 +# +#[[hrmp_channels]] +#sender = 1002 +#recipient = 1000 +#max_capacity = 4 +#max_message_size = 524288 diff --git a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh new file mode 100755 index 000000000000..66c9ddc037b8 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh @@ -0,0 +1,401 @@ +#!/bin/bash + +# import common functions +source "$FRAMEWORK_PATH/utils/bridges.sh" + +# Expected sovereign accounts. +# +# Generated by: +# +# #[test] +# fn generate_sovereign_accounts() { +# use sp_core::crypto::Ss58Codec; +# use polkadot_parachain_primitives::primitives::Sibling; +# +# parameter_types! { +# pub UniversalLocationAHR: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(1000)); +# pub UniversalLocationAHW: InteriorMultiLocation = X2(GlobalConsensus(Westend), Parachain(1000)); +# } +# +# // SS58=42 +# println!("GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Rococo)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# SiblingParachainConvertsVia::::convert_location( +# &MultiLocation { parents: 1, interior: X1(Parachain(1000)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# +# // SS58=42 +# println!("GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# GlobalConsensusConvertsFor::::convert_location( +# &MultiLocation { parents: 2, interior: X1(GlobalConsensus(Westend)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# println!("ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# SiblingParachainConvertsVia::::convert_location( +# &MultiLocation { parents: 1, interior: X1(Parachain(1000)) }).unwrap() +# ).to_ss58check_with_version(42_u16.into()) +# ); +# } +GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT="5GxRGwT8bU1JeBPTUXc7LEjZMxNrK8MyL2NJnkWFQJTQ4sii" +ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" +GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT="5He2Qdztyxxa4GoagY6q1jaiLMmKy1gXS7PdZkhfj8ZG9hk5" +ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO="5Eg2fntNprdN3FgH4sfEaaZhYtddZQSQUqvYJ1f2mLtinVhV" + +# Expected sovereign accounts for rewards on BridgeHubs. +# +# Generated by: +# #[test] +# fn generate_sovereign_accounts_for_rewards() { +# use bp_messages::LaneId; +# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; +# use sp_core::crypto::Ss58Codec; +# +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( +# LaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# } +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain="5EHnXaT5BhiSGP5hbdsoVGtzi2sQVgpDNToTxLYeQvKoMPEm" +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain="5EHnXaT5BhiSGP5hbdt5EJSapXYbxEv678jyWHEUskCXcjqo" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXaT5BhiSGP5h9Rg8sgUJqoLym3iEaWUiboT8S9AT5xFh" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5BhiSGP5h9RgQci1txJ2BDbp7KBRE9k8xty3BMUSi" + +LANE_ID="00000002" +XCM_VERSION=3 + +function init_ro_wnd() { + local relayer_path=$(ensure_relayer) + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path init-bridge rococo-to-bridge-hub-westend \ + --source-host localhost \ + --source-port 9942 \ + --source-version-mode Auto \ + --target-host localhost \ + --target-port 8945 \ + --target-version-mode Auto \ + --target-signer //Bob +} + +function init_wnd_ro() { + local relayer_path=$(ensure_relayer) + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path init-bridge westend-to-bridge-hub-rococo \ + --source-host localhost \ + --source-port 9945 \ + --source-version-mode Auto \ + --target-host localhost \ + --target-port 8943 \ + --target-version-mode Auto \ + --target-signer //Bob +} + +function run_relay() { + local relayer_path=$(ensure_relayer) + + RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ + $relayer_path relay-headers-and-messages bridge-hub-rococo-bridge-hub-westend \ + --rococo-host localhost \ + --rococo-port 9942 \ + --rococo-version-mode Auto \ + --bridge-hub-rococo-host localhost \ + --bridge-hub-rococo-port 8943 \ + --bridge-hub-rococo-version-mode Auto \ + --bridge-hub-rococo-signer //Charlie \ + --bridge-hub-rococo-transactions-mortality 4 \ + --westend-host localhost \ + --westend-port 9945 \ + --westend-version-mode Auto \ + --bridge-hub-westend-host localhost \ + --bridge-hub-westend-port 8945 \ + --bridge-hub-westend-version-mode Auto \ + --bridge-hub-westend-signer //Charlie \ + --bridge-hub-westend-transactions-mortality 4 \ + --lane "${LANE_ID}" +} + +case "$1" in + run-relay) + init_wnd_ro + init_ro_wnd + run_relay + ;; + init-asset-hub-rococo-local) + ensure_polkadot_js_api + # create foreign assets for native Westend token (governance call on Rococo) + force_create_foreign_asset \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9910" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } }')" \ + "$GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT" \ + 10000000000 \ + true + # HRMP + open_hrmp_channels \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1000 1013 4 524288 + open_hrmp_channels \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1013 1000 4 524288 + # set XCM version of remote AssetHubWestend + force_xcm_version \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9910" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } }')" \ + $XCM_VERSION + ;; + init-bridge-hub-rococo-local) + ensure_polkadot_js_api + # SA of sibling asset hub pays for the execution + transfer_balance \ + "ws://127.0.0.1:8943" \ + "//Alice" \ + "$ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO" \ + $((1000000000000 + 50000000000 * 20)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery + transfer_balance \ + "ws://127.0.0.1:8943" \ + "//Alice" \ + "$ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain" \ + $((1000000000000 + 2000000000000)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery confirmation + transfer_balance \ + "ws://127.0.0.1:8943" \ + "//Alice" \ + "$ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain" \ + $((1000000000000 + 2000000000000)) + # set XCM version of remote BridgeHubWestend + force_xcm_version \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1013 \ + "ws://127.0.0.1:8943" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1002 } ] } }')" \ + $XCM_VERSION + ;; + init-asset-hub-westend-local) + ensure_polkadot_js_api + # create foreign assets for native Rococo token (governance call on Westend) + force_create_foreign_asset \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9010" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } }')" \ + "$GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT" \ + 10000000000 \ + true + # HRMP + open_hrmp_channels \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 1002 4 524288 + open_hrmp_channels \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1002 1000 4 524288 + # set XCM version of remote AssetHubRococo + force_xcm_version \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9010" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } }')" \ + $XCM_VERSION + ;; + init-bridge-hub-westend-local) + # SA of sibling asset hub pays for the execution + transfer_balance \ + "ws://127.0.0.1:8945" \ + "//Alice" \ + "$ASSET_HUB_WESTEND_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_WESTEND" \ + $((1000000000000000 + 50000000000 * 20)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery + transfer_balance \ + "ws://127.0.0.1:8945" \ + "//Alice" \ + "$ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain" \ + $((1000000000000000 + 2000000000000)) + # drip SA of lane dedicated to asset hub for paying rewards for delivery confirmation + transfer_balance \ + "ws://127.0.0.1:8945" \ + "//Alice" \ + "$ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain" \ + $((1000000000000000 + 2000000000000)) + # set XCM version of remote BridgeHubRococo + force_xcm_version \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1002 \ + "ws://127.0.0.1:8945" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1013 } ] } }')" \ + $XCM_VERSION + ;; + reserve-transfer-assets-from-asset-hub-rococo-local) + amount=$2 + ensure_polkadot_js_api + # send ROCs to Alice account on AHW + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9910" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ + 0 \ + "Unlimited" + ;; + withdraw-reserve-assets-from-asset-hub-rococo-local) + amount=$2 + ensure_polkadot_js_api + # send back only 100000000000 wrappedWNDs to Alice account on AHW + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9910" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ + 0 \ + "Unlimited" + ;; + reserve-transfer-assets-from-asset-hub-westend-local) + amount=$2 + ensure_polkadot_js_api + # send WNDs to Alice account on AHR + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9010" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 1, "interior": "Here" } }, "fun": { "Fungible": '$amount' } } ] }')" \ + 0 \ + "Unlimited" + ;; + withdraw-reserve-assets-from-asset-hub-westend-local) + amount=$2 + ensure_polkadot_js_api + # send back only 100000000000 wrappedROCs to Alice account on AHR + limited_reserve_transfer_assets \ + "ws://127.0.0.1:9010" \ + "//Alice" \ + "$(jq --null-input '{ "V3": { "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } } }')" \ + "$(jq --null-input '{ "V3": { "parents": 0, "interior": { "X1": { "AccountId32": { "id": [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] } } } } }')" \ + "$(jq --null-input '{ "V3": [ { "id": { "Concrete": { "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } } }, "fun": { "Fungible": '$amount' } } ] }')" \ + 0 \ + "Unlimited" + ;; + claim-rewards-bridge-hub-rococo-local) + ensure_polkadot_js_api + # bhwd -> [62, 68, 77, 64] -> 0x62687764 + claim_rewards \ + "ws://127.0.0.1:8943" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x62687764" \ + "ThisChain" + claim_rewards \ + "ws://127.0.0.1:8943" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x62687764" \ + "BridgedChain" + ;; + claim-rewards-bridge-hub-westend-local) + # bhro -> [62, 68, 72, 6f] -> 0x6268726f + claim_rewards \ + "ws://127.0.0.1:8945" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x6268726f" \ + "ThisChain" + claim_rewards \ + "ws://127.0.0.1:8945" \ + "//Charlie" \ + "0x${LANE_ID}" \ + "0x6268726f" \ + "BridgedChain" + ;; + stop) + pkill -f polkadot + pkill -f parachain + ;; + import) + # to avoid trigger anything here + ;; + *) + echo "A command is require. Supported commands for: + Local (zombienet) run: + - run-relay + - init-asset-hub-rococo-local + - init-bridge-hub-rococo-local + - init-asset-hub-westend-local + - init-bridge-hub-westend-local + - reserve-transfer-assets-from-asset-hub-rococo-local + - withdraw-reserve-assets-from-asset-hub-rococo-local + - reserve-transfer-assets-from-asset-hub-westend-local + - withdraw-reserve-assets-from-asset-hub-westend-local + - claim-rewards-bridge-hub-rococo-local + - claim-rewards-bridge-hub-westend-local"; + exit 1 + ;; +esac diff --git a/bridges/testing/environments/rococo-westend/helper.sh b/bridges/testing/environments/rococo-westend/helper.sh new file mode 100755 index 000000000000..0a13ded213f5 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/helper.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +$ENV_PATH/bridges_rococo_westend.sh "$@" diff --git a/bridges/testing/environments/rococo-westend/rococo-init.zndsl b/bridges/testing/environments/rococo-westend/rococo-init.zndsl new file mode 100644 index 000000000000..c913e4db31f4 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/rococo-init.zndsl @@ -0,0 +1,8 @@ +Description: Check if the HRMP channel between Rococo BH and Rococo AH was opened successfully +Network: ./bridge_hub_rococo_local_network.toml +Creds: config + +# ensure that initialization has completed +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wait-hrmp-channel-opened.js with "1013" within 300 seconds + + diff --git a/bridges/testing/environments/rococo-westend/rococo.zndsl b/bridges/testing/environments/rococo-westend/rococo.zndsl new file mode 100644 index 000000000000..5b49c7c632fa --- /dev/null +++ b/bridges/testing/environments/rococo-westend/rococo.zndsl @@ -0,0 +1,7 @@ +Description: Check if the with-Westend GRANPDA pallet was initialized at Rococo BH +Network: ./bridge_hub_rococo_local_network.toml +Creds: config + +# relay is already started - let's wait until with-Westend GRANPDA pallet is initialized at Rococo +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Westend,0" within 400 seconds + diff --git a/bridges/testing/environments/rococo-westend/spawn.sh b/bridges/testing/environments/rococo-westend/spawn.sh new file mode 100755 index 000000000000..cbd0b1bc623a --- /dev/null +++ b/bridges/testing/environments/rococo-westend/spawn.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +set -e + +trap "trap - SIGTERM && kill -9 -$$" SIGINT SIGTERM EXIT + +source "$FRAMEWORK_PATH/utils/zombienet.sh" + +# whether to init the chains (open HRMP channels, set XCM version, create reserve assets, etc) +init=0 +start_relayer=0 +while [ $# -ne 0 ] +do + arg="$1" + case "$arg" in + --init) + init=1 + ;; + --start-relayer) + start_relayer=1 + ;; + esac + shift +done + +logs_dir=$TEST_DIR/logs +helper_script="${BASH_SOURCE%/*}/helper.sh" + +rococo_def=${BASH_SOURCE%/*}/bridge_hub_rococo_local_network.toml +start_zombienet $TEST_DIR $rococo_def rococo_dir rococo_pid +echo + +westend_def=${BASH_SOURCE%/*}/bridge_hub_westend_local_network.toml +start_zombienet $TEST_DIR $westend_def westend_dir westend_pid +echo + +if [[ $init -eq 1 ]]; then + rococo_init_log=$logs_dir/rococo-init.log + echo -e "Setting up the rococo side of the bridge. Logs available at: $rococo_init_log\n" + + westend_init_log=$logs_dir/westend-init.log + echo -e "Setting up the westend side of the bridge. Logs available at: $westend_init_log\n" + + $helper_script init-asset-hub-rococo-local >> $rococo_init_log 2>&1 & + rococo_init_pid=$! + $helper_script init-asset-hub-westend-local >> $westend_init_log 2>&1 & + westend_init_pid=$! + wait -n $rococo_init_pid $westend_init_pid + + + $helper_script init-bridge-hub-rococo-local >> $rococo_init_log 2>&1 & + rococo_init_pid=$! + $helper_script init-bridge-hub-westend-local >> $westend_init_log 2>&1 & + westend_init_pid=$! + wait -n $rococo_init_pid $westend_init_pid + + run_zndsl ${BASH_SOURCE%/*}/rococo-init.zndsl $rococo_dir + run_zndsl ${BASH_SOURCE%/*}/westend-init.zndsl $westend_dir +fi + +if [[ $start_relayer -eq 1 ]]; then + ${BASH_SOURCE%/*}/start_relayer.sh $rococo_dir $westend_dir relayer_pid +fi + +echo $rococo_dir > $TEST_DIR/rococo.env +echo $westend_dir > $TEST_DIR/westend.env +echo + +wait -n $rococo_pid $westend_pid $relayer_pid +kill -9 -$$ diff --git a/bridges/testing/environments/rococo-westend/start_relayer.sh b/bridges/testing/environments/rococo-westend/start_relayer.sh new file mode 100755 index 000000000000..7ddd312d395a --- /dev/null +++ b/bridges/testing/environments/rococo-westend/start_relayer.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +source "$FRAMEWORK_PATH/utils/common.sh" +source "$FRAMEWORK_PATH/utils/zombienet.sh" + +rococo_dir=$1 +westend_dir=$2 +__relayer_pid=$3 + +logs_dir=$TEST_DIR/logs +helper_script="${BASH_SOURCE%/*}/helper.sh" + +relayer_log=$logs_dir/relayer.log +echo -e "Starting rococo-westend relayer. Logs available at: $relayer_log\n" +start_background_process "$helper_script run-relay" $relayer_log relayer_pid + +run_zndsl ${BASH_SOURCE%/*}/rococo.zndsl $rococo_dir +run_zndsl ${BASH_SOURCE%/*}/westend.zndsl $westend_dir + +eval $__relayer_pid="'$relayer_pid'" + diff --git a/bridges/testing/environments/rococo-westend/westend-init.zndsl b/bridges/testing/environments/rococo-westend/westend-init.zndsl new file mode 100644 index 000000000000..0f5428eed3b0 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/westend-init.zndsl @@ -0,0 +1,7 @@ +Description: Check if the HRMP channel between Westend BH and Westend AH was opened successfully +Network: ./bridge_hub_westend_local_network.toml +Creds: config + +# ensure that initialization has completed +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wait-hrmp-channel-opened.js with "1002" within 600 seconds + diff --git a/bridges/testing/environments/rococo-westend/westend.zndsl b/bridges/testing/environments/rococo-westend/westend.zndsl new file mode 100644 index 000000000000..07968838852f --- /dev/null +++ b/bridges/testing/environments/rococo-westend/westend.zndsl @@ -0,0 +1,6 @@ +Description: Check if the with-Rococo GRANPDA pallet was initialized at Westend BH +Network: ./bridge_hub_westend_local_network.toml +Creds: config + +# relay is already started - let's wait until with-Rococo GRANPDA pallet is initialized at Westend +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds diff --git a/bridges/testing/framework/js-helpers/best-finalized-header-at-bridged-chain.js b/bridges/testing/framework/js-helpers/best-finalized-header-at-bridged-chain.js new file mode 100644 index 000000000000..af4f18aee9b2 --- /dev/null +++ b/bridges/testing/framework/js-helpers/best-finalized-header-at-bridged-chain.js @@ -0,0 +1,25 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later + const bridgedChainName = args[0]; + const expectedBridgedChainHeaderNumber = Number(args[1]); + const runtimeApiMethod = bridgedChainName + "FinalityApi_best_finalized"; + + while (true) { + const encodedBestFinalizedHeaderId = await api.rpc.state.call(runtimeApiMethod, []); + const bestFinalizedHeaderId = api.createType("Option", encodedBestFinalizedHeaderId); + if (bestFinalizedHeaderId.isSome) { + const bestFinalizedHeaderNumber = Number(bestFinalizedHeaderId.unwrap().toHuman()[0]); + if (bestFinalizedHeaderNumber > expectedBridgedChainHeaderNumber) { + return bestFinalizedHeaderNumber; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 6000)); + } +} + +module.exports = { run } diff --git a/bridges/testing/framework/js-helpers/chains/rococo-at-westend.js b/bridges/testing/framework/js-helpers/chains/rococo-at-westend.js new file mode 100644 index 000000000000..bcce3b3a303f --- /dev/null +++ b/bridges/testing/framework/js-helpers/chains/rococo-at-westend.js @@ -0,0 +1,6 @@ +module.exports = { + grandpaPalletName: "bridgeRococoGrandpa", + parachainsPalletName: "bridgeRococoParachains", + messagesPalletName: "bridgeRococoMessages", + bridgedBridgeHubParaId: 1013, +} diff --git a/bridges/testing/framework/js-helpers/chains/westend-at-rococo.js b/bridges/testing/framework/js-helpers/chains/westend-at-rococo.js new file mode 100644 index 000000000000..6a15b64a23b7 --- /dev/null +++ b/bridges/testing/framework/js-helpers/chains/westend-at-rococo.js @@ -0,0 +1,6 @@ +module.exports = { + grandpaPalletName: "bridgeWestendGrandpa", + parachainsPalletName: "bridgeWestendParachains", + messagesPalletName: "bridgeWestendMessages", + bridgedBridgeHubParaId: 1002, +} diff --git a/bridges/testing/framework/js-helpers/native-assets-balance-increased.js b/bridges/testing/framework/js-helpers/native-assets-balance-increased.js new file mode 100644 index 000000000000..749c3e2fec32 --- /dev/null +++ b/bridges/testing/framework/js-helpers/native-assets-balance-increased.js @@ -0,0 +1,21 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + const accountAddress = args[0]; + const expectedIncrease = BigInt(args[1]); + const initialAccountData = await api.query.system.account(accountAddress); + const initialAccountBalance = initialAccountData.data['free']; + while (true) { + const accountData = await api.query.system.account(accountAddress); + const accountBalance = accountData.data['free']; + if (accountBalance > initialAccountBalance + expectedIncrease) { + return accountBalance; + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 6000)); + } +} + +module.exports = {run} diff --git a/bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js b/bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js new file mode 100644 index 000000000000..979179245ebe --- /dev/null +++ b/bridges/testing/framework/js-helpers/only-mandatory-headers-synced-when-idle.js @@ -0,0 +1,44 @@ +const utils = require("./utils"); + +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // parse arguments + const exitAfterSeconds = Number(args[0]); + const bridgedChain = require("./chains/" + args[1]); + + // start listening to new blocks + let totalGrandpaHeaders = 0; + let initialParachainHeaderImported = false; + api.rpc.chain.subscribeNewHeads(async function (header) { + const apiAtParent = await api.at(header.parentHash); + const apiAtCurrent = await api.at(header.hash); + const currentEvents = await apiAtCurrent.query.system.events(); + + totalGrandpaHeaders += await utils.ensureOnlyMandatoryGrandpaHeadersImported( + bridgedChain, + apiAtParent, + apiAtCurrent, + currentEvents, + ); + initialParachainHeaderImported = await utils.ensureOnlyInitialParachainHeaderImported( + bridgedChain, + apiAtParent, + apiAtCurrent, + currentEvents, + ); + }); + + // wait given time + await new Promise(resolve => setTimeout(resolve, exitAfterSeconds * 1000)); + // if we haven't seen any new GRANDPA or parachain headers => fail + if (totalGrandpaHeaders == 0) { + throw new Error("No bridged relay chain headers imported"); + } + if (!initialParachainHeaderImported) { + throw new Error("No bridged parachain headers imported"); + } +} + +module.exports = { run } diff --git a/bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js b/bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js new file mode 100644 index 000000000000..8c3130e4fd96 --- /dev/null +++ b/bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js @@ -0,0 +1,81 @@ +const utils = require("./utils"); + +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // parse arguments + const exitAfterSeconds = Number(args[0]); + const bridgedChain = require("./chains/" + args[1]); + + // start listening to new blocks + let atLeastOneMessageReceived = false; + let atLeastOneMessageDelivered = false; + const unsubscribe = await api.rpc.chain.subscribeNewHeads(async function (header) { + const apiAtParent = await api.at(header.parentHash); + const apiAtCurrent = await api.at(header.hash); + const currentEvents = await apiAtCurrent.query.system.events(); + + const messagesReceived = currentEvents.find((record) => { + return record.event.section == bridgedChain.messagesPalletName + && record.event.method == "MessagesReceived"; + }) != undefined; + const messagesDelivered = currentEvents.find((record) => { + return record.event.section == bridgedChain.messagesPalletName && + record.event.method == "MessagesDelivered"; + }) != undefined; + const hasMessageUpdates = messagesReceived || messagesDelivered; + atLeastOneMessageReceived = atLeastOneMessageReceived || messagesReceived; + atLeastOneMessageDelivered = atLeastOneMessageDelivered || messagesDelivered; + + if (!hasMessageUpdates) { + // if there are no any message update transactions, we only expect mandatory GRANDPA + // headers and initial parachain headers + await utils.ensureOnlyMandatoryGrandpaHeadersImported( + bridgedChain, + apiAtParent, + apiAtCurrent, + currentEvents, + ); + await utils.ensureOnlyInitialParachainHeaderImported( + bridgedChain, + apiAtParent, + apiAtCurrent, + currentEvents, + ); + } else { + const messageTransactions = (messagesReceived ? 1 : 0) + (messagesDelivered ? 1 : 0); + + // otherwise we only accept at most one GRANDPA header + const newGrandpaHeaders = utils.countGrandpaHeaderImports(bridgedChain, currentEvents); + if (newGrandpaHeaders > 1) { + utils.logEvents(currentEvents); + throw new Error("Unexpected relay chain header import: " + newGrandpaHeaders + " / " + messageTransactions); + } + + // ...and at most one parachain header + const newParachainHeaders = utils.countParachainHeaderImports(bridgedChain, currentEvents); + if (newParachainHeaders > 1) { + utils.logEvents(currentEvents); + throw new Error("Unexpected parachain header import: " + newParachainHeaders + " / " + messageTransactions); + } + } + }); + + // wait until we have received + delivered messages OR until timeout + await utils.pollUntil( + exitAfterSeconds, + () => { return atLeastOneMessageReceived && atLeastOneMessageDelivered; }, + () => { unsubscribe(); }, + () => { + if (!atLeastOneMessageReceived) { + throw new Error("No messages received from bridged chain"); + } + if (!atLeastOneMessageDelivered) { + throw new Error("No messages delivered to bridged chain"); + } + }, + ); +} + +module.exports = { run } diff --git a/bridges/testing/framework/js-helpers/relayer-rewards.js b/bridges/testing/framework/js-helpers/relayer-rewards.js new file mode 100644 index 000000000000..5347c649604f --- /dev/null +++ b/bridges/testing/framework/js-helpers/relayer-rewards.js @@ -0,0 +1,28 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later + const relayerAccountAddress = args[0]; + const laneId = args[1]; + const bridgedChainId = args[2]; + const relayerFundOwner = args[3]; + const expectedRelayerReward = BigInt(args[4]); + while (true) { + const relayerReward = await api.query.bridgeRelayers.relayerRewards( + relayerAccountAddress, + { laneId: laneId, bridgedChainId: bridgedChainId, owner: relayerFundOwner } + ); + if (relayerReward.isSome) { + const relayerRewardBalance = relayerReward.unwrap().toBigInt(); + if (relayerRewardBalance > expectedRelayerReward) { + return relayerRewardBalance; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 6000)); + } +} + +module.exports = { run } diff --git a/bridges/testing/framework/js-helpers/utils.js b/bridges/testing/framework/js-helpers/utils.js new file mode 100644 index 000000000000..f6e9f5623b47 --- /dev/null +++ b/bridges/testing/framework/js-helpers/utils.js @@ -0,0 +1,103 @@ +module.exports = { + logEvents: function(events) { + let stringifiedEvents = ""; + events.forEach((record) => { + if (stringifiedEvents != "") { + stringifiedEvents += ", "; + } + stringifiedEvents += record.event.section + "::" + record.event.method; + }); + console.log("Block events: " + stringifiedEvents); + }, + countGrandpaHeaderImports: function(bridgedChain, events) { + return events.reduce( + (count, record) => { + const { event } = record; + if (event.section == bridgedChain.grandpaPalletName && event.method == "UpdatedBestFinalizedHeader") { + count += 1; + } + return count; + }, + 0, + ); + }, + countParachainHeaderImports: function(bridgedChain, events) { + return events.reduce( + (count, record) => { + const { event } = record; + if (event.section == bridgedChain.parachainsPalletName && event.method == "UpdatedParachainHead") { + count += 1; + } + return count; + }, + 0, + ); + }, + pollUntil: async function( + timeoutInSecs, + predicate, + cleanup, + onFailure, + ) { + const begin = new Date().getTime(); + const end = begin + timeoutInSecs * 1000; + while (new Date().getTime() < end) { + if (predicate()) { + cleanup(); + return; + } + await new Promise(resolve => setTimeout(resolve, 100)); + } + + cleanup(); + onFailure(); + }, + ensureOnlyMandatoryGrandpaHeadersImported: async function( + bridgedChain, + apiAtParent, + apiAtCurrent, + currentEvents, + ) { + // remember id of bridged relay chain GRANDPA authorities set at parent block + const authoritySetAtParent = await apiAtParent.query[bridgedChain.grandpaPalletName].currentAuthoritySet(); + const authoritySetIdAtParent = authoritySetAtParent["setId"]; + + // now read the id of bridged relay chain GRANDPA authorities set at current block + const authoritySetAtCurrent = await apiAtCurrent.query[bridgedChain.grandpaPalletName].currentAuthoritySet(); + const authoritySetIdAtCurrent = authoritySetAtCurrent["setId"]; + + // we expect to see no more than `authoritySetIdAtCurrent - authoritySetIdAtParent` new GRANDPA headers + const maxNewGrandpaHeaders = authoritySetIdAtCurrent - authoritySetIdAtParent; + const newGrandpaHeaders = module.exports.countGrandpaHeaderImports(bridgedChain, currentEvents); + + // check that our assumptions are correct + if (newGrandpaHeaders > maxNewGrandpaHeaders) { + module.exports.logEvents(currentEvents); + throw new Error("Unexpected relay chain header import: " + newGrandpaHeaders + " / " + maxNewGrandpaHeaders); + } + + return newGrandpaHeaders; + }, + ensureOnlyInitialParachainHeaderImported: async function( + bridgedChain, + apiAtParent, + apiAtCurrent, + currentEvents, + ) { + // remember whether we already know bridged parachain header at a parent block + const bestBridgedParachainHeader = await apiAtParent.query[bridgedChain.parachainsPalletName].parasInfo(bridgedChain.bridgedBridgeHubParaId);; + const hasBestBridgedParachainHeader = bestBridgedParachainHeader.isSome; + + // we expect to see: no more than `1` bridged parachain header if there were no parachain header before. + const maxNewParachainHeaders = hasBestBridgedParachainHeader ? 0 : 1; + const newParachainHeaders = module.exports.countParachainHeaderImports(bridgedChain, currentEvents); + + // check that our assumptions are correct + if (newParachainHeaders > maxNewParachainHeaders) { + module.exports.logEvents(currentEvents); + throw new Error("Unexpected parachain header import: " + newParachainHeaders + " / " + maxNewParachainHeaders); + } + + return hasBestBridgedParachainHeader; + }, +} diff --git a/bridges/testing/framework/js-helpers/wait-hrmp-channel-opened.js b/bridges/testing/framework/js-helpers/wait-hrmp-channel-opened.js new file mode 100644 index 000000000000..765d48cc4984 --- /dev/null +++ b/bridges/testing/framework/js-helpers/wait-hrmp-channel-opened.js @@ -0,0 +1,22 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + const sibling = args[0]; + + while (true) { + const messagingStateAsObj = await api.query.parachainSystem.relevantMessagingState(); + const messagingState = api.createType("Option", messagingStateAsObj); + if (messagingState.isSome) { + const egressChannels = messagingState.unwrap().egressChannels; + if (egressChannels.find(x => x[0] == sibling)) { + return; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 6000)); + } +} + +module.exports = { run } diff --git a/bridges/testing/framework/js-helpers/wrapped-assets-balance.js b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js new file mode 100644 index 000000000000..27287118547f --- /dev/null +++ b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js @@ -0,0 +1,26 @@ +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + // TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later + const accountAddress = args[0]; + const expectedForeignAssetBalance = BigInt(args[1]); + const bridgedNetworkName = args[2]; + while (true) { + const foreignAssetAccount = await api.query.foreignAssets.account( + { parents: 2, interior: { X1: { GlobalConsensus: bridgedNetworkName } } }, + accountAddress + ); + if (foreignAssetAccount.isSome) { + const foreignAssetAccountBalance = foreignAssetAccount.unwrap().balance.toBigInt(); + if (foreignAssetAccountBalance > expectedForeignAssetBalance) { + return foreignAssetAccountBalance; + } + } + + // else sleep and retry + await new Promise((resolve) => setTimeout(resolve, 6000)); + } +} + +module.exports = { run } diff --git a/bridges/testing/framework/utils/bridges.sh b/bridges/testing/framework/utils/bridges.sh new file mode 100755 index 000000000000..7c8399461584 --- /dev/null +++ b/bridges/testing/framework/utils/bridges.sh @@ -0,0 +1,309 @@ +#!/bin/bash + +function relayer_path() { + local default_path=~/local_bridge_testing/bin/substrate-relay + local path="${SUBSTRATE_RELAY_BINARY:-$default_path}" + echo "$path" +} + +function ensure_relayer() { + local path=$(relayer_path) + if [[ ! -f "$path" ]]; then + echo " Required substrate-relay binary '$path' does not exist!" + echo " You need to build it and copy to this location!" + echo " Please, check ./parachains/runtimes/bridge-hubs/README.md (Prepare/Build/Deploy)" + exit 1 + fi + + echo $path +} + +function ensure_polkadot_js_api() { + if ! which polkadot-js-api &> /dev/null; then + echo '' + echo 'Required command `polkadot-js-api` not in PATH, please, install, e.g.:' + echo "npm install -g @polkadot/api-cli@beta" + echo " or" + echo "yarn global add @polkadot/api-cli" + echo '' + exit 1 + fi + if ! which jq &> /dev/null; then + echo '' + echo 'Required command `jq` not in PATH, please, install, e.g.:' + echo "apt install -y jq" + echo '' + exit 1 + fi + generate_hex_encoded_call_data "check" "--" + local retVal=$? + if [ $retVal -ne 0 ]; then + echo "" + echo "" + echo "-------------------" + echo "Installing (nodejs) sub module: ${BASH_SOURCE%/*}/generate_hex_encoded_call" + pushd ${BASH_SOURCE%/*}/generate_hex_encoded_call + npm install + popd + fi +} + +function call_polkadot_js_api() { + # --noWait: without that argument `polkadot-js-api` waits until transaction is included into the block. + # With it, it just submits it to the tx pool and exits. + # --nonce -1: means to compute transaction nonce using `system_accountNextIndex` RPC, which includes all + # transaction that are in the tx pool. + polkadot-js-api --noWait --nonce -1 "$@" +} + +function generate_hex_encoded_call_data() { + local type=$1 + local endpoint=$2 + local output=$3 + shift + shift + shift + echo "Input params: $@" + + node ${BASH_SOURCE%/*}/../utils/generate_hex_encoded_call "$type" "$endpoint" "$output" "$@" + local retVal=$? + + if [ $type != "check" ]; then + local hex_encoded_data=$(cat $output) + echo "Generated hex-encoded bytes to file '$output': $hex_encoded_data" + fi + + return $retVal +} + +function transfer_balance() { + local runtime_para_endpoint=$1 + local seed=$2 + local target_account=$3 + local amount=$4 + echo " calling transfer_balance:" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" + echo " seed: ${seed}" + echo " target_account: ${target_account}" + echo " amount: ${amount}" + echo "--------------------------------------------------" + + call_polkadot_js_api \ + --ws "${runtime_para_endpoint}" \ + --seed "${seed?}" \ + tx.balances.transferAllowDeath \ + "${target_account}" \ + "${amount}" +} + +function send_governance_transact() { + local relay_url=$1 + local relay_chain_seed=$2 + local para_id=$3 + local hex_encoded_data=$4 + local require_weight_at_most_ref_time=$5 + local require_weight_at_most_proof_size=$6 + echo " calling send_governance_transact:" + echo " relay_url: ${relay_url}" + echo " relay_chain_seed: ${relay_chain_seed}" + echo " para_id: ${para_id}" + echo " hex_encoded_data: ${hex_encoded_data}" + echo " require_weight_at_most_ref_time: ${require_weight_at_most_ref_time}" + echo " require_weight_at_most_proof_size: ${require_weight_at_most_proof_size}" + echo " params:" + + local dest=$(jq --null-input \ + --arg para_id "$para_id" \ + '{ "V3": { "parents": 0, "interior": { "X1": { "Parachain": $para_id } } } }') + + local message=$(jq --null-input \ + --argjson hex_encoded_data $hex_encoded_data \ + --arg require_weight_at_most_ref_time "$require_weight_at_most_ref_time" \ + --arg require_weight_at_most_proof_size "$require_weight_at_most_proof_size" \ + ' + { + "V3": [ + { + "UnpaidExecution": { + "weight_limit": "Unlimited" + } + }, + { + "Transact": { + "origin_kind": "Superuser", + "require_weight_at_most": { + "ref_time": $require_weight_at_most_ref_time, + "proof_size": $require_weight_at_most_proof_size, + }, + "call": { + "encoded": $hex_encoded_data + } + } + } + ] + } + ') + + echo "" + echo " dest:" + echo "${dest}" + echo "" + echo " message:" + echo "${message}" + echo "" + echo "--------------------------------------------------" + + call_polkadot_js_api \ + --ws "${relay_url?}" \ + --seed "${relay_chain_seed?}" \ + --sudo \ + tx.xcmPallet.send \ + "${dest}" \ + "${message}" +} + +function open_hrmp_channels() { + local relay_url=$1 + local relay_chain_seed=$2 + local sender_para_id=$3 + local recipient_para_id=$4 + local max_capacity=$5 + local max_message_size=$6 + echo " calling open_hrmp_channels:" + echo " relay_url: ${relay_url}" + echo " relay_chain_seed: ${relay_chain_seed}" + echo " sender_para_id: ${sender_para_id}" + echo " recipient_para_id: ${recipient_para_id}" + echo " max_capacity: ${max_capacity}" + echo " max_message_size: ${max_message_size}" + echo " params:" + echo "--------------------------------------------------" + call_polkadot_js_api \ + --ws "${relay_url?}" \ + --seed "${relay_chain_seed?}" \ + --sudo \ + tx.hrmp.forceOpenHrmpChannel \ + ${sender_para_id} \ + ${recipient_para_id} \ + ${max_capacity} \ + ${max_message_size} +} + +function force_xcm_version() { + local relay_url=$1 + local relay_chain_seed=$2 + local runtime_para_id=$3 + local runtime_para_endpoint=$4 + local dest=$5 + local xcm_version=$6 + echo " calling force_xcm_version:" + echo " relay_url: ${relay_url}" + echo " relay_chain_seed: ${relay_chain_seed}" + echo " runtime_para_id: ${runtime_para_id}" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" + echo " dest: ${dest}" + echo " xcm_version: ${xcm_version}" + echo " params:" + + # 1. generate data for Transact (PolkadotXcm::force_xcm_version) + local tmp_output_file=$(mktemp) + generate_hex_encoded_call_data "force-xcm-version" "${runtime_para_endpoint}" "${tmp_output_file}" "$dest" "$xcm_version" + local hex_encoded_data=$(cat $tmp_output_file) + + # 2. trigger governance call + send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 +} + +function force_create_foreign_asset() { + local relay_url=$1 + local relay_chain_seed=$2 + local runtime_para_id=$3 + local runtime_para_endpoint=$4 + local asset_multilocation=$5 + local asset_owner_account_id=$6 + local min_balance=$7 + local is_sufficient=$8 + echo " calling force_create_foreign_asset:" + echo " relay_url: ${relay_url}" + echo " relay_chain_seed: ${relay_chain_seed}" + echo " runtime_para_id: ${runtime_para_id}" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" + echo " asset_multilocation: ${asset_multilocation}" + echo " asset_owner_account_id: ${asset_owner_account_id}" + echo " min_balance: ${min_balance}" + echo " is_sufficient: ${is_sufficient}" + echo " params:" + + # 1. generate data for Transact (ForeignAssets::force_create) + local tmp_output_file=$(mktemp) + generate_hex_encoded_call_data "force-create-asset" "${runtime_para_endpoint}" "${tmp_output_file}" "$asset_multilocation" "$asset_owner_account_id" $is_sufficient $min_balance + local hex_encoded_data=$(cat $tmp_output_file) + + # 2. trigger governance call + send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 +} + +function limited_reserve_transfer_assets() { + local url=$1 + local seed=$2 + local destination=$3 + local beneficiary=$4 + local assets=$5 + local fee_asset_item=$6 + local weight_limit=$7 + echo " calling limited_reserve_transfer_assets:" + echo " url: ${url}" + echo " seed: ${seed}" + echo " destination: ${destination}" + echo " beneficiary: ${beneficiary}" + echo " assets: ${assets}" + echo " fee_asset_item: ${fee_asset_item}" + echo " weight_limit: ${weight_limit}" + echo "" + echo "--------------------------------------------------" + + call_polkadot_js_api \ + --ws "${url?}" \ + --seed "${seed?}" \ + tx.polkadotXcm.limitedReserveTransferAssets \ + "${destination}" \ + "${beneficiary}" \ + "${assets}" \ + "${fee_asset_item}" \ + "${weight_limit}" +} + +function claim_rewards() { + local runtime_para_endpoint=$1 + local seed=$2 + local lane_id=$3 + local bridged_chain_id=$4 + local owner=$5 + echo " calling claim_rewards:" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" + echo " seed: ${seed}" + echo " lane_id: ${lane_id}" + echo " bridged_chain_id: ${bridged_chain_id}" + echo " owner: ${owner}" + echo "" + + local rewards_account_params=$(jq --null-input \ + --arg lane_id "$lane_id" \ + --arg bridged_chain_id "$bridged_chain_id" \ + --arg owner "$owner" \ + '{ + "laneId": $lane_id, + "bridgedChainId": $bridged_chain_id, + "owner": $owner + }') + + echo " rewards_account_params:" + echo "${rewards_account_params}" + echo "--------------------------------------------------" + + call_polkadot_js_api \ + --ws "${runtime_para_endpoint}" \ + --seed "${seed?}" \ + tx.bridgeRelayers.claimRewards \ + "${rewards_account_params}" +} \ No newline at end of file diff --git a/bridges/testing/framework/utils/common.sh b/bridges/testing/framework/utils/common.sh new file mode 100644 index 000000000000..06f41320be13 --- /dev/null +++ b/bridges/testing/framework/utils/common.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +function start_background_process() { + local command=$1 + local log_file=$2 + local __pid=$3 + + $command > $log_file 2>&1 & + eval $__pid="'$!'" +} + +function wait_for_process_file() { + local pid=$1 + local file=$2 + local timeout=$3 + local __found=$4 + + local time=0 + until [ -e $file ]; do + if ! kill -0 $pid; then + echo "Process finished unsuccessfully" + return + fi + if (( time++ >= timeout )); then + echo "Timeout waiting for file $file: $timeout seconds" + eval $__found=0 + return + fi + sleep 1 + done + + echo "File $file found after $time seconds" + eval $__found=1 +} + +function ensure_process_file() { + local pid=$1 + local file=$2 + local timeout=$3 + + wait_for_process_file $pid $file $timeout file_found + if [ "$file_found" != "1" ]; then + exit 1 + fi +} diff --git a/bridges/testing/framework/utils/generate_hex_encoded_call/index.js b/bridges/testing/framework/utils/generate_hex_encoded_call/index.js new file mode 100644 index 000000000000..30f89d754ceb --- /dev/null +++ b/bridges/testing/framework/utils/generate_hex_encoded_call/index.js @@ -0,0 +1,165 @@ +const fs = require("fs"); +const { exit } = require("process"); +const { WsProvider, ApiPromise } = require("@polkadot/api"); +const util = require("@polkadot/util"); + +// connect to a substrate chain and return the api object +async function connect(endpoint, types = {}) { + const provider = new WsProvider(endpoint); + const api = await ApiPromise.create({ + provider, + types, + throwOnConnect: false, + }); + return api; +} + +function writeHexEncodedBytesToOutput(method, outputFile) { + console.log("Payload (hex): ", method.toHex()); + console.log("Payload (bytes): ", Array.from(method.toU8a())); + console.log("Payload (plain): ", JSON.stringify(method)); + fs.writeFileSync(outputFile, JSON.stringify(Array.from(method.toU8a()))); +} + +function remarkWithEvent(endpoint, outputFile) { + console.log(`Generating remarkWithEvent from RPC endpoint: ${endpoint} to outputFile: ${outputFile}`); + connect(endpoint) + .then((api) => { + const call = api.tx.system.remarkWithEvent("Hello"); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function addExporterConfig(endpoint, outputFile, bridgedNetwork, bridgeConfig) { + console.log(`Generating addExporterConfig from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on bridgedNetwork: ${bridgedNetwork}, bridgeConfig: ${bridgeConfig}`); + connect(endpoint) + .then((api) => { + const call = api.tx.bridgeTransfer.addExporterConfig(bridgedNetwork, JSON.parse(bridgeConfig)); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function addUniversalAlias(endpoint, outputFile, location, junction) { + console.log(`Generating addUniversalAlias from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on location: ${location}, junction: ${junction}`); + connect(endpoint) + .then((api) => { + const call = api.tx.bridgeTransfer.addUniversalAlias(JSON.parse(location), JSON.parse(junction)); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function addReserveLocation(endpoint, outputFile, reserve_location) { + console.log(`Generating addReserveLocation from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on reserve_location: ${reserve_location}`); + connect(endpoint) + .then((api) => { + const call = api.tx.bridgeTransfer.addReserveLocation(JSON.parse(reserve_location)); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function removeExporterConfig(endpoint, outputFile, bridgedNetwork) { + console.log(`Generating removeExporterConfig from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on bridgedNetwork: ${bridgedNetwork}`); + connect(endpoint) + .then((api) => { + const call = api.tx.bridgeTransfer.removeExporterConfig(bridgedNetwork); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function forceCreateAsset(endpoint, outputFile, assetId, assetOwnerAccountId, isSufficient, minBalance) { + var isSufficient = isSufficient == "true" ? true : false; + console.log(`Generating forceCreateAsset from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on assetId: ${assetId}, assetOwnerAccountId: ${assetOwnerAccountId}, isSufficient: ${isSufficient}, minBalance: ${minBalance}`); + connect(endpoint) + .then((api) => { + const call = api.tx.foreignAssets.forceCreate(JSON.parse(assetId), assetOwnerAccountId, isSufficient, minBalance); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function forceXcmVersion(endpoint, outputFile, dest, xcm_version) { + console.log(`Generating forceXcmVersion from RPC endpoint: ${endpoint} to outputFile: ${outputFile}, dest: ${dest}, xcm_version: ${xcm_version}`); + connect(endpoint) + .then((api) => { + const call = api.tx.polkadotXcm.forceXcmVersion(JSON.parse(dest), xcm_version); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +if (!process.argv[2] || !process.argv[3]) { + console.log("usage: node ./script/generate_hex_encoded_call "); + exit(1); +} + +const type = process.argv[2]; +const rpcEnpoint = process.argv[3]; +const output = process.argv[4]; +const inputArgs = process.argv.slice(5, process.argv.length); +console.log(`Generating hex-encoded call data for:`); +console.log(` type: ${type}`); +console.log(` rpcEnpoint: ${rpcEnpoint}`); +console.log(` output: ${output}`); +console.log(` inputArgs: ${inputArgs}`); + +switch (type) { + case 'remark-with-event': + remarkWithEvent(rpcEnpoint, output); + break; + case 'add-exporter-config': + addExporterConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + break; + case 'remove-exporter-config': + removeExporterConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + break; + case 'add-universal-alias': + addUniversalAlias(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + break; + case 'add-reserve-location': + addReserveLocation(rpcEnpoint, output, inputArgs[0]); + break; + case 'force-create-asset': + forceCreateAsset(rpcEnpoint, output, inputArgs[0], inputArgs[1], inputArgs[2], inputArgs[3]); + break; + case 'force-xcm-version': + forceXcmVersion(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + break; + case 'check': + console.log(`Checking nodejs installation, if you see this everything is ready!`); + break; + default: + console.log(`Sorry, we are out of ${type} - not yet supported!`); +} diff --git a/bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json b/bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json new file mode 100644 index 000000000000..b2dddaa19ed1 --- /dev/null +++ b/bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json @@ -0,0 +1,759 @@ +{ + "name": "y", + "version": "y", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "y", + "version": "y", + "license": "MIT", + "dependencies": { + "@polkadot/api": "^10.11", + "@polkadot/util": "^12.6" + } + }, + "node_modules/@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@polkadot/api": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/api/-/api-10.11.2.tgz", + "integrity": "sha512-AorCZxCWCoTtdbl4DPUZh+ACe/pbLIS1BkdQY0AFJuZllm0x/yWzjgampcPd5jQAA/O3iKShRBkZqj6Mk9yG/A==", + "dependencies": { + "@polkadot/api-augment": "10.11.2", + "@polkadot/api-base": "10.11.2", + "@polkadot/api-derive": "10.11.2", + "@polkadot/keyring": "^12.6.2", + "@polkadot/rpc-augment": "10.11.2", + "@polkadot/rpc-core": "10.11.2", + "@polkadot/rpc-provider": "10.11.2", + "@polkadot/types": "10.11.2", + "@polkadot/types-augment": "10.11.2", + "@polkadot/types-codec": "10.11.2", + "@polkadot/types-create": "10.11.2", + "@polkadot/types-known": "10.11.2", + "@polkadot/util": "^12.6.2", + "@polkadot/util-crypto": "^12.6.2", + "eventemitter3": "^5.0.1", + "rxjs": "^7.8.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/api-augment": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/api-augment/-/api-augment-10.11.2.tgz", + "integrity": "sha512-PTpnqpezc75qBqUtgrc0GYB8h9UHjfbHSRZamAbecIVAJ2/zc6CqtnldeaBlIu1IKTgBzi3FFtTyYu+ZGbNT2Q==", + "dependencies": { + "@polkadot/api-base": "10.11.2", + "@polkadot/rpc-augment": "10.11.2", + "@polkadot/types": "10.11.2", + "@polkadot/types-augment": "10.11.2", + "@polkadot/types-codec": "10.11.2", + "@polkadot/util": "^12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/api-base": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/api-base/-/api-base-10.11.2.tgz", + "integrity": "sha512-4LIjaUfO9nOzilxo7XqzYKCNMtmUypdk8oHPdrRnSjKEsnK7vDsNi+979z2KXNXd2KFSCFHENmI523fYnMnReg==", + "dependencies": { + "@polkadot/rpc-core": "10.11.2", + "@polkadot/types": "10.11.2", + "@polkadot/util": "^12.6.2", + "rxjs": "^7.8.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/api-derive": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/api-derive/-/api-derive-10.11.2.tgz", + "integrity": "sha512-m3BQbPionkd1iSlknddxnL2hDtolPIsT+aRyrtn4zgMRPoLjHFmTmovvg8RaUyYofJtZeYrnjMw0mdxiSXx7eA==", + "dependencies": { + "@polkadot/api": "10.11.2", + "@polkadot/api-augment": "10.11.2", + "@polkadot/api-base": "10.11.2", + "@polkadot/rpc-core": "10.11.2", + "@polkadot/types": "10.11.2", + "@polkadot/types-codec": "10.11.2", + "@polkadot/util": "^12.6.2", + "@polkadot/util-crypto": "^12.6.2", + "rxjs": "^7.8.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/keyring": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/keyring/-/keyring-12.6.2.tgz", + "integrity": "sha512-O3Q7GVmRYm8q7HuB3S0+Yf/q/EB2egKRRU3fv9b3B7V+A52tKzA+vIwEmNVaD1g5FKW9oB97rmpggs0zaKFqHw==", + "dependencies": { + "@polkadot/util": "12.6.2", + "@polkadot/util-crypto": "12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "12.6.2", + "@polkadot/util-crypto": "12.6.2" + } + }, + "node_modules/@polkadot/networks": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/networks/-/networks-12.6.2.tgz", + "integrity": "sha512-1oWtZm1IvPWqvMrldVH6NI2gBoCndl5GEwx7lAuQWGr7eNL+6Bdc5K3Z9T0MzFvDGoi2/CBqjX9dRKo39pDC/w==", + "dependencies": { + "@polkadot/util": "12.6.2", + "@substrate/ss58-registry": "^1.44.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/rpc-augment": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-augment/-/rpc-augment-10.11.2.tgz", + "integrity": "sha512-9AhT0WW81/8jYbRcAC6PRmuxXqNhJje8OYiulBQHbG1DTCcjAfz+6VQBke9BwTStzPq7d526+yyBKD17O3zlAA==", + "dependencies": { + "@polkadot/rpc-core": "10.11.2", + "@polkadot/types": "10.11.2", + "@polkadot/types-codec": "10.11.2", + "@polkadot/util": "^12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/rpc-core": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-core/-/rpc-core-10.11.2.tgz", + "integrity": "sha512-Ot0CFLWx8sZhLZog20WDuniPA01Bk2StNDsdAQgcFKPwZw6ShPaZQCHuKLQK6I6DodOrem9FXX7c1hvoKJP5Ww==", + "dependencies": { + "@polkadot/rpc-augment": "10.11.2", + "@polkadot/rpc-provider": "10.11.2", + "@polkadot/types": "10.11.2", + "@polkadot/util": "^12.6.2", + "rxjs": "^7.8.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/rpc-provider": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/rpc-provider/-/rpc-provider-10.11.2.tgz", + "integrity": "sha512-he5jWMpDJp7e+vUzTZDzpkB7ps3H8psRally+/ZvZZScPvFEjfczT7I1WWY9h58s8+ImeVP/lkXjL9h/gUOt3Q==", + "dependencies": { + "@polkadot/keyring": "^12.6.2", + "@polkadot/types": "10.11.2", + "@polkadot/types-support": "10.11.2", + "@polkadot/util": "^12.6.2", + "@polkadot/util-crypto": "^12.6.2", + "@polkadot/x-fetch": "^12.6.2", + "@polkadot/x-global": "^12.6.2", + "@polkadot/x-ws": "^12.6.2", + "eventemitter3": "^5.0.1", + "mock-socket": "^9.3.1", + "nock": "^13.4.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@substrate/connect": "0.7.35" + } + }, + "node_modules/@polkadot/types": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/types/-/types-10.11.2.tgz", + "integrity": "sha512-d52j3xXni+C8GdYZVTSfu8ROAnzXFMlyRvXtor0PudUc8UQHOaC4+mYAkTBGA2gKdmL8MHSfRSbhcxHhsikY6Q==", + "dependencies": { + "@polkadot/keyring": "^12.6.2", + "@polkadot/types-augment": "10.11.2", + "@polkadot/types-codec": "10.11.2", + "@polkadot/types-create": "10.11.2", + "@polkadot/util": "^12.6.2", + "@polkadot/util-crypto": "^12.6.2", + "rxjs": "^7.8.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-augment": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/types-augment/-/types-augment-10.11.2.tgz", + "integrity": "sha512-8eB8ew04wZiE5GnmFvEFW1euJWmF62SGxb1O+8wL3zoUtB9Xgo1vB6w6xbTrd+HLV6jNSeXXnbbF1BEUvi9cNg==", + "dependencies": { + "@polkadot/types": "10.11.2", + "@polkadot/types-codec": "10.11.2", + "@polkadot/util": "^12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-codec": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/types-codec/-/types-codec-10.11.2.tgz", + "integrity": "sha512-3xjOQL+LOOMzYqlgP9ROL0FQnzU8lGflgYewzau7AsDlFziSEtb49a9BpYo6zil4koC+QB8zQ9OHGFumG08T8w==", + "dependencies": { + "@polkadot/util": "^12.6.2", + "@polkadot/x-bigint": "^12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-create": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/types-create/-/types-create-10.11.2.tgz", + "integrity": "sha512-SJt23NxYvefRxVZZm6mT9ed1pR6FDoIGQ3xUpbjhTLfU2wuhpKjekMVorYQ6z/gK2JLMu2kV92Ardsz+6GX5XQ==", + "dependencies": { + "@polkadot/types-codec": "10.11.2", + "@polkadot/util": "^12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-known": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/types-known/-/types-known-10.11.2.tgz", + "integrity": "sha512-kbEIX7NUQFxpDB0FFGNyXX/odY7jbp56RGD+Z4A731fW2xh/DgAQrI994xTzuh0c0EqPE26oQm3kATSpseqo9w==", + "dependencies": { + "@polkadot/networks": "^12.6.2", + "@polkadot/types": "10.11.2", + "@polkadot/types-codec": "10.11.2", + "@polkadot/types-create": "10.11.2", + "@polkadot/util": "^12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/types-support": { + "version": "10.11.2", + "resolved": "https://registry.npmjs.org/@polkadot/types-support/-/types-support-10.11.2.tgz", + "integrity": "sha512-X11hoykFYv/3efg4coZy2hUOUc97JhjQMJLzDhHniFwGLlYU8MeLnPdCVGkXx0xDDjTo4/ptS1XpZ5HYcg+gRw==", + "dependencies": { + "@polkadot/util": "^12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/util": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-12.6.2.tgz", + "integrity": "sha512-l8TubR7CLEY47240uki0TQzFvtnxFIO7uI/0GoWzpYD/O62EIAMRsuY01N4DuwgKq2ZWD59WhzsLYmA5K6ksdw==", + "dependencies": { + "@polkadot/x-bigint": "12.6.2", + "@polkadot/x-global": "12.6.2", + "@polkadot/x-textdecoder": "12.6.2", + "@polkadot/x-textencoder": "12.6.2", + "@types/bn.js": "^5.1.5", + "bn.js": "^5.2.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/util-crypto": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/util-crypto/-/util-crypto-12.6.2.tgz", + "integrity": "sha512-FEWI/dJ7wDMNN1WOzZAjQoIcCP/3vz3wvAp5QQm+lOrzOLj0iDmaIGIcBkz8HVm3ErfSe/uKP0KS4jgV/ib+Mg==", + "dependencies": { + "@noble/curves": "^1.3.0", + "@noble/hashes": "^1.3.3", + "@polkadot/networks": "12.6.2", + "@polkadot/util": "12.6.2", + "@polkadot/wasm-crypto": "^7.3.2", + "@polkadot/wasm-util": "^7.3.2", + "@polkadot/x-bigint": "12.6.2", + "@polkadot/x-randomvalues": "12.6.2", + "@scure/base": "^1.1.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "12.6.2" + } + }, + "node_modules/@polkadot/wasm-bridge": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-bridge/-/wasm-bridge-7.3.2.tgz", + "integrity": "sha512-AJEXChcf/nKXd5Q/YLEV5dXQMle3UNT7jcXYmIffZAo/KI394a+/24PaISyQjoNC0fkzS1Q8T5pnGGHmXiVz2g==", + "dependencies": { + "@polkadot/wasm-util": "7.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto/-/wasm-crypto-7.3.2.tgz", + "integrity": "sha512-+neIDLSJ6jjVXsjyZ5oLSv16oIpwp+PxFqTUaZdZDoA2EyFRQB8pP7+qLsMNk+WJuhuJ4qXil/7XiOnZYZ+wxw==", + "dependencies": { + "@polkadot/wasm-bridge": "7.3.2", + "@polkadot/wasm-crypto-asmjs": "7.3.2", + "@polkadot/wasm-crypto-init": "7.3.2", + "@polkadot/wasm-crypto-wasm": "7.3.2", + "@polkadot/wasm-util": "7.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-asmjs": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.3.2.tgz", + "integrity": "sha512-QP5eiUqUFur/2UoF2KKKYJcesc71fXhQFLT3D4ZjG28Mfk2ZPI0QNRUfpcxVQmIUpV5USHg4geCBNuCYsMm20Q==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-init": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.3.2.tgz", + "integrity": "sha512-FPq73zGmvZtnuJaFV44brze3Lkrki3b4PebxCy9Fplw8nTmisKo9Xxtfew08r0njyYh+uiJRAxPCXadkC9sc8g==", + "dependencies": { + "@polkadot/wasm-bridge": "7.3.2", + "@polkadot/wasm-crypto-asmjs": "7.3.2", + "@polkadot/wasm-crypto-wasm": "7.3.2", + "@polkadot/wasm-util": "7.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*", + "@polkadot/x-randomvalues": "*" + } + }, + "node_modules/@polkadot/wasm-crypto-wasm": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.3.2.tgz", + "integrity": "sha512-15wd0EMv9IXs5Abp1ZKpKKAVyZPhATIAHfKsyoWCEFDLSOA0/K0QGOxzrAlsrdUkiKZOq7uzSIgIDgW8okx2Mw==", + "dependencies": { + "@polkadot/wasm-util": "7.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/wasm-util": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@polkadot/wasm-util/-/wasm-util-7.3.2.tgz", + "integrity": "sha512-bmD+Dxo1lTZyZNxbyPE380wd82QsX+43mgCm40boyKrRppXEyQmWT98v/Poc7chLuskYb6X8IQ6lvvK2bGR4Tg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "*" + } + }, + "node_modules/@polkadot/x-bigint": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/x-bigint/-/x-bigint-12.6.2.tgz", + "integrity": "sha512-HSIk60uFPX4GOFZSnIF7VYJz7WZA7tpFJsne7SzxOooRwMTWEtw3fUpFy5cYYOeLh17/kHH1Y7SVcuxzVLc74Q==", + "dependencies": { + "@polkadot/x-global": "12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-fetch": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/x-fetch/-/x-fetch-12.6.2.tgz", + "integrity": "sha512-8wM/Z9JJPWN1pzSpU7XxTI1ldj/AfC8hKioBlUahZ8gUiJaOF7K9XEFCrCDLis/A1BoOu7Ne6WMx/vsJJIbDWw==", + "dependencies": { + "@polkadot/x-global": "12.6.2", + "node-fetch": "^3.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-global": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/x-global/-/x-global-12.6.2.tgz", + "integrity": "sha512-a8d6m+PW98jmsYDtAWp88qS4dl8DyqUBsd0S+WgyfSMtpEXu6v9nXDgPZgwF5xdDvXhm+P0ZfVkVTnIGrScb5g==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-randomvalues": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-12.6.2.tgz", + "integrity": "sha512-Vr8uG7rH2IcNJwtyf5ebdODMcr0XjoCpUbI91Zv6AlKVYOGKZlKLYJHIwpTaKKB+7KPWyQrk4Mlym/rS7v9feg==", + "dependencies": { + "@polkadot/x-global": "12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@polkadot/util": "12.6.2", + "@polkadot/wasm-util": "*" + } + }, + "node_modules/@polkadot/x-textdecoder": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/x-textdecoder/-/x-textdecoder-12.6.2.tgz", + "integrity": "sha512-M1Bir7tYvNappfpFWXOJcnxUhBUFWkUFIdJSyH0zs5LmFtFdbKAeiDXxSp2Swp5ddOZdZgPac294/o2TnQKN1w==", + "dependencies": { + "@polkadot/x-global": "12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-textencoder": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/x-textencoder/-/x-textencoder-12.6.2.tgz", + "integrity": "sha512-4N+3UVCpI489tUJ6cv3uf0PjOHvgGp9Dl+SZRLgFGt9mvxnvpW/7+XBADRMtlG4xi5gaRK7bgl5bmY6OMDsNdw==", + "dependencies": { + "@polkadot/x-global": "12.6.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polkadot/x-ws": { + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@polkadot/x-ws/-/x-ws-12.6.2.tgz", + "integrity": "sha512-cGZWo7K5eRRQCRl2LrcyCYsrc3lRbTlixZh3AzgU8uX4wASVGRlNWi/Hf4TtHNe1ExCDmxabJzdIsABIfrr7xw==", + "dependencies": { + "@polkadot/x-global": "12.6.2", + "tslib": "^2.6.2", + "ws": "^8.15.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@scure/base": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", + "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@substrate/connect": { + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/@substrate/connect/-/connect-0.7.35.tgz", + "integrity": "sha512-Io8vkalbwaye+7yXfG1Nj52tOOoJln2bMlc7Q9Yy3vEWqZEVkgKmcPVzbwV0CWL3QD+KMPDA2Dnw/X7EdwgoLw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@substrate/connect-extension-protocol": "^1.0.1", + "smoldot": "2.0.7" + } + }, + "node_modules/@substrate/connect-extension-protocol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@substrate/connect-extension-protocol/-/connect-extension-protocol-1.0.1.tgz", + "integrity": "sha512-161JhCC1csjH3GE5mPLEd7HbWtwNSPJBg3p1Ksz9SFlTzj/bgEwudiRN2y5i0MoLGCIJRYKyKGMxVnd29PzNjg==", + "optional": true + }, + "node_modules/@substrate/ss58-registry": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/@substrate/ss58-registry/-/ss58-registry-1.44.0.tgz", + "integrity": "sha512-7lQ/7mMCzVNSEfDS4BCqnRnKCFKpcOaPrxMeGTXHX1YQzM/m2BBHjbK2C3dJvjv7GYxMiaTq/HdWQj1xS6ss+A==" + }, + "node_modules/@types/bn.js": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/mock-socket": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", + "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nock": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.4.0.tgz", + "integrity": "sha512-W8NVHjO/LCTNA64yxAPHV/K47LpGYcVzgKd3Q0n6owhwvD0Dgoterc25R4rnZbckJEb6Loxz1f5QMuJpJnbSyQ==", + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/smoldot": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-2.0.7.tgz", + "integrity": "sha512-VAOBqEen6vises36/zgrmAT1GWk2qE3X8AGnO7lmQFdskbKx8EovnwS22rtPAG+Y1Rk23/S22kDJUdPANyPkBA==", + "optional": true, + "dependencies": { + "ws": "^8.8.1" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/bridges/testing/framework/utils/generate_hex_encoded_call/package.json b/bridges/testing/framework/utils/generate_hex_encoded_call/package.json new file mode 100644 index 000000000000..ecf0a2483db1 --- /dev/null +++ b/bridges/testing/framework/utils/generate_hex_encoded_call/package.json @@ -0,0 +1,11 @@ +{ + "name": "y", + "version": "y", + "description": "create a scale hex-encoded call values from given message", + "main": "index.js", + "license": "MIT", + "dependencies": { + "@polkadot/api": "^10.11", + "@polkadot/util": "^12.6" + } +} diff --git a/bridges/testing/framework/utils/zombienet.sh b/bridges/testing/framework/utils/zombienet.sh new file mode 100644 index 000000000000..bbcd1a306202 --- /dev/null +++ b/bridges/testing/framework/utils/zombienet.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +source "${BASH_SOURCE%/*}/common.sh" + +function start_zombienet() { + local test_dir=$1 + local definition_path=$2 + local __zombienet_dir=$3 + local __zombienet_pid=$4 + + local zombienet_name=`basename $definition_path .toml` + local zombienet_dir=$test_dir/$zombienet_name + eval $__zombienet_dir="'$zombienet_dir'" + mkdir -p $zombienet_dir + rm -rf $zombienet_dir + + local logs_dir=$test_dir/logs + mkdir -p $logs_dir + local zombienet_log=$logs_dir/$zombienet_name.log + + echo "Starting $zombienet_name zombienet. Logs available at: $zombienet_log" + start_background_process \ + "$ZOMBIENET_BINARY spawn --dir $zombienet_dir --provider native $definition_path" \ + "$zombienet_log" zombienet_pid + + ensure_process_file $zombienet_pid "$zombienet_dir/zombie.json" 180 + echo "$zombienet_name zombienet started successfully" + + eval $__zombienet_pid="'$zombienet_pid'" +} + +function run_zndsl() { + local zndsl_file=$1 + local zombienet_dir=$2 + + echo "Running $zndsl_file." + $ZOMBIENET_BINARY test --dir $zombienet_dir --provider native $zndsl_file $zombienet_dir/zombie.json + echo +} diff --git a/bridges/testing/run-new-test.sh b/bridges/testing/run-new-test.sh new file mode 100755 index 000000000000..7c84a69aa47d --- /dev/null +++ b/bridges/testing/run-new-test.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -e + +trap 'kill -9 -$$ || echo "Environment already teared down"' SIGINT SIGTERM EXIT + +test=$1 +shift + +# whether to use paths for zombienet+bridges tests container or for local testing +ZOMBIENET_DOCKER_PATHS=0 +while [ $# -ne 0 ] +do + arg="$1" + case "$arg" in + --docker) + ZOMBIENET_DOCKER_PATHS=1 + ;; + esac + shift +done + +export POLKADOT_SDK_PATH=`realpath ${BASH_SOURCE%/*}/../..` +export FRAMEWORK_PATH=`realpath ${BASH_SOURCE%/*}/framework` + +# set path to binaries +if [ "$ZOMBIENET_DOCKER_PATHS" -eq 1 ]; then + # otherwise zombienet uses some hardcoded paths + unset RUN_IN_CONTAINER + unset ZOMBIENET_IMAGE + + export POLKADOT_BINARY=/usr/local/bin/polkadot + export POLKADOT_PARACHAIN_BINARY=/usr/local/bin/polkadot-parachain + + export ZOMBIENET_BINARY=/usr/local/bin/zombie + export SUBSTRATE_RELAY_BINARY=/usr/local/bin/substrate-relay +else + export POLKADOT_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot + export POLKADOT_PARACHAIN_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot-parachain + + export ZOMBIENET_BINARY=~/local_bridge_testing/bin/zombienet-linux-x64 + export SUBSTRATE_RELAY_BINARY=~/local_bridge_testing/bin/substrate-relay +fi + +export TEST_DIR=`mktemp -d /tmp/bridges-tests-run-XXXXX` +echo -e "Test folder: $TEST_DIR\n" + +${BASH_SOURCE%/*}/tests/$test/run.sh diff --git a/bridges/testing/run-tests.sh b/bridges/testing/run-tests.sh new file mode 100755 index 000000000000..6149d9912653 --- /dev/null +++ b/bridges/testing/run-tests.sh @@ -0,0 +1,138 @@ +#!/bin/bash +set -x +shopt -s nullglob + +trap "trap - SIGINT SIGTERM EXIT && killall -q -9 substrate-relay && kill -- -$$" SIGINT SIGTERM EXIT + +# run tests in range [TESTS_BEGIN; TESTS_END) +TESTS_BEGIN=1 +TESTS_END=1000 +# whether to use paths for zombienet+bridges tests container or for local testing +ZOMBIENET_DOCKER_PATHS=0 +while [ $# -ne 0 ] +do + arg="$1" + case "$arg" in + --docker) + ZOMBIENET_DOCKER_PATHS=1 + ;; + --test) + shift + TESTS_BEGIN="$1" + TESTS_END="$1" + ;; + esac + shift +done + +# assuming that we'll be using native provide && all processes will be executing locally +# (we need absolute paths here, because they're used when scripts are called by zombienet from tmp folders) +export POLKADOT_SDK_PATH=`realpath $(dirname "$0")/../..` +export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_PATH/bridges/testing/tests + +# set pathc to binaries +if [ "$ZOMBIENET_DOCKER_PATHS" -eq 1 ]; then + export POLKADOT_BINARY=/usr/local/bin/polkadot + export POLKADOT_PARACHAIN_BINARY=/usr/local/bin/polkadot-parachain + + export SUBSTRATE_RELAY_BINARY=/usr/local/bin/substrate-relay + export ZOMBIENET_BINARY_PATH=/usr/local/bin/zombie +else + export POLKADOT_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot + export POLKADOT_PARACHAIN_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot-parachain + + export SUBSTRATE_RELAY_BINARY=~/local_bridge_testing/bin/substrate-relay + export ZOMBIENET_BINARY_PATH=~/local_bridge_testing/bin/zombienet-linux +fi + +# check if `wait` supports -p flag +if [ `printf "$BASH_VERSION\n5.1" | sort -V | head -n 1` = "5.1" ]; then IS_BASH_5_1=1; else IS_BASH_5_1=0; fi + +# bridge configuration +export LANE_ID="00000002" + +# tests configuration +ALL_TESTS_FOLDER=`mktemp -d /tmp/bridges-zombienet-tests.XXXXX` + +function start_coproc() { + local command=$1 + local name=$2 + local logname=`basename $name` + local coproc_log=`mktemp -p $TEST_FOLDER $logname.XXXXX` + coproc COPROC { + # otherwise zombienet uses some hardcoded paths + unset RUN_IN_CONTAINER + unset ZOMBIENET_IMAGE + + $command >$coproc_log 2>&1 + } + TEST_COPROCS[$COPROC_PID, 0]=$name + TEST_COPROCS[$COPROC_PID, 1]=$coproc_log + echo "Spawned $name coprocess. StdOut + StdErr: $coproc_log" + + return $COPROC_PID +} + +# execute every test from tests folder +TEST_INDEX=$TESTS_BEGIN +while true +do + declare -A TEST_COPROCS + TEST_COPROCS_COUNT=0 + TEST_PREFIX=$(printf "%04d" $TEST_INDEX) + + # it'll be used by the `sync-exit.sh` script + export TEST_FOLDER=`mktemp -d -p $ALL_TESTS_FOLDER test-$TEST_PREFIX.XXXXX` + + # check if there are no more tests + zndsl_files=($BRIDGE_TESTS_FOLDER/$TEST_PREFIX-*.zndsl) + if [ ${#zndsl_files[@]} -eq 0 ]; then + break + fi + + # start tests + for zndsl_file in "${zndsl_files[@]}"; do + start_coproc "$ZOMBIENET_BINARY_PATH --provider native test $zndsl_file" "$zndsl_file" + echo -n "1">>$TEST_FOLDER/exit-sync + ((TEST_COPROCS_COUNT++)) + done + # wait until all tests are completed + for n in `seq 1 $TEST_COPROCS_COUNT`; do + if [ "$IS_BASH_5_1" -eq 1 ]; then + wait -n -p COPROC_PID + exit_code=$? + coproc_name=${TEST_COPROCS[$COPROC_PID, 0]} + coproc_log=${TEST_COPROCS[$COPROC_PID, 1]} + coproc_stdout=$(cat $coproc_log) + else + wait -n + exit_code=$? + coproc_name="" + coproc_stdout="" + fi + echo "Process $coproc_name has finished with exit code: $exit_code" + + # if exit code is not zero, exit + if [ $exit_code -ne 0 ]; then + echo "=====================================================================" + echo "=== Shutting down. Log of failed process below ===" + echo "=====================================================================" + echo "$coproc_stdout" + + exit 1 + fi + done + + # proceed to next index + ((TEST_INDEX++)) + if [ "$TEST_INDEX" -ge "$TESTS_END" ]; then + break + fi + + # kill relay here - it is started manually by tests + killall substrate-relay +done + +echo "=====================================================================" +echo "=== All tests have completed successfully ===" +echo "=====================================================================" diff --git a/bridges/testing/scripts/invoke-script.sh b/bridges/testing/scripts/invoke-script.sh new file mode 100755 index 000000000000..cd0557b071bb --- /dev/null +++ b/bridges/testing/scripts/invoke-script.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +INVOKE_LOG=`mktemp -p $TEST_FOLDER invoke.XXXXX` + +pushd $POLKADOT_SDK_PATH/bridges/testing/environments/rococo-westend +./bridges_rococo_westend.sh $1 >$INVOKE_LOG 2>&1 +popd diff --git a/bridges/testing/scripts/start-relayer.sh b/bridges/testing/scripts/start-relayer.sh new file mode 100755 index 000000000000..38ea62fad524 --- /dev/null +++ b/bridges/testing/scripts/start-relayer.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +RELAY_LOG=`mktemp -p $TEST_FOLDER relay.XXXXX` + +pushd $POLKADOT_SDK_PATH/bridges/testing/environments/rococo-westend +./bridges_rococo_westend.sh run-relay >$RELAY_LOG 2>&1& +popd diff --git a/bridges/testing/scripts/sync-exit.sh b/bridges/testing/scripts/sync-exit.sh new file mode 100755 index 000000000000..cc20b098e783 --- /dev/null +++ b/bridges/testing/scripts/sync-exit.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +# every network adds a char to the file, let's remove ours +truncate -s -1 $TEST_FOLDER/exit-sync + +# when all chars are removed, then our test is done +while true +do + if [ `stat --printf="%s" $TEST_FOLDER/exit-sync` -eq 0 ]; then + exit + fi + sleep 100 +done diff --git a/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl new file mode 100644 index 000000000000..cdb7d28e940c --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/roc-reaches-westend.zndsl @@ -0,0 +1,12 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# send 5 ROC to //Alice from Rococo AH to Westend AH +asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "reserve-transfer-assets-from-asset-hub-rococo-local 5000000000000" within 120 seconds + +# check that //Alice received at least 4.8 ROC on Westend AH +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Rococo" within 600 seconds + +# check that the relayer //Charlie is rewarded by Westend AH +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x6268726F,ThisChain,0" within 30 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/run.sh b/bridges/testing/tests/0001-asset-transfer/run.sh new file mode 100755 index 000000000000..a7bb122919b4 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/run.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +source "${BASH_SOURCE%/*}/../../framework/utils/common.sh" +source "${BASH_SOURCE%/*}/../../framework/utils/zombienet.sh" + +export ENV_PATH=`realpath ${BASH_SOURCE%/*}/../../environments/rococo-westend` + +$ENV_PATH/spawn.sh --init --start-relayer & +env_pid=$! + +ensure_process_file $env_pid $TEST_DIR/rococo.env 600 +rococo_dir=`cat $TEST_DIR/rococo.env` +echo + +ensure_process_file $env_pid $TEST_DIR/westend.env 300 +westend_dir=`cat $TEST_DIR/westend.env` +echo + +run_zndsl ${BASH_SOURCE%/*}/roc-reaches-westend.zndsl $westend_dir +run_zndsl ${BASH_SOURCE%/*}/wnd-reaches-rococo.zndsl $rococo_dir + +run_zndsl ${BASH_SOURCE%/*}/wroc-reaches-rococo.zndsl $rococo_dir +run_zndsl ${BASH_SOURCE%/*}/wwnd-reaches-westend.zndsl $westend_dir diff --git a/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl new file mode 100644 index 000000000000..dbc03864e2b6 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/wnd-reaches-rococo.zndsl @@ -0,0 +1,12 @@ +Description: User is able to transfer WND from Westend Asset Hub to Rococo Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_rococo_local_network.toml +Creds: config + +# send 5 WND to //Alice from Westend AH to Rococo AH +asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "reserve-transfer-assets-from-asset-hub-westend-local 5000000000000" within 120 seconds + +# check that //Alice received at least 4.8 WND on Rococo AH +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,4800000000000,Westend" within 600 seconds + +# check that the relayer //Charlie is rewarded by Rococo AH +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000002,0x62687764,ThisChain,0" within 30 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl b/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl new file mode 100644 index 000000000000..9967732cabe1 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/wroc-reaches-rococo.zndsl @@ -0,0 +1,10 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# send 3 wROC back to Alice from Westend AH to Rococo AH +asset-hub-rococo-collator1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-assets-from-asset-hub-westend-local 3000000000000" within 120 seconds + +# check that //Alice received at least 2.8 wROC on Rococo AH +# (we wait until //Alice account increases here - there are no other transactions that may increase it) +asset-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 600 seconds diff --git a/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl b/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl new file mode 100644 index 000000000000..2037b0baf3c0 --- /dev/null +++ b/bridges/testing/tests/0001-asset-transfer/wwnd-reaches-westend.zndsl @@ -0,0 +1,10 @@ +Description: User is able to transfer ROC from Rococo Asset Hub to Westend Asset Hub and back +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# send 3 wWND back to Alice from Rococo AH to Westend AH +asset-hub-westend-collator1: run {{ENV_PATH}}/helper.sh with "withdraw-reserve-assets-from-asset-hub-rococo-local 3000000000000" within 120 seconds + +# check that //Alice received at least 2.8 wWND on Westend AH +# (we wait until //Alice account increases here - there are no other transactions that may increase it) +asset-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/native-assets-balance-increased.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,2800000000000" within 600 seconds diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/rococo-to-westend.zndsl b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/rococo-to-westend.zndsl new file mode 100644 index 000000000000..6e381f537732 --- /dev/null +++ b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/rococo-to-westend.zndsl @@ -0,0 +1,8 @@ +Description: While relayer is idle, we only sync mandatory Rococo (and a single Rococo BH) headers to Westend BH. +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# ensure that relayer is only syncing mandatory headers while idle. This includes both headers that were +# generated while relay was offline and those in the next 100 seconds while script is active. +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/only-mandatory-headers-synced-when-idle.js with "300,rococo-at-westend" within 600 seconds + diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh new file mode 100755 index 000000000000..7d5b8d927366 --- /dev/null +++ b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/run.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set -e + +source "${BASH_SOURCE%/*}/../../framework/utils/common.sh" +source "${BASH_SOURCE%/*}/../../framework/utils/zombienet.sh" + +export ENV_PATH=`realpath ${BASH_SOURCE%/*}/../../environments/rococo-westend` + +$ENV_PATH/spawn.sh & +env_pid=$! + +ensure_process_file $env_pid $TEST_DIR/rococo.env 600 +rococo_dir=`cat $TEST_DIR/rococo.env` +echo + +ensure_process_file $env_pid $TEST_DIR/westend.env 300 +westend_dir=`cat $TEST_DIR/westend.env` +echo + +# Sleep for some time before starting the relayer. We want to sleep for at least 1 session, +# which is expected to be 60 seconds for the test environment. +echo -e "Sleeping 90s before starting relayer ...\n" +sleep 90 +${BASH_SOURCE%/*}/../../environments/rococo-westend/start_relayer.sh $rococo_dir $westend_dir relayer_pid + +# Sometimes the relayer syncs multiple parachain heads in the begining leading to test failures. +# See issue: https://github.com/paritytech/parity-bridges-common/issues/2838. +# TODO: Remove this sleep after the issue is fixed. +echo -e "Sleeping 180s before runing the tests ...\n" +sleep 180 + +run_zndsl ${BASH_SOURCE%/*}/rococo-to-westend.zndsl $westend_dir +run_zndsl ${BASH_SOURCE%/*}/westend-to-rococo.zndsl $rococo_dir + diff --git a/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl new file mode 100644 index 000000000000..b4b3e4367916 --- /dev/null +++ b/bridges/testing/tests/0002-mandatory-headers-synced-while-idle/westend-to-rococo.zndsl @@ -0,0 +1,7 @@ +Description: While relayer is idle, we only sync mandatory Westend (and a single Westend BH) headers to Rococo BH. +Network: {{ENV_PATH}}/bridge_hub_rococo_local_network.toml +Creds: config + +# ensure that relayer is only syncing mandatory headers while idle. This includes both headers that were +# generated while relay was offline and those in the next 100 seconds while script is active. +bridge-hub-rococo-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/only-mandatory-headers-synced-when-idle.js with "300,westend-at-rococo" within 600 seconds diff --git a/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl b/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl new file mode 100644 index 000000000000..07b91481dc7c --- /dev/null +++ b/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl @@ -0,0 +1,26 @@ +Description: While relayer is active, we only sync mandatory and required Rococo (and Rococo BH) headers to Westend BH. +Network: ../environments/rococo-westend/bridge_hub_westend_local_network.toml +Creds: config + +# step 1: initialize Westend AH +asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-westend-local" within 60 seconds + +# step 2: initialize Westend bridge hub +bridge-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-westend-local" within 60 seconds + +# step 3: ensure that initialization has completed +asset-hub-westend-collator1: js-script ../js-helpers/wait-hrmp-channel-opened.js with "1002" within 600 seconds + +# step 4: send message from Westend to Rococo +asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-westend-local" within 60 seconds + +# step 5: start relayer +# (we are starting it after sending the message to be sure that relayer won't relay messages before our js script +# will be started at step 6) +# (it is started by sibling 0003-required-headers-synced-while-active-westend-to-rococo.zndsl) + +# step 6: ensure that relayer won't sync any extra headers while delivering messages and confirmations +bridge-hub-westend-collator1: js-script ../js-helpers/only-required-headers-synced-when-active.js with "500,rococo-at-westend" within 600 seconds + +# wait until other network test has completed OR exit with an error too +asset-hub-westend-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl b/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl new file mode 100644 index 000000000000..a6b11fc24052 --- /dev/null +++ b/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl @@ -0,0 +1,26 @@ +Description: While relayer is active, we only sync mandatory and required Westend (and Westend BH) headers to Rococo BH. +Network: ../environments/rococo-westend/bridge_hub_rococo_local_network.toml +Creds: config + +# step 1: initialize Rococo AH +asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-rococo-local" within 60 seconds + +# step 2: initialize Rococo bridge hub +bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 60 seconds + +# step 3: ensure that initialization has completed +asset-hub-rococo-collator1: js-script ../js-helpers/wait-hrmp-channel-opened.js with "1013" within 600 seconds + +# step 4: send message from Rococo to Westend +asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-rococo-local" within 60 seconds + +# step 5: start relayer +# (we are starting it after sending the message to be sure that relayer won't relay messages before our js script +# will be started at step 6) +bridge-hub-rococo-collator1: run ../scripts/start-relayer.sh within 60 seconds + +# step 6: ensure that relayer won't sync any extra headers while delivering messages and confirmations +bridge-hub-rococo-collator1: js-script ../js-helpers/only-required-headers-synced-when-active.js with "500,westend-at-rococo" within 600 seconds + +# wait until other network test has completed OR exit with an error too +asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds