From 446e29aa27e834de845fbfd32777a8b86fafa665 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:37:39 +0300 Subject: [PATCH 01/38] wip --- Cargo.toml | 1 + libs/mocks/src/liquidity_pools.rs | 8 +- .../src/liquidity_pools_gateway_routers.rs | 0 libs/traits/src/liquidity_pools.rs | 5 + pallets/liquidity-pools-gateway/Cargo.toml | 3 + pallets/liquidity-pools-gateway/src/lib.rs | 299 ++++++- .../liquidity-pools-gateway/src/message.rs | 8 +- pallets/liquidity-pools-gateway/src/mock.rs | 55 +- pallets/liquidity-pools-gateway/src/tests.rs | 731 ++++++++++++++++-- .../liquidity-pools-gateway/src/weights.rs | 36 + pallets/liquidity-pools/src/message.rs | 19 +- 11 files changed, 1083 insertions(+), 82 deletions(-) create mode 100644 libs/mocks/src/liquidity_pools_gateway_routers.rs diff --git a/Cargo.toml b/Cargo.toml index f5cac551f1..9e6599e871 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,7 @@ impl-trait-for-tuples = "0.2.2" num-traits = { version = "0.2.17", default-features = false } num_enum = { version = "0.5.3", default-features = false } chrono = { version = "0.4", default-features = false } +itertools = { version = "0.13.0", default-features = false } # Cumulus cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, branch = "release-polkadot-v1.7.2" } diff --git a/libs/mocks/src/liquidity_pools.rs b/libs/mocks/src/liquidity_pools.rs index acee16d4db..dcae66f60f 100644 --- a/libs/mocks/src/liquidity_pools.rs +++ b/libs/mocks/src/liquidity_pools.rs @@ -2,7 +2,7 @@ pub mod pallet { use cfg_traits::liquidity_pools::InboundMessageHandler; use frame_support::pallet_prelude::*; - use mock_builder::{execute_call, register_call}; + use mock_builder::{execute_call, register_call, CallHandler}; #[pallet::config] pub trait Config: frame_system::Config { @@ -17,8 +17,10 @@ pub mod pallet { type CallIds = StorageMap<_, _, String, mock_builder::CallId>; impl Pallet { - pub fn mock_handle(f: impl Fn(T::DomainAddress, T::Message) -> DispatchResult + 'static) { - register_call!(move |(sender, msg)| f(sender, msg)); + pub fn mock_handle( + f: impl Fn(T::DomainAddress, T::Message) -> DispatchResult + 'static, + ) -> CallHandler { + register_call!(move |(sender, msg)| f(sender, msg)) } } diff --git a/libs/mocks/src/liquidity_pools_gateway_routers.rs b/libs/mocks/src/liquidity_pools_gateway_routers.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/traits/src/liquidity_pools.rs b/libs/traits/src/liquidity_pools.rs index 0a90a072f9..607e90aa51 100644 --- a/libs/traits/src/liquidity_pools.rs +++ b/libs/traits/src/liquidity_pools.rs @@ -15,6 +15,8 @@ use frame_support::{dispatch::DispatchResult, weights::Weight}; use sp_runtime::DispatchError; use sp_std::vec::Vec; +pub type Proof = [u8; 32]; + /// An encoding & decoding trait for the purpose of meeting the /// LiquidityPools General Message Passing Format pub trait LPEncoding: Sized { @@ -31,6 +33,9 @@ pub trait LPEncoding: Sized { /// Creates an empty message. /// It's the identity message for composing messages with pack_with fn empty() -> Self; + + fn get_message_proof(&self) -> Option; + fn to_message_proof(&self) -> Self; } pub trait RouterSupport: Sized { diff --git a/pallets/liquidity-pools-gateway/Cargo.toml b/pallets/liquidity-pools-gateway/Cargo.toml index 5f01d96284..f5b0356569 100644 --- a/pallets/liquidity-pools-gateway/Cargo.toml +++ b/pallets/liquidity-pools-gateway/Cargo.toml @@ -35,6 +35,9 @@ cfg-utils = { workspace = true } [dev-dependencies] cfg-mocks = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } +itertools = { workspace = true, default-features = true } +lazy_static = { workspace = true, default-features = true } +mock-builder = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index f1b1c62336..80f126334e 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -39,8 +39,9 @@ use frame_system::pallet_prelude::{ensure_signed, OriginFor}; use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; -use parity_scale_codec::FullCodec; -use sp_std::{convert::TryInto, vec::Vec}; +use parity_scale_codec::{EncodeLike, FullCodec}; +use sp_runtime::traits::EnsureAddAssign; +use sp_std::{cmp::Ordering, convert::TryInto, vec::Vec}; use crate::weights::WeightInfo; @@ -117,7 +118,13 @@ pub mod pallet { type Sender: Get; /// Type used for queueing messages. - type MessageQueue: MessageQueue>; + type MessageQueue: MessageQueue< + Message = GatewayMessage, + >; + + /// Number of routers for a domain. + #[pallet::constant] + type MultiRouterCount: Get; } #[pallet::event] @@ -134,6 +141,12 @@ pub mod pallet { domain: Domain, hook_address: [u8; 20], }, + + /// The routers for a given domain were set. + DomainMultiRouterSet { + domain: Domain, + routers: BoundedVec, + }, } /// Storage that contains a limited number of whitelisted instances of @@ -161,6 +174,34 @@ pub mod pallet { pub(crate) type PackedMessage = StorageMap<_, Blake2_128Concat, (T::AccountId, Domain), T::Message>; + /// Storage for routers. + /// + /// This can only be set by an admin. + #[pallet::storage] + #[pallet::getter(fn routers)] + pub type Routers = StorageMap<_, Blake2_128Concat, T::Hash, T::Router>; + + /// Storage for domain multi-routers. + /// + /// This can only be set by an admin. + #[pallet::storage] + #[pallet::getter(fn domain_multi_routers)] + pub type DomainMultiRouters = + StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; + + /// Storage that keeps track of incoming message proofs. + #[pallet::storage] + #[pallet::getter(fn inbound_message_proof_count)] + pub type InboundMessageProofCount = + StorageMap<_, Blake2_128Concat, Proof, u32, ValueQuery>; + + /// Storage that keeps track of incoming messages and the expected proof + /// count. + #[pallet::storage] + #[pallet::getter(fn inbound_messages)] + pub type InboundMessages = + StorageMap<_, Blake2_128Concat, Proof, (DomainAddress, T::Message, u32)>; + #[pallet::error] pub enum Error { /// The origin of the message to be processed is invalid. @@ -188,6 +229,18 @@ pub mod pallet { /// Emitted when you can `end_batch_message()` but the packing process /// was not started by `start_batch_message()`. MessagePackingNotStarted, + + /// Invalid multi router. + InvalidMultiRouter, + + /// Multi-router not found. + MultiRouterNotFound, + + /// Message proof cannot be retrieved. + MessageProofRetrieval, + + /// Recovery message not found. + RecoveryMessageNotFound, } #[pallet::call] @@ -254,7 +307,7 @@ pub mod pallet { /// Set the address of the domain hook /// /// Can only be called by `AdminOrigin`. - #[pallet::weight(T::WeightInfo::set_domain_router())] + #[pallet::weight(T::WeightInfo::set_domain_hook_address())] #[pallet::call_index(8)] pub fn set_domain_hook_address( origin: OriginFor, @@ -305,9 +358,136 @@ pub mod pallet { None => Err(Error::::MessagePackingNotStarted.into()), } } + + /// Set routers for a particular domain. + #[pallet::weight(T::WeightInfo::set_domain_multi_router())] + #[pallet::call_index(11)] + pub fn set_domain_multi_router( + origin: OriginFor, + domain: Domain, + routers: BoundedVec, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + + ensure!(domain != Domain::Centrifuge, Error::::DomainNotSupported); + ensure!( + routers.len() == T::MultiRouterCount::get() as usize, + Error::::InvalidMultiRouter + ); + + let mut router_hashes = Vec::new(); + + for router in &routers { + router.init().map_err(|_| Error::::RouterInitFailed)?; + + let router_hash = router.hash(); + + router_hashes.push(router_hash); + + Routers::::insert(router_hash, router); + } + + >::insert( + domain.clone(), + BoundedVec::try_from(router_hashes).map_err(|_| Error::::InvalidMultiRouter)?, + ); + + Self::clear_storages_for_inbound_messages(); + + Self::deposit_event(Event::DomainMultiRouterSet { domain, routers }); + + Ok(()) + } + + /// Manually increase the proof count for a particular message and + /// executes it if the required count is reached. + /// + /// Can only be called by `AdminOrigin`. + #[pallet::weight(T::WeightInfo::execute_message_recovery())] + #[pallet::call_index(12)] + pub fn execute_message_recovery( + origin: OriginFor, + message_proof: Proof, + proof_count: u32, + ) -> DispatchResult { + //TODO(cdamian): Implement this. + unimplemented!() + } } impl Pallet { + fn clear_storages_for_inbound_messages() { + let _ = InboundMessages::::clear(u32::MAX, None); + let _ = InboundMessageProofCount::::clear(u32::MAX, None); + } + + //TODO(cdamian): Use safe math + fn get_expected_message_proof_count() -> u32 { + T::MultiRouterCount::get() - 1 + } + + /// Inserts a message and its expected proof count, or increases the + /// message proof count for a particular message. + fn get_proof_and_current_count( + domain_address: DomainAddress, + message: T::Message, + weight: &mut Weight, + ) -> Result<(Proof, u32), DispatchError> { + match message.get_message_proof() { + None => { + let message_proof = message + .to_message_proof() + .get_message_proof() + .expect("message proof ensured by 'to_message_proof'"); + + match InboundMessages::::try_mutate(message_proof, |storage_entry| { + match storage_entry { + None => { + *storage_entry = Some(( + domain_address, + message, + Self::get_expected_message_proof_count(), + )); + } + Some((_, _, expected_proof_count)) => { + // We already have a message, in this case we should expect another + // set of message proofs. + expected_proof_count + .ensure_add_assign(Self::get_expected_message_proof_count())?; + } + }; + + Ok(()) + }) { + Ok(_) => {} + Err(e) => return Err(e), + }; + + *weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + + Ok(( + message_proof, + InboundMessageProofCount::::get(message_proof), + )) + } + Some(message_proof) => { + let message_proof_count = + match InboundMessageProofCount::::try_mutate(message_proof, |count| { + count.ensure_add_assign(1)?; + + Ok(*count) + }) { + Ok(r) => r, + Err(e) => return Err(e), + }; + + *weight = weight.saturating_add(T::DbWeight::get().writes(1)); + + Ok((message_proof, message_proof_count)) + } + } + } + /// Give the message to the `InboundMessageHandler` to be processed. fn process_inbound_message( domain_address: DomainAddress, @@ -318,6 +498,69 @@ pub mod pallet { for submessage in message.submessages() { count += 1; + let (message_proof, mut current_message_proof_count) = + match Self::get_proof_and_current_count( + domain_address.clone(), + message.clone(), + &mut weight, + ) { + Ok(r) => r, + Err(e) => return (Err(e), weight), + }; + + let (_, message, mut total_expected_proof_count) = + match InboundMessages::::get(message_proof) { + None => return (Ok(()), weight), + Some(r) => r, + }; + + weight = weight.saturating_add(T::DbWeight::get().reads(1)); + + let expected_message_proof_count = Self::get_expected_message_proof_count(); + + match current_message_proof_count.cmp(&expected_message_proof_count) { + Ordering::Less => return (Ok(()), weight), + Ordering::Equal => { + InboundMessageProofCount::::remove(message_proof); + total_expected_proof_count -= expected_message_proof_count; + + if total_expected_proof_count == 0 { + InboundMessages::::remove(message_proof); + } else { + InboundMessages::::insert( + message_proof, + ( + domain_address.clone(), + message.clone(), + total_expected_proof_count, + ), + ); + } + } + Ordering::Greater => { + current_message_proof_count -= expected_message_proof_count; + InboundMessageProofCount::::insert( + message_proof, + current_message_proof_count, + ); + + total_expected_proof_count -= expected_message_proof_count; + + if total_expected_proof_count == 0 { + InboundMessages::::remove(message_proof); + } else { + InboundMessages::::insert( + message_proof, + ( + domain_address.clone(), + message.clone(), + total_expected_proof_count, + ), + ); + } + } + } + if let Err(e) = T::InboundMessageHandler::handle(domain_address.clone(), submessage) { // We only consume the processed weight if error during the batch @@ -332,13 +575,15 @@ pub mod pallet { /// message using the router, and calculates and returns the required /// weight for these operations in the `DispatchResultWithPostInfo`. fn process_outbound_message( - sender: DomainAddress, - domain: Domain, + sender: T::AccountId, message: T::Message, + router_hash: T::Hash, ) -> (DispatchResult, Weight) { let router_ids = T::RouterId::for_domain(domain); - // TODO handle router ids logic + let Some(router) = Routers::::get(router_hash) else { + return (Err(Error::::RouterNotFound.into()), read_weight); + }; let mut count = 0; let bytes = message.serialize(); @@ -355,15 +600,33 @@ pub mod pallet { } fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { - // We are using the sender specified in the pallet config so that we can - // ensure that the account is funded - let gateway_message = GatewayMessage::::Outbound { - sender: T::Sender::get(), - destination, - message, - }; + let router_hashes = DomainMultiRouters::::get(destination.clone()) + .ok_or(Error::::MultiRouterNotFound)?; + + let message_proof = message.to_message_proof(); + let mut message_opt = Some(message); + + for router_hash in router_hashes { + // Ensure that we only send the actual message once, using one router. + // The remaining routers will send the message proof. + let router_msg = match message_opt.take() { + Some(m) => m, + None => message_proof.clone(), + }; + + // We are using the sender specified in the pallet config so that we can + // ensure that the account is funded + let gateway_message = + GatewayMessage::::Outbound { + sender: T::Sender::get(), + message: router_msg, + router_hash, + }; + + T::MessageQueue::submit(gateway_message)?; + } - T::MessageQueue::submit(gateway_message) + Ok(()) } } @@ -396,7 +659,7 @@ pub mod pallet { } impl MessageProcessor for Pallet { - type Message = GatewayMessage; + type Message = GatewayMessage; fn process(msg: Self::Message) -> (DispatchResult, Weight) { match msg { @@ -406,9 +669,9 @@ pub mod pallet { } => Self::process_inbound_message(domain_address, message), GatewayMessage::Outbound { sender, - destination, message, - } => Self::process_outbound_message(sender, destination, message), + router_hash, + } => Self::process_outbound_message(sender, message, router_hash), } } diff --git a/pallets/liquidity-pools-gateway/src/message.rs b/pallets/liquidity-pools-gateway/src/message.rs index 505e075b0f..a2f568c23e 100644 --- a/pallets/liquidity-pools-gateway/src/message.rs +++ b/pallets/liquidity-pools-gateway/src/message.rs @@ -3,19 +3,19 @@ use frame_support::pallet_prelude::{Decode, Encode, MaxEncodedLen, TypeInfo}; /// Message type used by the LP gateway. #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] -pub enum GatewayMessage { +pub enum GatewayMessage { Inbound { domain_address: DomainAddress, message: Message, }, Outbound { - sender: DomainAddress, - destination: Domain, + sender: AccountId, message: Message, + router_hash: Hash, }, } -impl Default for GatewayMessage { +impl Default for GatewayMessage { fn default() -> Self { GatewayMessage::Inbound { domain_address: Default::default(), diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 1ea75c1885..ae85e34c0c 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -1,6 +1,11 @@ -use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_liquidity_pools_gateway_queue}; -use cfg_traits::liquidity_pools::{LPEncoding, RouterSupport}; -use cfg_types::domain_address::{Domain, DomainAddress}; +use std::fmt::{Debug, Formatter}; + +use cfg_mocks::{ + pallet_mock_liquidity_pools, pallet_mock_liquidity_pools_gateway_queue, pallet_mock_routers, + RouterMock, +}; +use cfg_traits::liquidity_pools::{LPEncoding, Proof}; +use cfg_types::domain_address::DomainAddress; use frame_support::{derive_impl, weights::constants::RocksDbWeight}; use frame_system::EnsureRoot; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -15,11 +20,24 @@ pub const LP_ADMIN_ACCOUNT: AccountId32 = AccountId32::new([u8::MAX; 32]); pub const MAX_PACKED_MESSAGES_ERR: &str = "packed limit error"; pub const MAX_PACKED_MESSAGES: usize = 10; -#[derive(Default, Debug, Eq, PartialEq, Clone, Encode, Decode, TypeInfo)] +pub const MESSAGE_PROOF: [u8; 32] = [1; 32]; + +#[derive(Default, Eq, PartialEq, Clone, Encode, Decode, TypeInfo, Hash)] pub enum Message { #[default] Simple, Pack(Vec), + Proof([u8; 32]), +} + +impl Debug for Message { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Message::Simple => write!(f, "Simple"), + Message::Pack(p) => write!(f, "Pack - {:?}", p), + Message::Proof(_) => write!(f, "Proof"), + } + } } /// Avoiding automatic infinity loop with the MaxEncodedLen derive @@ -32,8 +50,8 @@ impl MaxEncodedLen for Message { impl LPEncoding for Message { fn serialize(&self) -> Vec { match self { - Self::Simple => vec![0x42], Self::Pack(list) => list.iter().map(|_| 0x42).collect(), + _ => vec![0x42], } } @@ -47,10 +65,6 @@ impl LPEncoding for Message { fn pack_with(&mut self, other: Self) -> DispatchResult { match self { - Self::Simple => { - *self = Self::Pack(vec![Self::Simple, other]); - Ok(()) - } Self::Pack(list) if list.len() == MAX_PACKED_MESSAGES => { Err(MAX_PACKED_MESSAGES_ERR.into()) } @@ -58,19 +72,37 @@ impl LPEncoding for Message { list.push(other); Ok(()) } + _ => { + *self = Self::Pack(vec![self.clone(), other]); + Ok(()) + } } } fn submessages(&self) -> Vec { match self { - Self::Simple => vec![Self::Simple], Self::Pack(list) => list.clone(), + _ => vec![self.clone()], } } fn empty() -> Self { Self::Pack(vec![]) } + + fn get_message_proof(&self) -> Option { + match self { + Message::Proof(p) => Some(p.clone()), + _ => None, + } + } + + fn to_message_proof(&self) -> Self { + match self { + Message::Proof(_) => self.clone(), + _ => Message::Proof(MESSAGE_PROOF), + } + } } #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] @@ -118,6 +150,7 @@ frame_support::parameter_types! { pub Sender: DomainAddress = DomainAddress::Centrifuge(AccountId32::from(H256::from_low_u64_be(1).to_fixed_bytes()).into()); pub const MaxIncomingMessageSize: u32 = 1024; pub const LpAdminAccount: AccountId32 = LP_ADMIN_ACCOUNT; + pub const MultiRouterCount: u32 = 3; } impl pallet_liquidity_pools_gateway::Config for Runtime { @@ -127,6 +160,8 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type MaxIncomingMessageSize = MaxIncomingMessageSize; type Message = Message; type MessageQueue = MockLiquidityPoolsGatewayQueue; + type MultiRouterCount = MultiRouterCount; + type Router = RouterMock; type MessageSender = MockMessageSender; type RouterId = RouterId; type RuntimeEvent = RuntimeEvent; diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 61e54fde63..283d49f81f 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -1,13 +1,16 @@ -/* +use std::collections::HashMap; + use cfg_mocks::*; -use cfg_primitives::LP_DEFENSIVE_WEIGHT; -use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler}; +use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler, Proof}; use cfg_types::domain_address::*; use frame_support::{ assert_err, assert_noop, assert_ok, dispatch::PostDispatchInfo, pallet_prelude::Pays, weights::Weight, }; -use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160}; +use itertools::Itertools; +use lazy_static::lazy_static; +use parity_scale_codec::MaxEncodedLen; +use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160, H256}; use sp_runtime::{DispatchError, DispatchError::BadOrigin, DispatchErrorWithPostInfo}; use sp_std::sync::{ atomic::{AtomicU32, Ordering}, @@ -290,7 +293,7 @@ mod receive_message_domain { let encoded_msg = message.serialize(); - let gateway_message = GatewayMessage::::Inbound { + let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), }; @@ -371,7 +374,7 @@ mod receive_message_domain { let err = sp_runtime::DispatchError::from("liquidity_pools error"); - let gateway_message = GatewayMessage::::Inbound { + let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), }; @@ -401,24 +404,47 @@ mod outbound_message_handler_impl { let domain = Domain::EVM(0); let sender = get_test_account_id(); let msg = Message::Simple; + let message_proof = msg.to_message_proof().get_message_proof().unwrap(); - let router = RouterMock::::default(); - router.mock_init(move || Ok(())); + let router_hash_1 = H256::from_low_u64_be(1); + let router_hash_2 = H256::from_low_u64_be(2); + let router_hash_3 = H256::from_low_u64_be(3); - assert_ok!(LiquidityPoolsGateway::set_domain_router( + let router_mock_1 = RouterMock::::default(); + let router_mock_2 = RouterMock::::default(); + let router_mock_3 = RouterMock::::default(); + + router_mock_1.mock_init(move || Ok(())); + router_mock_1.mock_hash(move || router_hash_1); + router_mock_2.mock_init(move || Ok(())); + router_mock_2.mock_hash(move || router_hash_2); + router_mock_3.mock_init(move || Ok(())); + router_mock_3.mock_hash(move || router_hash_3); + + assert_ok!(LiquidityPoolsGateway::set_domain_multi_router( RuntimeOrigin::root(), domain.clone(), - router.clone(), + BoundedVec::try_from(vec![router_mock_1, router_mock_2, router_mock_3]).unwrap(), )); - let gateway_message = GatewayMessage::::Outbound { - sender: ::Sender::get(), - destination: domain.clone(), - message: msg.clone(), - }; - MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { - assert_eq!(mock_msg, gateway_message); + match mock_msg { + GatewayMessage::Inbound { .. } => { + assert!(false, "expected outbound message") + } + GatewayMessage::Outbound { + sender, message, .. + } => { + assert_eq!(sender, ::Sender::get()); + + match message { + Message::Proof(p) => { + assert_eq!(p, message_proof); + } + _ => {} + } + } + } Ok(()) }); @@ -448,19 +474,31 @@ mod outbound_message_handler_impl { let sender = get_test_account_id(); let msg = Message::Simple; - let router = RouterMock::::default(); - router.mock_init(move || Ok(())); + let router_hash_1 = H256::from_low_u64_be(1); + let router_hash_2 = H256::from_low_u64_be(2); + let router_hash_3 = H256::from_low_u64_be(3); - assert_ok!(LiquidityPoolsGateway::set_domain_router( + let router_mock_1 = RouterMock::::default(); + let router_mock_2 = RouterMock::::default(); + let router_mock_3 = RouterMock::::default(); + + router_mock_1.mock_init(move || Ok(())); + router_mock_1.mock_hash(move || router_hash_1); + router_mock_2.mock_init(move || Ok(())); + router_mock_2.mock_hash(move || router_hash_2); + router_mock_3.mock_init(move || Ok(())); + router_mock_3.mock_hash(move || router_hash_3); + + assert_ok!(LiquidityPoolsGateway::set_domain_multi_router( RuntimeOrigin::root(), domain.clone(), - router.clone(), + BoundedVec::try_from(vec![router_mock_1, router_mock_2, router_mock_3]).unwrap(), )); - let gateway_message = GatewayMessage::::Outbound { + let gateway_message = GatewayMessage::Outbound { sender: ::Sender::get(), - destination: domain.clone(), message: msg.clone(), + router_hash: router_hash_3, }; let err = DispatchError::Unavailable; @@ -531,34 +569,634 @@ mod message_processor_impl { mod inbound { use super::*; + #[macro_use] + mod util { + use super::*; + + macro_rules! run_tests { + ($tests:expr) => { + // $tests = Vec<(Vec, &ExpectedTestResult)> + for test in $tests { + new_test_ext().execute_with(|| { + println!("Executing test for - {:?}", test.0); + + let handler = MockLiquidityPools::mock_handle(move |_, _| Ok(())); + + // test.0 = Vec + for test_message in test.0 { + let domain_address = DomainAddress::EVM(1, [1; 20]); + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: test_message.clone(), + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_ok!(res); + } + + assert_eq!(handler.times(), test.1.mock_called_times); + + assert_eq!( + InboundMessages::::get(MESSAGE_PROOF), + // test.1 = &ExpectedTestResult + test.1.inbound_message, + ); + assert_eq!( + InboundMessageProofCount::::get(MESSAGE_PROOF), + // test.1 = &ExpectedTestResult + test.1.proof_count, + ); + }); + } + }; + } + + lazy_static! { + static ref TEST_MESSAGES: Vec = + vec![Message::Simple, Message::Proof(MESSAGE_PROOF),]; + } + + /// Generate all `Message` combinations for a specific + /// number of messages, like: + /// + /// vec![ + /// Message::Simple, + /// Message::Simple, + /// ] + /// vec![ + /// Message::Simple, + /// Message::Proof(MESSAGE_PROOF), + /// ] + /// vec![ + /// Message::Proof(MESSAGE_PROOF), + /// Message::Simple, + /// ] + /// vec![ + /// Message::Proof(MESSAGE_PROOF), + /// Message::Proof(MESSAGE_PROOF), + /// ] + pub fn generate_test_combinations(count: usize) -> Vec> { + std::iter::repeat(TEST_MESSAGES.clone().into_iter()) + .take(count) + .multi_cartesian_product() + .collect::>() + } + + pub struct ExpectedTestResult { + pub inbound_message: Option<(DomainAddress, Message, u32)>, + pub proof_count: u32, + pub mock_called_times: u32, + } + } + + use util::*; + + mod combined_messages { + use super::*; + + mod two_messages { + use super::*; + + lazy_static! { + static ref TEST_MAP: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![Message::Simple, Message::Simple], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 4 + )), + proof_count: 0, + mock_called_times: 0, + } + ), + ( + vec![Message::Proof(MESSAGE_PROOF), Message::Proof(MESSAGE_PROOF)], + ExpectedTestResult { + inbound_message: None, + proof_count: 2, + mock_called_times: 0, + } + ), + ( + vec![Message::Simple, Message::Proof(MESSAGE_PROOF)], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ( + vec![Message::Proof(MESSAGE_PROOF), Message::Simple], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ]); + } + + #[test] + fn two_messages() { + let tests = generate_test_combinations(2) + .iter() + .map(|x| { + ( + x.clone(), + TEST_MAP + .get(x) + .expect(format!("test for {x:?} should be covered").as_str()), + ) + }) + .collect::>(); + + run_tests!(tests); + } + } + + mod three_messages { + use super::*; + + lazy_static! { + static ref TEST_MAP: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![Message::Simple, Message::Simple, Message::Simple,], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 6 + )), + proof_count: 0, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 3, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Simple, + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 4 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 4 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Simple, + Message::Simple, + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 4 + )), + proof_count: 1, + mock_called_times: 0, + } + ) + ]); + } + + #[test] + fn three_messages() { + let tests = generate_test_combinations(3) + .iter() + .map(|x| { + ( + x.clone(), + TEST_MAP + .get(x) + .expect(format!("test for {x:?} should be covered").as_str()), + ) + }) + .collect::>(); + + run_tests!(tests); + } + } + + mod four_messages { + use super::*; + + lazy_static! { + static ref TEST_MAP: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + Message::Simple, + Message::Simple, + Message::Simple, + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 8 + )), + proof_count: 0, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 4, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 1, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 1, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 1, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Simple, + ], + ExpectedTestResult { + inbound_message: None, + proof_count: 1, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Simple, + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Simple, + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 2 + )), + proof_count: 0, + mock_called_times: 1, + } + ), + ( + vec![ + Message::Simple, + Message::Simple, + Message::Simple, + Message::Proof(MESSAGE_PROOF), + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 6 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Simple, + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 6 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 6 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ( + vec![ + Message::Proof(MESSAGE_PROOF), + Message::Simple, + Message::Simple, + Message::Simple, + ], + ExpectedTestResult { + inbound_message: Some(( + DomainAddress::EVM(1, [1; 20]), + Message::Simple, + 6 + )), + proof_count: 1, + mock_called_times: 0, + } + ), + ]); + } + + #[test] + fn four_messages() { + let tests = generate_test_combinations(4) + .iter() + .filter(|x| TEST_MAP.get(x.clone()).is_some()) + .map(|x| { + ( + x.clone(), + TEST_MAP + .get(x) + .expect(format!("test for {x:?} should be covered").as_str()), + ) + }) + .collect::>(); + + run_tests!(tests); + } + } + } + #[test] - fn success() { + fn two_non_proof_and_four_proofs() { + let tests = generate_test_combinations(6) + .into_iter() + .filter(|x| { + let r = x.iter().counts_by(|c| c.clone()); + let non_proof_count = r.get(&Message::Simple); + let proof_count = r.get(&Message::Proof(MESSAGE_PROOF)); + + match (non_proof_count, proof_count) { + (Some(non_proof_count), Some(proof_count)) => { + *non_proof_count == 2 && *proof_count == 4 + } + _ => false, + } + }) + .map(|x| { + ( + x, + ExpectedTestResult { + inbound_message: None, + proof_count: 0, + mock_called_times: 2, + }, + ) + }) + .collect::>(); + + run_tests!(tests); + } + + #[test] + fn inbound_message_handler_error() { new_test_ext().execute_with(|| { let domain_address = DomainAddress::EVM(1, [1; 20]); - let message = Message::Simple; - let gateway_message = GatewayMessage::::Inbound { + + let message = Message::Proof(MESSAGE_PROOF); + let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), }; - MockLiquidityPools::mock_handle(move |mock_domain_address, mock_mesage| { - assert_eq!(mock_domain_address, domain_address); - assert_eq!(mock_mesage, message); + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_ok!(res); - Ok(()) - }); + let message = Message::Proof(MESSAGE_PROOF); + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); assert_ok!(res); - }); - } - #[test] - fn inbound_message_handler_error() { - new_test_ext().execute_with(|| { - let domain_address = DomainAddress::EVM(1, [1; 20]); let message = Message::Simple; - let gateway_message = GatewayMessage::::Inbound { + let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), }; @@ -597,6 +1235,8 @@ mod message_processor_impl { pays_fee: Pays::Yes, }; + let router_hash = H256::from_low_u64_be(1); + let router_mock = RouterMock::::default(); router_mock.mock_send(move |mock_sender, mock_message| { assert_eq!(mock_sender, expected_sender); @@ -604,6 +1244,7 @@ mod message_processor_impl { Ok(router_post_info) }); + router_mock.mock_hash(move || router_hash); DomainRouters::::insert(domain.clone(), router_mock); @@ -611,10 +1252,10 @@ mod message_processor_impl { .reads(1) + router_post_info.actual_weight.unwrap() + Weight::from_parts(0, message.serialize().len() as u64); - let gateway_message = GatewayMessage::::Outbound { + let gateway_message = GatewayMessage::Outbound { sender, - destination: domain, message: message.clone(), + router_hash, }; let (res, weight) = LiquidityPoolsGateway::process(gateway_message); @@ -627,15 +1268,14 @@ mod message_processor_impl { fn router_not_found() { new_test_ext().execute_with(|| { let sender = get_test_account_id(); - let domain = Domain::EVM(1); let message = Message::Simple; let expected_weight = ::DbWeight::get().reads(1); - let gateway_message = GatewayMessage::::Outbound { + let gateway_message = GatewayMessage::Outbound { sender, - destination: domain, message, + router_hash: H256::from_low_u64_be(1), }; let (res, weight) = LiquidityPoolsGateway::process(gateway_message); @@ -678,10 +1318,10 @@ mod message_processor_impl { .reads(1) + router_post_info.actual_weight.unwrap() + Weight::from_parts(0, message.serialize().len() as u64); - let gateway_message = GatewayMessage::::Outbound { + let gateway_message = GatewayMessage::Outbound { sender, - destination: domain, message: message.clone(), + router_hash: H256::from_low_u64_be(1), }; let (res, weight) = LiquidityPoolsGateway::process(gateway_message); @@ -850,4 +1490,3 @@ mod batches { }); } } -*/ diff --git a/pallets/liquidity-pools-gateway/src/weights.rs b/pallets/liquidity-pools-gateway/src/weights.rs index b1ac9ed578..ce5650e801 100644 --- a/pallets/liquidity-pools-gateway/src/weights.rs +++ b/pallets/liquidity-pools-gateway/src/weights.rs @@ -23,6 +23,9 @@ pub trait WeightInfo { fn process_failed_outbound_message() -> Weight; fn start_batch_message() -> Weight; fn end_batch_message() -> Weight; + fn set_domain_hook_address() -> Weight; + fn set_domain_multi_router() -> Weight; + fn execute_message_recovery() -> Weight; } // NOTE: We use temporary weights here. `execute_epoch` is by far our heaviest @@ -146,4 +149,37 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(2)) } + + fn set_domain_hook_address() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(30_117_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + + fn set_domain_multi_router() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(30_117_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } + + fn execute_message_recovery() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(30_117_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } } diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 076c8f6250..fac0bed5e8 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -5,7 +5,10 @@ //! also have a custom GMPF implementation, aiming for a fixed-size encoded //! representation for each message variant. -use cfg_traits::{liquidity_pools::LPEncoding, Seconds}; +use cfg_traits::{ + liquidity_pools::{LPEncoding, Proof}, + Seconds, +}; use cfg_types::domain_address::Domain; use frame_support::{pallet_prelude::RuntimeDebug, BoundedVec}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -15,6 +18,7 @@ use serde::{ ser::{Error as _, SerializeTuple}, Deserialize, Serialize, Serializer, }; +use sp_core::{keccak_256, U256}; use sp_runtime::{traits::ConstU32, DispatchError, DispatchResult}; use sp_std::{vec, vec::Vec}; @@ -557,6 +561,19 @@ impl LPEncoding for Message { fn empty() -> Message { Message::Batch(BatchMessages::default()) } + + fn get_message_proof(&self) -> Option { + match self { + Message::MessageProof { hash } => Some(hash.clone()), + _ => None, + } + } + + fn to_message_proof(&self) -> Self { + let hash = keccak_256(&LPEncoding::serialize(self)); + + Message::MessageProof { hash } + } } /// A Liquidity Pool message for updating restrictions on foreign domains. From 38fed75580c68591862bbca1229a6362951b5eec Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:22:44 +0300 Subject: [PATCH 02/38] lp-gateway: Add router hash for inbound messages, extrinsic to set inbound routers, session ID storage --- Cargo.lock | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 3743f9dbbb..b2f3c32cd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5450,6 +5450,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -8233,6 +8242,9 @@ dependencies = [ "frame-support", "frame-system", "hex", + "itertools 0.13.0", + "lazy_static", + "mock-builder", "orml-traits", "parity-scale-codec", "scale-info", From 6cad7997f9cbcc25924bedf4576ddd4683127a0b Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:22:44 +0300 Subject: [PATCH 03/38] lp-gateway: Add router hash for inbound messages, extrinsic to set inbound routers, session ID storage --- Cargo.lock | 1 + pallets/liquidity-pools-gateway/Cargo.toml | 2 + pallets/liquidity-pools-gateway/src/lib.rs | 68 ++++++++++++++++--- .../liquidity-pools-gateway/src/message.rs | 6 +- pallets/liquidity-pools-gateway/src/mock.rs | 1 + pallets/liquidity-pools-gateway/src/tests.rs | 11 ++- .../liquidity-pools-gateway/src/weights.rs | 16 ++++- 7 files changed, 91 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2f3c32cd2..12681bcd7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8248,6 +8248,7 @@ dependencies = [ "orml-traits", "parity-scale-codec", "scale-info", + "sp-arithmetic", "sp-core", "sp-io", "sp-runtime", diff --git a/pallets/liquidity-pools-gateway/Cargo.toml b/pallets/liquidity-pools-gateway/Cargo.toml index f5b0356569..e2caa19652 100644 --- a/pallets/liquidity-pools-gateway/Cargo.toml +++ b/pallets/liquidity-pools-gateway/Cargo.toml @@ -22,6 +22,7 @@ scale-info = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +sp-arithmetic = { workspace = true } # Benchmarking frame-benchmarking = { workspace = true, optional = true } @@ -56,6 +57,7 @@ std = [ "cfg-utils/std", "hex/std", "cfg-primitives/std", + "sp-arithmetic/std", ] try-runtime = [ "cfg-traits/try-runtime", diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 80f126334e..ae71e5be2a 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -40,6 +40,7 @@ use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; use parity_scale_codec::{EncodeLike, FullCodec}; +use sp_arithmetic::traits::BaseArithmetic; use sp_runtime::traits::EnsureAddAssign; use sp_std::{cmp::Ordering, convert::TryInto, vec::Vec}; @@ -125,6 +126,16 @@ pub mod pallet { /// Number of routers for a domain. #[pallet::constant] type MultiRouterCount: Get; + + /// Type for identifying sessions of inbound routers. + type SessionId: Parameter + + Member + + BaseArithmetic + + Default + + Copy + + MaybeSerializeDeserialize + + TypeInfo + + MaxEncodedLen; } #[pallet::event] @@ -142,11 +153,16 @@ pub mod pallet { hook_address: [u8; 20], }, - /// The routers for a given domain were set. - DomainMultiRouterSet { + /// The outbound routers for a given domain were set. + OutboundRoutersSet { domain: Domain, routers: BoundedVec, }, + + /// Inbound routers were set. + InboundRoutersSet { + router_hashes: BoundedVec, + }, } /// Storage that contains a limited number of whitelisted instances of @@ -202,6 +218,14 @@ pub mod pallet { pub type InboundMessages = StorageMap<_, Blake2_128Concat, Proof, (DomainAddress, T::Message, u32)>; + #[pallet::storage] + #[pallet::getter(fn inbound_routers)] + pub type InboundRouters = + StorageValue<_, BoundedVec, ValueQuery>; + + #[pallet::storage] + pub type SessionIdStore = StorageValue<_, T::SessionId, ValueQuery>; + #[pallet::error] pub enum Error { /// The origin of the message to be processed is invalid. @@ -359,10 +383,10 @@ pub mod pallet { } } - /// Set routers for a particular domain. - #[pallet::weight(T::WeightInfo::set_domain_multi_router())] + /// Set outbound routers for a particular domain. + #[pallet::weight(T::WeightInfo::set_outbound_routers())] #[pallet::call_index(11)] - pub fn set_domain_multi_router( + pub fn set_outbound_routers( origin: OriginFor, domain: Domain, routers: BoundedVec, @@ -392,9 +416,33 @@ pub mod pallet { BoundedVec::try_from(router_hashes).map_err(|_| Error::::InvalidMultiRouter)?, ); - Self::clear_storages_for_inbound_messages(); + Self::deposit_event(Event::OutboundRoutersSet { domain, routers }); + + Ok(()) + } + + /// Set inbound routers. + #[pallet::weight(T::WeightInfo::set_inbound_routers())] + #[pallet::call_index(12)] + pub fn set_inbound_routers( + origin: OriginFor, + router_hashes: BoundedVec, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + + ensure!( + router_hashes.len() == T::MultiRouterCount::get() as usize, + Error::::InvalidMultiRouter + ); + + SessionIdStore::::try_mutate(|n| { + n.ensure_add_assign(One::one())?; + Ok::<(), DispatchError>(()) + })?; + + InboundRouters::::set(router_hashes.clone()); - Self::deposit_event(Event::DomainMultiRouterSet { domain, routers }); + Self::deposit_event(Event::InboundRoutersSet { router_hashes }); Ok(()) } @@ -404,7 +452,7 @@ pub mod pallet { /// /// Can only be called by `AdminOrigin`. #[pallet::weight(T::WeightInfo::execute_message_recovery())] - #[pallet::call_index(12)] + #[pallet::call_index(13)] pub fn execute_message_recovery( origin: OriginFor, message_proof: Proof, @@ -492,6 +540,7 @@ pub mod pallet { fn process_inbound_message( domain_address: DomainAddress, message: T::Message, + router_hash: T::Hash, ) -> (DispatchResult, Weight) { let mut count = 0; @@ -666,7 +715,8 @@ pub mod pallet { GatewayMessage::Inbound { domain_address, message, - } => Self::process_inbound_message(domain_address, message), + router_hash, + } => Self::process_inbound_message(domain_address, message, router_hash), GatewayMessage::Outbound { sender, message, diff --git a/pallets/liquidity-pools-gateway/src/message.rs b/pallets/liquidity-pools-gateway/src/message.rs index a2f568c23e..42226a46eb 100644 --- a/pallets/liquidity-pools-gateway/src/message.rs +++ b/pallets/liquidity-pools-gateway/src/message.rs @@ -7,6 +7,7 @@ pub enum GatewayMessage { Inbound { domain_address: DomainAddress, message: Message, + router_hash: Hash, }, Outbound { sender: AccountId, @@ -15,11 +16,14 @@ pub enum GatewayMessage { }, } -impl Default for GatewayMessage { +impl Default + for GatewayMessage +{ fn default() -> Self { GatewayMessage::Inbound { domain_address: Default::default(), message: Default::default(), + router_hash: Default::default(), } } } diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index ae85e34c0c..ec1abe268b 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -167,6 +167,7 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type Sender = Sender; + type SessionId = u64; type WeightInfo = (); } diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 283d49f81f..3c9f056071 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -296,6 +296,7 @@ mod receive_message_domain { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), + router_hash: H256::from_low_u64_be(1), }; MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { @@ -377,6 +378,7 @@ mod receive_message_domain { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), + router_hash: H256::from_low_u64_be(1), }; MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { @@ -421,7 +423,7 @@ mod outbound_message_handler_impl { router_mock_3.mock_init(move || Ok(())); router_mock_3.mock_hash(move || router_hash_3); - assert_ok!(LiquidityPoolsGateway::set_domain_multi_router( + assert_ok!(LiquidityPoolsGateway::set_outbound_routers( RuntimeOrigin::root(), domain.clone(), BoundedVec::try_from(vec![router_mock_1, router_mock_2, router_mock_3]).unwrap(), @@ -489,7 +491,7 @@ mod outbound_message_handler_impl { router_mock_3.mock_init(move || Ok(())); router_mock_3.mock_hash(move || router_hash_3); - assert_ok!(LiquidityPoolsGateway::set_domain_multi_router( + assert_ok!(LiquidityPoolsGateway::set_outbound_routers( RuntimeOrigin::root(), domain.clone(), BoundedVec::try_from(vec![router_mock_1, router_mock_2, router_mock_3]).unwrap(), @@ -588,6 +590,8 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: test_message.clone(), + //TODO(cdamian): Use test router hash. + router_hash: H256::from_low_u64_be(1), }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -1181,6 +1185,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), + router_hash: H256::from_low_u64_be(1), }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -1190,6 +1195,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), + router_hash: H256::from_low_u64_be(1), }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -1199,6 +1205,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), + router_hash: H256::from_low_u64_be(1), }; let err = DispatchError::Unavailable; diff --git a/pallets/liquidity-pools-gateway/src/weights.rs b/pallets/liquidity-pools-gateway/src/weights.rs index ce5650e801..c568dfc4bf 100644 --- a/pallets/liquidity-pools-gateway/src/weights.rs +++ b/pallets/liquidity-pools-gateway/src/weights.rs @@ -24,8 +24,9 @@ pub trait WeightInfo { fn start_batch_message() -> Weight; fn end_batch_message() -> Weight; fn set_domain_hook_address() -> Weight; - fn set_domain_multi_router() -> Weight; + fn set_outbound_routers() -> Weight; fn execute_message_recovery() -> Weight; + fn set_inbound_routers() -> Weight; } // NOTE: We use temporary weights here. `execute_epoch` is by far our heaviest @@ -161,7 +162,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(2)) } - fn set_domain_multi_router() -> Weight { + fn set_outbound_routers() -> Weight { // TODO: BENCHMARK CORRECTLY // // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` @@ -182,4 +183,15 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(2)) } + + fn set_inbound_routers() -> Weight { + // TODO: BENCHMARK CORRECTLY + // + // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` + // This one has one read and one write for sure and possible one + // read for `AdminOrigin` + Weight::from_parts(30_117_000, 5991) + .saturating_add(RocksDbWeight::get().reads(2)) + .saturating_add(RocksDbWeight::get().writes(2)) + } } From 52f60e330ed4c2aae6c1d195f9d250e1c7baf56a Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:32:32 +0300 Subject: [PATCH 04/38] lp-gateway: Use router hashes for inbound, use session ID, update inbound message processing logic --- pallets/liquidity-pools-gateway/src/lib.rs | 482 +++++++++++++++------ 1 file changed, 341 insertions(+), 141 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index ae71e5be2a..77a2611f77 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -59,6 +59,20 @@ mod mock; #[cfg(test)] mod tests; +/// Type that stores the information required when processing inbound messages. +#[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub enum InboundEntry { + Message { + domain_address: DomainAddress, + message: T::Message, + expected_proof_count: u32, + }, + Proof { + current_count: u32, + }, +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -161,6 +175,7 @@ pub mod pallet { /// Inbound routers were set. InboundRoutersSet { + domain: Domain, router_hashes: BoundedVec, }, } @@ -190,39 +205,48 @@ pub mod pallet { pub(crate) type PackedMessage = StorageMap<_, Blake2_128Concat, (T::AccountId, Domain), T::Message>; - /// Storage for routers. + /// Storage for outbound routers. /// /// This can only be set by an admin. #[pallet::storage] #[pallet::getter(fn routers)] - pub type Routers = StorageMap<_, Blake2_128Concat, T::Hash, T::Router>; + pub type OutboundRouters = StorageMap<_, Blake2_128Concat, T::Hash, T::Router>; - /// Storage for domain multi-routers. + /// Storage for outbound routers specific for a domain. /// /// This can only be set by an admin. #[pallet::storage] - #[pallet::getter(fn domain_multi_routers)] - pub type DomainMultiRouters = + #[pallet::getter(fn outbound_domain_routers)] + pub type OutboundDomainRouters = StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; - /// Storage that keeps track of incoming message proofs. - #[pallet::storage] - #[pallet::getter(fn inbound_message_proof_count)] - pub type InboundMessageProofCount = - StorageMap<_, Blake2_128Concat, Proof, u32, ValueQuery>; - - /// Storage that keeps track of incoming messages and the expected proof - /// count. + /// Storage for pending inbound messages. #[pallet::storage] - #[pallet::getter(fn inbound_messages)] - pub type InboundMessages = - StorageMap<_, Blake2_128Concat, Proof, (DomainAddress, T::Message, u32)>; - + #[pallet::getter(fn pending_inbound_entries)] + pub type PendingInboundEntries = StorageDoubleMap< + _, + Blake2_128Concat, + T::SessionId, + Blake2_128Concat, + (Proof, T::Hash), + InboundEntry, + >; + + /// Storage for inbound routers specific for a domain. + /// + /// This can only be set by an admin. #[pallet::storage] #[pallet::getter(fn inbound_routers)] pub type InboundRouters = - StorageValue<_, BoundedVec, ValueQuery>; + StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; + + /// Storage for the session ID of an inbound domain. + #[pallet::storage] + #[pallet::getter(fn inbound_domain_sessions)] + pub type InboundDomainSessions = + StorageMap<_, Blake2_128Concat, Domain, T::SessionId>; + /// Storage for inbound router session IDs. #[pallet::storage] pub type SessionIdStore = StorageValue<_, T::SessionId, ValueQuery>; @@ -408,10 +432,10 @@ pub mod pallet { router_hashes.push(router_hash); - Routers::::insert(router_hash, router); + OutboundRouters::::insert(router_hash, router); } - >::insert( + >::insert( domain.clone(), BoundedVec::try_from(router_hashes).map_err(|_| Error::::InvalidMultiRouter)?, ); @@ -426,6 +450,7 @@ pub mod pallet { #[pallet::call_index(12)] pub fn set_inbound_routers( origin: OriginFor, + domain: Domain, router_hashes: BoundedVec, ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; @@ -435,14 +460,18 @@ pub mod pallet { Error::::InvalidMultiRouter ); - SessionIdStore::::try_mutate(|n| { + let session_id = SessionIdStore::::try_mutate(|n| { n.ensure_add_assign(One::one())?; - Ok::<(), DispatchError>(()) + Ok::(*n) })?; - InboundRouters::::set(router_hashes.clone()); + InboundRouters::::insert(domain.clone(), router_hashes.clone()); + InboundDomainSessions::::insert(domain.clone(), session_id); - Self::deposit_event(Event::InboundRoutersSet { router_hashes }); + Self::deposit_event(Event::InboundRoutersSet { + domain, + router_hashes, + }); Ok(()) } @@ -464,76 +493,261 @@ pub mod pallet { } impl Pallet { - fn clear_storages_for_inbound_messages() { - let _ = InboundMessages::::clear(u32::MAX, None); - let _ = InboundMessageProofCount::::clear(u32::MAX, None); - } - //TODO(cdamian): Use safe math fn get_expected_message_proof_count() -> u32 { T::MultiRouterCount::get() - 1 } - /// Inserts a message and its expected proof count, or increases the - /// message proof count for a particular message. - fn get_proof_and_current_count( + fn get_message_proof(message: T::Message) -> Proof { + match message.get_message_proof() { + None => message + .to_message_proof() + .get_message_proof() + .expect("message proof ensured by 'to_message_proof'"), + Some(proof) => proof, + } + } + + fn create_inbound_entry( domain_address: DomainAddress, message: T::Message, - weight: &mut Weight, - ) -> Result<(Proof, u32), DispatchError> { + ) -> InboundEntry { match message.get_message_proof() { - None => { - let message_proof = message - .to_message_proof() - .get_message_proof() - .expect("message proof ensured by 'to_message_proof'"); - - match InboundMessages::::try_mutate(message_proof, |storage_entry| { - match storage_entry { - None => { - *storage_entry = Some(( - domain_address, - message, - Self::get_expected_message_proof_count(), - )); + None => InboundEntry::Message { + domain_address, + message, + expected_proof_count: Self::get_expected_message_proof_count(), + }, + Some(_) => InboundEntry::Proof { current_count: 1 }, + } + } + + /// Validation ensures that: + /// + /// - the router that sent the inbound message is a valid router for the + /// specific domain. + /// - messages are only sent by the first inbound router. + /// - proofs are not sent by the first inbound router. + fn validate_inbound_entry( + domain: Domain, + router_hash: T::Hash, + inbound_entry: &InboundEntry, + ) -> DispatchResult { + let inbound_routers = + //TODO(cdamian): Add new error + InboundRouters::::get(domain).ok_or(Error::::InvalidMultiRouter)?; + + ensure!( + inbound_routers.iter().any(|x| x == &router_hash), + //TODO(cdamian): Add error + Error::::InvalidMultiRouter + ); + + match inbound_entry { + InboundEntry::Message { .. } => { + ensure!( + inbound_routers.get(0) == Some(&router_hash), + //TODO(cdamian): Add error + Error::::InvalidMultiRouter + ); + + Ok(()) + } + InboundEntry::Proof { .. } => { + ensure!( + inbound_routers.get(0) != Some(&router_hash), + //TODO(cdamian): Add error + Error::::InvalidMultiRouter + ); + + Ok(()) + } + } + } + + fn update_storage_entry(old: &mut InboundEntry, new: InboundEntry) -> DispatchResult { + match old { + InboundEntry::Message { + expected_proof_count, + .. + } => match new { + InboundEntry::Message { .. } => { + expected_proof_count + .ensure_add_assign(Self::get_expected_message_proof_count())?; + + Ok(()) + } + //TODO(cdamian): Update error + InboundEntry::Proof { .. } => Err(Error::::InvalidMultiRouter.into()), + }, + InboundEntry::Proof { current_count } => match new { + InboundEntry::Proof { .. } => { + current_count.ensure_add_assign(1)?; + + Ok(()) + } + //TODO(cdamian): Update error + InboundEntry::Message { .. } => Err(Error::::InvalidMultiRouter.into()), + }, + } + } + + fn update_pending_entry( + session_id: T::SessionId, + message_proof: Proof, + router_hash: T::Hash, + inbound_entry: InboundEntry, + weight: &mut Weight, + ) -> DispatchResult { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + PendingInboundEntries::::try_mutate( + session_id, + (message_proof, router_hash), + |storage_entry| match storage_entry { + None => { + *storage_entry = Some(inbound_entry); + + Ok::<(), DispatchError>(()) + } + Some(stored_inbound_entry) => match stored_inbound_entry { + InboundEntry::Message { + expected_proof_count: old, + .. + } => match inbound_entry { + InboundEntry::Message { + expected_proof_count: new, + .. + } => old.ensure_add_assign(new).map_err(|e| e.into()), + InboundEntry::Proof { .. } => { + // TODO(cdamian): Add new error. + Err(Error::::InvalidMultiRouter.into()) } - Some((_, _, expected_proof_count)) => { - // We already have a message, in this case we should expect another - // set of message proofs. - expected_proof_count - .ensure_add_assign(Self::get_expected_message_proof_count())?; + }, + InboundEntry::Proof { current_count: old } => match inbound_entry { + InboundEntry::Proof { current_count: new } => { + old.ensure_add_assign(new).map_err(|e| e.into()) } - }; + InboundEntry::Message { .. } => { + // TODO(cdamian): Add new error. + Err(Error::::InvalidMultiRouter.into()) + } + }, + }, + }, + ) + } - Ok(()) - }) { - Ok(_) => {} - Err(e) => return Err(e), - }; + fn validate_and_update_pending_entries( + session_id: T::SessionId, + message_proof: Proof, + router_hash: T::Hash, + domain_address: DomainAddress, + message: T::Message, + weight: &mut Weight, + ) -> DispatchResult { + let session_id = InboundDomainSessions::::get(domain_address.domain()) + .ok_or(Error::::InvalidMultiRouter)?; - *weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + let message_proof = Self::get_message_proof(message.clone()); - Ok(( - message_proof, - InboundMessageProofCount::::get(message_proof), - )) - } - Some(message_proof) => { - let message_proof_count = - match InboundMessageProofCount::::try_mutate(message_proof, |count| { - count.ensure_add_assign(1)?; + let inbound_entry = Self::create_inbound_entry(domain_address.clone(), message); - Ok(*count) - }) { - Ok(r) => r, - Err(e) => return Err(e), - }; + Self::validate_inbound_entry(domain_address.domain(), router_hash, &inbound_entry)?; - *weight = weight.saturating_add(T::DbWeight::get().writes(1)); + Self::update_pending_entry( + session_id, + message_proof, + router_hash, + inbound_entry, + weight, + )?; - Ok((message_proof, message_proof_count)) + Ok(()) + } + + fn get_executable_message( + inbound_routers: BoundedVec, + session_id: T::SessionId, + message_proof: Proof, + ) -> Option { + let mut message = None; + let mut proof_count = 0; + + for inbound_router in inbound_routers { + match PendingInboundEntries::::get(session_id, (message_proof, inbound_router)) { + // We expected one InboundEntry for each router, if that's not the case, + // we can return. + None => return None, + Some(inbound_entry) => match inbound_entry { + InboundEntry::Message { + message: stored_message, + .. + } => message = Some(stored_message), + InboundEntry::Proof { current_count } => { + if current_count > 0 { + proof_count += 1; + } + } + }, + }; + } + + if proof_count == Self::get_expected_message_proof_count() { + return message; + } + + None + } + + fn decrease_pending_entries_counts( + inbound_routers: BoundedVec, + session_id: T::SessionId, + message_proof: Proof, + ) -> DispatchResult { + for inbound_router in inbound_routers { + match PendingInboundEntries::::try_mutate( + session_id, + (message_proof, inbound_router), + |storage_entry| match storage_entry { + // TODO(cdamian): Add new error + None => Err(Error::::InvalidMultiRouter.into()), + Some(stored_inbound_entry) => match stored_inbound_entry { + InboundEntry::Message { + expected_proof_count, + .. + } => { + let updated_count = (*expected_proof_count) + .ensure_sub(Self::get_expected_message_proof_count())?; + + if updated_count == 0 { + *storage_entry = None; + } else { + *expected_proof_count = updated_count; + } + + Ok::<(), DispatchError>(()) + } + InboundEntry::Proof { current_count } => { + let updated_count = (*current_count).ensure_sub(1)?; + + if updated_count == 0 { + *storage_entry = None; + } else { + *current_count = updated_count; + } + + Ok::<(), DispatchError>(()) + } + }, + }, + ) { + Ok(()) => {} + Err(e) => return Err(e), } } + + Ok(()) } /// Give the message to the `InboundMessageHandler` to be processed. @@ -542,78 +756,64 @@ pub mod pallet { message: T::Message, router_hash: T::Hash, ) -> (DispatchResult, Weight) { + let mut weight = T::DbWeight::get().reads(1); + + let Some(inbound_routers) = InboundRouters::::get(domain_address.domain()) else { + //TODO(cdamian): Add new error + return (Err(Error::::InvalidMultiRouter.into()), weight); + }; + + if inbound_routers.len() == 0 {} + + let Some(session_id) = InboundDomainSessions::::get(domain_address.domain()) else { + //TODO(cdamian): Add error + return (Err(Error::::InvalidMultiRouter.into()), weight); + }; + + let message_proof = Self::get_message_proof(message.clone()); + + weight.saturating_accrue( + Weight::from_parts(0, T::Message::max_encoded_len() as u64) + .saturating_add(LP_DEFENSIVE_WEIGHT), + ); + let mut count = 0; for submessage in message.submessages() { count += 1; - let (message_proof, mut current_message_proof_count) = - match Self::get_proof_and_current_count( - domain_address.clone(), - message.clone(), - &mut weight, - ) { - Ok(r) => r, - Err(e) => return (Err(e), weight), - }; - - let (_, message, mut total_expected_proof_count) = - match InboundMessages::::get(message_proof) { - None => return (Ok(()), weight), - Some(r) => r, - }; + if let Err(e) = Self::validate_and_update_pending_entries( + session_id, + message_proof, + router_hash, + domain_address.clone(), + submessage.clone(), + &mut weight, + ) { + return (Err(e), weight); + } - weight = weight.saturating_add(T::DbWeight::get().reads(1)); - - let expected_message_proof_count = Self::get_expected_message_proof_count(); - - match current_message_proof_count.cmp(&expected_message_proof_count) { - Ordering::Less => return (Ok(()), weight), - Ordering::Equal => { - InboundMessageProofCount::::remove(message_proof); - total_expected_proof_count -= expected_message_proof_count; - - if total_expected_proof_count == 0 { - InboundMessages::::remove(message_proof); - } else { - InboundMessages::::insert( - message_proof, - ( - domain_address.clone(), - message.clone(), - total_expected_proof_count, - ), - ); - } - } - Ordering::Greater => { - current_message_proof_count -= expected_message_proof_count; - InboundMessageProofCount::::insert( + match Self::get_executable_message( + inbound_routers.clone(), + session_id, + message_proof, + ) { + Some(m) => { + if let Err(e) = Self::decrease_pending_entries_counts( + inbound_routers.clone(), + session_id, message_proof, - current_message_proof_count, - ); - - total_expected_proof_count -= expected_message_proof_count; - - if total_expected_proof_count == 0 { - InboundMessages::::remove(message_proof); - } else { - InboundMessages::::insert( - message_proof, - ( - domain_address.clone(), - message.clone(), - total_expected_proof_count, - ), - ); + ) { + return (Err(e), weight.saturating_mul(count)); } - } - } - if let Err(e) = T::InboundMessageHandler::handle(domain_address.clone(), submessage) - { - // We only consume the processed weight if error during the batch - return (Err(e), LP_DEFENSIVE_WEIGHT.saturating_mul(count)); + if let Err(e) = T::InboundMessageHandler::handle(domain_address.clone(), m) + { + // We only consume the processed weight if error during the batch + return (Err(e), weight.saturating_mul(count)); + } + } + None => continue, } } @@ -630,7 +830,7 @@ pub mod pallet { ) -> (DispatchResult, Weight) { let router_ids = T::RouterId::for_domain(domain); - let Some(router) = Routers::::get(router_hash) else { + let Some(router) = OutboundRouters::::get(router_hash) else { return (Err(Error::::RouterNotFound.into()), read_weight); }; @@ -649,7 +849,7 @@ pub mod pallet { } fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { - let router_hashes = DomainMultiRouters::::get(destination.clone()) + let router_hashes = OutboundDomainRouters::::get(destination.clone()) .ok_or(Error::::MultiRouterNotFound)?; let message_proof = message.to_message_proof(); From 5226748aa7e0e1f88896bf0853b3af962b06ede9 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Fri, 9 Aug 2024 15:16:58 +0300 Subject: [PATCH 05/38] lp-gateway: Add and use InboundProcessingInfo --- pallets/liquidity-pools-gateway/src/lib.rs | 170 ++++++++++++------- pallets/liquidity-pools-gateway/src/mock.rs | 3 +- pallets/liquidity-pools-gateway/src/tests.rs | 1 + 3 files changed, 108 insertions(+), 66 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 77a2611f77..fa4b5b7f2b 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -73,6 +73,14 @@ pub enum InboundEntry { }, } +#[derive(Clone)] +pub struct InboundProcessingInfo { + domain_address: DomainAddress, + inbound_routers: BoundedVec, + current_session_id: T::SessionId, + expected_proof_count_per_message: u32, +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -137,9 +145,9 @@ pub mod pallet { Message = GatewayMessage, >; - /// Number of routers for a domain. + /// Maximum number of routers allowed for a domain. #[pallet::constant] - type MultiRouterCount: Get; + type MaxRouterCount: Get; /// Type for identifying sessions of inbound routers. type SessionId: Parameter @@ -170,13 +178,13 @@ pub mod pallet { /// The outbound routers for a given domain were set. OutboundRoutersSet { domain: Domain, - routers: BoundedVec, + routers: BoundedVec, }, /// Inbound routers were set. InboundRoutersSet { domain: Domain, - router_hashes: BoundedVec, + router_hashes: BoundedVec, }, } @@ -218,7 +226,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn outbound_domain_routers)] pub type OutboundDomainRouters = - StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; + StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; /// Storage for pending inbound messages. #[pallet::storage] @@ -238,7 +246,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn inbound_routers)] pub type InboundRouters = - StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; + StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; /// Storage for the session ID of an inbound domain. #[pallet::storage] @@ -413,13 +421,13 @@ pub mod pallet { pub fn set_outbound_routers( origin: OriginFor, domain: Domain, - routers: BoundedVec, + routers: BoundedVec, ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; ensure!(domain != Domain::Centrifuge, Error::::DomainNotSupported); ensure!( - routers.len() == T::MultiRouterCount::get() as usize, + routers.len() == T::MaxRouterCount::get() as usize, Error::::InvalidMultiRouter ); @@ -451,12 +459,12 @@ pub mod pallet { pub fn set_inbound_routers( origin: OriginFor, domain: Domain, - router_hashes: BoundedVec, + router_hashes: BoundedVec, ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; ensure!( - router_hashes.len() == T::MultiRouterCount::get() as usize, + router_hashes.len() == T::MaxRouterCount::get() as usize, Error::::InvalidMultiRouter ); @@ -494,8 +502,13 @@ pub mod pallet { impl Pallet { //TODO(cdamian): Use safe math - fn get_expected_message_proof_count() -> u32 { - T::MultiRouterCount::get() - 1 + fn get_expected_proof_count(domain: &Domain) -> Result { + let routers = + InboundRouters::::get(domain).ok_or(Error::::MultiRouterNotFound)?; + + let expected_proof_count = routers.len().ensure_sub(1)?; + + Ok(expected_proof_count as u32) } fn get_message_proof(message: T::Message) -> Proof { @@ -511,12 +524,13 @@ pub mod pallet { fn create_inbound_entry( domain_address: DomainAddress, message: T::Message, + expected_proof_count: u32, ) -> InboundEntry { match message.get_message_proof() { None => InboundEntry::Message { domain_address, message, - expected_proof_count: Self::get_expected_message_proof_count(), + expected_proof_count, }, Some(_) => InboundEntry::Proof { current_count: 1 }, } @@ -565,15 +579,21 @@ pub mod pallet { } } - fn update_storage_entry(old: &mut InboundEntry, new: InboundEntry) -> DispatchResult { + fn update_storage_entry( + domain: Domain, + old: &mut InboundEntry, + new: InboundEntry, + ) -> DispatchResult { match old { InboundEntry::Message { - expected_proof_count, + expected_proof_count: stored_expected_proof_count, .. } => match new { InboundEntry::Message { .. } => { - expected_proof_count - .ensure_add_assign(Self::get_expected_message_proof_count())?; + let expected_message_proof_count = Self::get_expected_proof_count(&domain)?; + + stored_expected_proof_count + .ensure_add_assign(expected_message_proof_count)?; Ok(()) } @@ -639,24 +659,26 @@ pub mod pallet { } fn validate_and_update_pending_entries( - session_id: T::SessionId, + inbound_processing_info: &InboundProcessingInfo, + message: T::Message, message_proof: Proof, router_hash: T::Hash, - domain_address: DomainAddress, - message: T::Message, weight: &mut Weight, ) -> DispatchResult { - let session_id = InboundDomainSessions::::get(domain_address.domain()) - .ok_or(Error::::InvalidMultiRouter)?; - - let message_proof = Self::get_message_proof(message.clone()); - - let inbound_entry = Self::create_inbound_entry(domain_address.clone(), message); + let inbound_entry = Self::create_inbound_entry( + inbound_processing_info.domain_address.clone(), + message, + inbound_processing_info.expected_proof_count_per_message, + ); - Self::validate_inbound_entry(domain_address.domain(), router_hash, &inbound_entry)?; + Self::validate_inbound_entry( + inbound_processing_info.domain_address.domain(), + router_hash, + &inbound_entry, + )?; Self::update_pending_entry( - session_id, + inbound_processing_info.current_session_id, message_proof, router_hash, inbound_entry, @@ -667,15 +689,17 @@ pub mod pallet { } fn get_executable_message( - inbound_routers: BoundedVec, - session_id: T::SessionId, + inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, ) -> Option { let mut message = None; - let mut proof_count = 0; + let mut votes = 0; - for inbound_router in inbound_routers { - match PendingInboundEntries::::get(session_id, (message_proof, inbound_router)) { + for inbound_router in &inbound_processing_info.inbound_routers { + match PendingInboundEntries::::get( + inbound_processing_info.current_session_id, + (message_proof, inbound_router), + ) { // We expected one InboundEntry for each router, if that's not the case, // we can return. None => return None, @@ -686,14 +710,14 @@ pub mod pallet { } => message = Some(stored_message), InboundEntry::Proof { current_count } => { if current_count > 0 { - proof_count += 1; + votes += 1; } } }, }; } - if proof_count == Self::get_expected_message_proof_count() { + if votes == inbound_processing_info.expected_proof_count_per_message { return message; } @@ -701,13 +725,12 @@ pub mod pallet { } fn decrease_pending_entries_counts( - inbound_routers: BoundedVec, - session_id: T::SessionId, + inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, ) -> DispatchResult { - for inbound_router in inbound_routers { + for inbound_router in &inbound_processing_info.inbound_routers { match PendingInboundEntries::::try_mutate( - session_id, + inbound_processing_info.current_session_id, (message_proof, inbound_router), |storage_entry| match storage_entry { // TODO(cdamian): Add new error @@ -717,8 +740,9 @@ pub mod pallet { expected_proof_count, .. } => { - let updated_count = (*expected_proof_count) - .ensure_sub(Self::get_expected_message_proof_count())?; + let updated_count = (*expected_proof_count).ensure_sub( + inbound_processing_info.expected_proof_count_per_message, + )?; if updated_count == 0 { *storage_entry = None; @@ -750,27 +774,47 @@ pub mod pallet { Ok(()) } + fn get_inbound_processing_info( + domain_address: DomainAddress, + weight: &mut Weight, + ) -> Result, DispatchError> { + let inbound_routers = + //TODO(cdamian): Add new error + InboundRouters::::get(domain_address.domain()).ok_or(Error::::InvalidMultiRouter)?; + + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + let current_session_id = + //TODO(cdamian): Add new error + InboundDomainSessions::::get(domain_address.domain()).ok_or(Error::::InvalidMultiRouter)?; + + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + let expected_proof_count = Self::get_expected_proof_count(&domain_address.domain())?; + + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + Ok(InboundProcessingInfo { + domain_address, + inbound_routers, + current_session_id, + expected_proof_count_per_message: expected_proof_count, + }) + } + /// Give the message to the `InboundMessageHandler` to be processed. fn process_inbound_message( domain_address: DomainAddress, message: T::Message, router_hash: T::Hash, ) -> (DispatchResult, Weight) { - let mut weight = T::DbWeight::get().reads(1); + let mut weight = Default::default(); - let Some(inbound_routers) = InboundRouters::::get(domain_address.domain()) else { - //TODO(cdamian): Add new error - return (Err(Error::::InvalidMultiRouter.into()), weight); - }; - - if inbound_routers.len() == 0 {} - - let Some(session_id) = InboundDomainSessions::::get(domain_address.domain()) else { - //TODO(cdamian): Add error - return (Err(Error::::InvalidMultiRouter.into()), weight); - }; - - let message_proof = Self::get_message_proof(message.clone()); + let inbound_processing_info = + match Self::get_inbound_processing_info(domain_address.clone(), &mut weight) { + Ok(i) => i, + Err(e) => return (Err(e), weight), + }; weight.saturating_accrue( Weight::from_parts(0, T::Message::max_encoded_len() as u64) @@ -782,26 +826,22 @@ pub mod pallet { for submessage in message.submessages() { count += 1; + let message_proof = Self::get_message_proof(message.clone()); + if let Err(e) = Self::validate_and_update_pending_entries( - session_id, + &inbound_processing_info, + submessage.clone(), message_proof, router_hash, - domain_address.clone(), - submessage.clone(), &mut weight, ) { return (Err(e), weight); } - match Self::get_executable_message( - inbound_routers.clone(), - session_id, - message_proof, - ) { + match Self::get_executable_message(&inbound_processing_info, message_proof) { Some(m) => { if let Err(e) = Self::decrease_pending_entries_counts( - inbound_routers.clone(), - session_id, + &inbound_processing_info, message_proof, ) { return (Err(e), weight.saturating_mul(count)); diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index ec1abe268b..a4d45b42fc 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -150,7 +150,7 @@ frame_support::parameter_types! { pub Sender: DomainAddress = DomainAddress::Centrifuge(AccountId32::from(H256::from_low_u64_be(1).to_fixed_bytes()).into()); pub const MaxIncomingMessageSize: u32 = 1024; pub const LpAdminAccount: AccountId32 = LP_ADMIN_ACCOUNT; - pub const MultiRouterCount: u32 = 3; + pub const MaxRouterCount: u32 = 8; } impl pallet_liquidity_pools_gateway::Config for Runtime { @@ -158,6 +158,7 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type InboundMessageHandler = MockLiquidityPools; type LocalEVMOrigin = EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; + type MaxRouterCount = MaxRouterCount; type Message = Message; type MessageQueue = MockLiquidityPoolsGatewayQueue; type MultiRouterCount = MultiRouterCount; diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 3c9f056071..a66cc89115 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use cfg_mocks::*; +use cfg_primitives::LP_DEFENSIVE_WEIGHT; use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler, Proof}; use cfg_types::domain_address::*; use frame_support::{ From 656e392b7ad0962a0250b9bbcde9da1b4617d65d Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Fri, 9 Aug 2024 19:52:50 +0300 Subject: [PATCH 06/38] lp-gateway: Unit tests WIP --- pallets/liquidity-pools-gateway/src/lib.rs | 124 +- pallets/liquidity-pools-gateway/src/mock.rs | 1 - pallets/liquidity-pools-gateway/src/tests.rs | 1171 ++++++++++-------- 3 files changed, 707 insertions(+), 589 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index fa4b5b7f2b..71d33f1a8d 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -40,7 +40,7 @@ use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; use parity_scale_codec::{EncodeLike, FullCodec}; -use sp_arithmetic::traits::BaseArithmetic; +use sp_arithmetic::traits::{BaseArithmetic, EnsureSub, One}; use sp_runtime::traits::EnsureAddAssign; use sp_std::{cmp::Ordering, convert::TryInto, vec::Vec}; @@ -63,14 +63,14 @@ mod tests; #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub enum InboundEntry { - Message { - domain_address: DomainAddress, - message: T::Message, - expected_proof_count: u32, - }, - Proof { - current_count: u32, - }, + Message { + domain_address: DomainAddress, + message: T::Message, + expected_proof_count: u32, + }, + Proof { + current_count: u32, + }, } #[derive(Clone)] @@ -289,6 +289,27 @@ pub mod pallet { /// Invalid multi router. InvalidMultiRouter, + /// Inbound domain session not found. + InboundDomainSessionNotFound, + + /// The router that sent the inbound message is unknown. + UnknownInboundMessageRouter, + + /// The router that sent the message is not the first one. + MessageExpectedFromFirstRouter, + + /// The router that sent the proof should not be the first one. + ProofNotExpectedFromFirstRouter, + + /// A message was expected instead of a proof. + ExpectedMessageType, + + /// A message proof was expected instead of a message. + ExpectedMessageProofType, + + /// Pending inbound entry not found. + PendingInboundEntryNotFound, + /// Multi-router not found. MultiRouterNotFound, @@ -426,10 +447,6 @@ pub mod pallet { T::AdminOrigin::ensure_origin(origin)?; ensure!(domain != Domain::Centrifuge, Error::::DomainNotSupported); - ensure!( - routers.len() == T::MaxRouterCount::get() as usize, - Error::::InvalidMultiRouter - ); let mut router_hashes = Vec::new(); @@ -463,11 +480,6 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - ensure!( - router_hashes.len() == T::MaxRouterCount::get() as usize, - Error::::InvalidMultiRouter - ); - let session_id = SessionIdStore::::try_mutate(|n| { n.ensure_add_assign(One::one())?; Ok::(*n) @@ -501,7 +513,6 @@ pub mod pallet { } impl Pallet { - //TODO(cdamian): Use safe math fn get_expected_proof_count(domain: &Domain) -> Result { let routers = InboundRouters::::get(domain).ok_or(Error::::MultiRouterNotFound)?; @@ -543,26 +554,23 @@ pub mod pallet { /// - messages are only sent by the first inbound router. /// - proofs are not sent by the first inbound router. fn validate_inbound_entry( - domain: Domain, + inbound_processing_info: &InboundProcessingInfo, router_hash: T::Hash, inbound_entry: &InboundEntry, ) -> DispatchResult { - let inbound_routers = - //TODO(cdamian): Add new error - InboundRouters::::get(domain).ok_or(Error::::InvalidMultiRouter)?; + let inbound_routers = inbound_processing_info.inbound_routers.clone(); ensure!( inbound_routers.iter().any(|x| x == &router_hash), - //TODO(cdamian): Add error - Error::::InvalidMultiRouter + Error::::UnknownInboundMessageRouter ); + //TODO(cdamian): Test with 2 routers match inbound_entry { InboundEntry::Message { .. } => { ensure!( inbound_routers.get(0) == Some(&router_hash), - //TODO(cdamian): Add error - Error::::InvalidMultiRouter + Error::::MessageExpectedFromFirstRouter ); Ok(()) @@ -570,8 +578,7 @@ pub mod pallet { InboundEntry::Proof { .. } => { ensure!( inbound_routers.get(0) != Some(&router_hash), - //TODO(cdamian): Add error - Error::::InvalidMultiRouter + Error::::ProofNotExpectedFromFirstRouter ); Ok(()) @@ -579,39 +586,6 @@ pub mod pallet { } } - fn update_storage_entry( - domain: Domain, - old: &mut InboundEntry, - new: InboundEntry, - ) -> DispatchResult { - match old { - InboundEntry::Message { - expected_proof_count: stored_expected_proof_count, - .. - } => match new { - InboundEntry::Message { .. } => { - let expected_message_proof_count = Self::get_expected_proof_count(&domain)?; - - stored_expected_proof_count - .ensure_add_assign(expected_message_proof_count)?; - - Ok(()) - } - //TODO(cdamian): Update error - InboundEntry::Proof { .. } => Err(Error::::InvalidMultiRouter.into()), - }, - InboundEntry::Proof { current_count } => match new { - InboundEntry::Proof { .. } => { - current_count.ensure_add_assign(1)?; - - Ok(()) - } - //TODO(cdamian): Update error - InboundEntry::Message { .. } => Err(Error::::InvalidMultiRouter.into()), - }, - } - } - fn update_pending_entry( session_id: T::SessionId, message_proof: Proof, @@ -640,8 +614,8 @@ pub mod pallet { .. } => old.ensure_add_assign(new).map_err(|e| e.into()), InboundEntry::Proof { .. } => { - // TODO(cdamian): Add new error. - Err(Error::::InvalidMultiRouter.into()) + //TODO(cdamian): Test with 2 routers + Err(Error::::ExpectedMessageType.into()) } }, InboundEntry::Proof { current_count: old } => match inbound_entry { @@ -649,8 +623,7 @@ pub mod pallet { old.ensure_add_assign(new).map_err(|e| e.into()) } InboundEntry::Message { .. } => { - // TODO(cdamian): Add new error. - Err(Error::::InvalidMultiRouter.into()) + Err(Error::::ExpectedMessageProofType.into()) } }, }, @@ -671,11 +644,7 @@ pub mod pallet { inbound_processing_info.expected_proof_count_per_message, ); - Self::validate_inbound_entry( - inbound_processing_info.domain_address.domain(), - router_hash, - &inbound_entry, - )?; + Self::validate_inbound_entry(&inbound_processing_info, router_hash, &inbound_entry)?; Self::update_pending_entry( inbound_processing_info.current_session_id, @@ -733,8 +702,7 @@ pub mod pallet { inbound_processing_info.current_session_id, (message_proof, inbound_router), |storage_entry| match storage_entry { - // TODO(cdamian): Add new error - None => Err(Error::::InvalidMultiRouter.into()), + None => Err(Error::::PendingInboundEntryNotFound.into()), Some(stored_inbound_entry) => match stored_inbound_entry { InboundEntry::Message { expected_proof_count, @@ -778,15 +746,13 @@ pub mod pallet { domain_address: DomainAddress, weight: &mut Weight, ) -> Result, DispatchError> { - let inbound_routers = - //TODO(cdamian): Add new error - InboundRouters::::get(domain_address.domain()).ok_or(Error::::InvalidMultiRouter)?; + let inbound_routers = InboundRouters::::get(domain_address.domain()) + .ok_or(Error::::MultiRouterNotFound)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); - let current_session_id = - //TODO(cdamian): Add new error - InboundDomainSessions::::get(domain_address.domain()).ok_or(Error::::InvalidMultiRouter)?; + let current_session_id = InboundDomainSessions::::get(domain_address.domain()) + .ok_or(Error::::InboundDomainSessionNotFound)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index a4d45b42fc..d423806265 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -161,7 +161,6 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type MaxRouterCount = MaxRouterCount; type Message = Message; type MessageQueue = MockLiquidityPoolsGatewayQueue; - type MultiRouterCount = MultiRouterCount; type Router = RouterMock; type MessageSender = MockMessageSender; type RouterId = RouterId; diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index a66cc89115..d38d5a532f 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -23,7 +23,13 @@ use super::{ origin::*, pallet::*, }; -use crate::GatewayMessage; +use crate::{GatewayMessage, InboundEntry}; + +lazy_static! { + static ref ROUTER_HASH_1: H256 = H256::from_low_u64_be(1); + static ref ROUTER_HASH_2: H256 = H256::from_low_u64_be(2); + static ref ROUTER_HASH_3: H256 = H256::from_low_u64_be(3); +} mod utils { use super::*; @@ -652,530 +658,675 @@ mod message_processor_impl { pub proof_count: u32, pub mock_called_times: u32, } + + pub fn gen_new(t: T, count: usize) -> Vec::Item>> + where + T: IntoIterator + Clone, + T::IntoIter: Clone, + T::Item: Clone, + { + std::iter::repeat(t.clone().into_iter()) + .take(count) + .multi_cartesian_product() + .collect::>() + } } use util::*; - mod combined_messages { + mod one_router { use super::*; - mod two_messages { - use super::*; - - lazy_static! { - static ref TEST_MAP: HashMap, ExpectedTestResult> = - HashMap::from([ - ( - vec![Message::Simple, Message::Simple], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 4 - )), - proof_count: 0, - mock_called_times: 0, - } - ), - ( - vec![Message::Proof(MESSAGE_PROOF), Message::Proof(MESSAGE_PROOF)], - ExpectedTestResult { - inbound_message: None, - proof_count: 2, - mock_called_times: 0, - } - ), - ( - vec![Message::Simple, Message::Proof(MESSAGE_PROOF)], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ( - vec![Message::Proof(MESSAGE_PROOF), Message::Simple], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ]); - } + #[test] + fn success() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let session_id = 1; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_hash = *ROUTER_HASH_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_hash, + }; + + InboundRouters::::insert( + domain_address.domain(), + BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + ); + InboundDomainSessions::::insert(domain_address.domain(), session_id); + + let handler = MockLiquidityPools::mock_handle( + move |mock_domain_address, mock_message| { + assert_eq!(mock_domain_address, domain_address); + assert_eq!(mock_message, message); + + Ok(()) + }, + ); - #[test] - fn two_messages() { - let tests = generate_test_combinations(2) - .iter() - .map(|x| { - ( - x.clone(), - TEST_MAP - .get(x) - .expect(format!("test for {x:?} should be covered").as_str()), - ) - }) - .collect::>(); - - run_tests!(tests); - } + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_ok!(res); + assert_eq!(handler.times(), 1); + }); } - mod three_messages { - use super::*; - - lazy_static! { - static ref TEST_MAP: HashMap, ExpectedTestResult> = - HashMap::from([ - ( - vec![Message::Simple, Message::Simple, Message::Simple,], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 6 - )), - proof_count: 0, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 3, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Simple, - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 4 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 4 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Simple, - Message::Simple, - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 4 - )), - proof_count: 1, - mock_called_times: 0, - } - ) - ]); - } + #[test] + fn multi_router_not_found() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_hash = *ROUTER_HASH_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_hash, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::MultiRouterNotFound); + }); + } - #[test] - fn three_messages() { - let tests = generate_test_combinations(3) - .iter() - .map(|x| { - ( - x.clone(), - TEST_MAP - .get(x) - .expect(format!("test for {x:?} should be covered").as_str()), - ) - }) - .collect::>(); - - run_tests!(tests); - } + #[test] + fn inbound_domain_session_not_found() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_hash = *ROUTER_HASH_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_hash, + }; + + InboundRouters::::insert( + domain_address.domain(), + BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + ); + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::InboundDomainSessionNotFound); + }); } - mod four_messages { - use super::*; - - lazy_static! { - static ref TEST_MAP: HashMap, ExpectedTestResult> = - HashMap::from([ - ( - vec![ - Message::Simple, - Message::Simple, - Message::Simple, - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 8 - )), - proof_count: 0, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 4, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 1, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 1, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 1, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Simple, - ], - ExpectedTestResult { - inbound_message: None, - proof_count: 1, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Simple, - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Simple, - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 2 - )), - proof_count: 0, - mock_called_times: 1, - } - ), - ( - vec![ - Message::Simple, - Message::Simple, - Message::Simple, - Message::Proof(MESSAGE_PROOF), - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 6 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Simple, - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 6 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 6 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ( - vec![ - Message::Proof(MESSAGE_PROOF), - Message::Simple, - Message::Simple, - Message::Simple, - ], - ExpectedTestResult { - inbound_message: Some(( - DomainAddress::EVM(1, [1; 20]), - Message::Simple, - 6 - )), - proof_count: 1, - mock_called_times: 0, - } - ), - ]); - } + #[test] + fn unknown_inbound_message_router() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let session_id = 1; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_hash = *ROUTER_HASH_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + // The router stored has a different hash, this should trigger the expected + // error. + router_hash: *ROUTER_HASH_2, + }; + + InboundRouters::::insert( + domain_address.domain(), + BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + ); + InboundDomainSessions::::insert(domain_address.domain(), session_id); + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::UnknownInboundMessageRouter); + }); + } - #[test] - fn four_messages() { - let tests = generate_test_combinations(4) - .iter() - .filter(|x| TEST_MAP.get(x.clone()).is_some()) - .map(|x| { - ( - x.clone(), - TEST_MAP - .get(x) - .expect(format!("test for {x:?} should be covered").as_str()), - ) - }) - .collect::>(); - - run_tests!(tests); - } + #[test] + fn expected_message_proof_type() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let message_proof = message.to_message_proof().get_message_proof().unwrap(); + let session_id = 1; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_hash = *ROUTER_HASH_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_hash, + }; + + InboundRouters::::insert( + domain_address.domain(), + BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + ); + InboundDomainSessions::::insert(domain_address.domain(), session_id); + PendingInboundEntries::::insert( + session_id, + (message_proof, router_hash), + InboundEntry::::Proof { current_count: 0 }, + ); + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::ExpectedMessageProofType); + }); } } - #[test] - fn two_non_proof_and_four_proofs() { - let tests = generate_test_combinations(6) - .into_iter() - .filter(|x| { - let r = x.iter().counts_by(|c| c.clone()); - let non_proof_count = r.get(&Message::Simple); - let proof_count = r.get(&Message::Proof(MESSAGE_PROOF)); - - match (non_proof_count, proof_count) { - (Some(non_proof_count), Some(proof_count)) => { - *non_proof_count == 2 && *proof_count == 4 - } - _ => false, - } - }) - .map(|x| { - ( - x, - ExpectedTestResult { - inbound_message: None, - proof_count: 0, - mock_called_times: 2, - }, - ) - }) - .collect::>(); - - run_tests!(tests); - } + // mod combined_messages { + // use super::*; + // + // mod two_messages { + // use super::*; + // + // lazy_static! { + // static ref TEST_MAP: HashMap, ExpectedTestResult> = + // HashMap::from([ + // ( + // vec![Message::Simple, Message::Simple], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 4 + // )), + // proof_count: 0, + // mock_called_times: 0, + // } + // ), + // ( + // vec![Message::Proof(MESSAGE_PROOF), Message::Proof(MESSAGE_PROOF)], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 2, + // mock_called_times: 0, + // } + // ), + // ( + // vec![Message::Simple, Message::Proof(MESSAGE_PROOF)], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ( + // vec![Message::Proof(MESSAGE_PROOF), Message::Simple], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ]); + // } + // + // #[test] + // fn two_messages() { + // let tests = generate_test_combinations(2) + // .iter() + // .map(|x| { + // ( + // x.clone(), + // TEST_MAP + // .get(x) + // .expect(format!("test for {x:?} should be covered").as_str()), + // ) + // }) + // .collect::>(); + // + // run_tests!(tests); + // } + // } + // + // mod three_messages { + // use super::*; + // + // lazy_static! { + // static ref TEST_MAP: HashMap, ExpectedTestResult> = + // HashMap::from([ + // ( + // vec![Message::Simple, Message::Simple, Message::Simple,], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 6 + // )), + // proof_count: 0, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 3, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 4 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 4 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 4 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ) + // ]); + // } + // + // #[test] + // fn three_messages() { + // let tests = generate_test_combinations(3) + // .iter() + // .map(|x| { + // ( + // x.clone(), + // TEST_MAP + // .get(x) + // .expect(format!("test for {x:?} should be covered").as_str()), + // ) + // }) + // .collect::>(); + // + // run_tests!(tests); + // } + // } + // + // mod four_messages { + // use super::*; + // + // lazy_static! { + // static ref TEST_MAP: HashMap, ExpectedTestResult> = + // HashMap::from([ + // ( + // vec![ + // Message::Simple, + // Message::Simple, + // Message::Simple, + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 8 + // )), + // proof_count: 0, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 4, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 1, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 1, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 1, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 1, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 2 + // )), + // proof_count: 0, + // mock_called_times: 1, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Simple, + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 6 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 6 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Simple, + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 6 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ( + // vec![ + // Message::Proof(MESSAGE_PROOF), + // Message::Simple, + // Message::Simple, + // Message::Simple, + // ], + // ExpectedTestResult { + // inbound_message: Some(( + // DomainAddress::EVM(1, [1; 20]), + // Message::Simple, + // 6 + // )), + // proof_count: 1, + // mock_called_times: 0, + // } + // ), + // ]); + // } + // + // #[test] + // fn four_messages() { + // let tests = generate_test_combinations(4) + // .iter() + // .filter(|x| TEST_MAP.get(x.clone()).is_some()) + // .map(|x| { + // ( + // x.clone(), + // TEST_MAP + // .get(x) + // .expect(format!("test for {x:?} should be covered").as_str()), + // ) + // }) + // .collect::>(); + // + // run_tests!(tests); + // } + // } + // } + // + // #[test] + // fn two_non_proof_and_four_proofs() { + // let tests = generate_test_combinations(6) + // .into_iter() + // .filter(|x| { + // let r = x.iter().counts_by(|c| c.clone()); + // let non_proof_count = r.get(&Message::Simple); + // let proof_count = r.get(&Message::Proof(MESSAGE_PROOF)); + // + // match (non_proof_count, proof_count) { + // (Some(non_proof_count), Some(proof_count)) => { + // *non_proof_count == 2 && *proof_count == 4 + // } + // _ => false, + // } + // }) + // .map(|x| { + // ( + // x, + // ExpectedTestResult { + // inbound_message: None, + // proof_count: 0, + // mock_called_times: 2, + // }, + // ) + // }) + // .collect::>(); + // + // run_tests!(tests); + // } #[test] fn inbound_message_handler_error() { @@ -1466,6 +1617,7 @@ mod batches { let (result, weight) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { domain_address, message: Message::deserialize(&(1..=5).collect::>()).unwrap(), + router_hash: *ROUTER_HASH_1, }); assert_eq!(weight, LP_DEFENSIVE_WEIGHT * 5); @@ -1490,6 +1642,7 @@ mod batches { let (result, weight) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { domain_address, message: Message::deserialize(&(1..=5).collect::>()).unwrap(), + router_hash: *ROUTER_HASH_1, }); // 2 correct messages and 1 failed message processed. From 35849538ac9809dbcb4d1dd76c1c4643aad3f792 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Sat, 10 Aug 2024 12:08:55 +0300 Subject: [PATCH 07/38] lp-gateway: Unit tests WIP 2 --- pallets/liquidity-pools-gateway/src/lib.rs | 1 - pallets/liquidity-pools-gateway/src/tests.rs | 2283 +++++++++++++----- 2 files changed, 1699 insertions(+), 585 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 71d33f1a8d..3ccc0a7c96 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -565,7 +565,6 @@ pub mod pallet { Error::::UnknownInboundMessageRouter ); - //TODO(cdamian): Test with 2 routers match inbound_entry { InboundEntry::Message { .. } => { ensure!( diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index d38d5a532f..c2352ad917 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -25,6 +25,8 @@ use super::{ }; use crate::{GatewayMessage, InboundEntry}; +pub const TEST_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(0, [1; 20]); + lazy_static! { static ref ROUTER_HASH_1: H256 = H256::from_low_u64_be(1); static ref ROUTER_HASH_2: H256 = H256::from_low_u64_be(2); @@ -582,84 +584,85 @@ mod message_processor_impl { mod util { use super::*; - macro_rules! run_tests { - ($tests:expr) => { - // $tests = Vec<(Vec, &ExpectedTestResult)> - for test in $tests { - new_test_ext().execute_with(|| { - println!("Executing test for - {:?}", test.0); - - let handler = MockLiquidityPools::mock_handle(move |_, _| Ok(())); - - // test.0 = Vec - for test_message in test.0 { - let domain_address = DomainAddress::EVM(1, [1; 20]); - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: test_message.clone(), - //TODO(cdamian): Use test router hash. - router_hash: H256::from_low_u64_be(1), - }; - - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_ok!(res); - } + pub fn run_inbound_message_test_suite(suite: InboundMessageTestSuite) { + let test_routers = suite.routers; - assert_eq!(handler.times(), test.1.mock_called_times); + for test in suite.tests { + println!("Executing test for - {:?}", test.router_messages); - assert_eq!( - InboundMessages::::get(MESSAGE_PROOF), - // test.1 = &ExpectedTestResult - test.1.inbound_message, - ); - assert_eq!( - InboundMessageProofCount::::get(MESSAGE_PROOF), - // test.1 = &ExpectedTestResult - test.1.proof_count, - ); - }); - } - }; - } + new_test_ext().execute_with(|| { + let session_id = 1; - lazy_static! { - static ref TEST_MESSAGES: Vec = - vec![Message::Simple, Message::Proof(MESSAGE_PROOF),]; + InboundRouters::::insert( + TEST_DOMAIN_ADDRESS.domain(), + BoundedVec::try_from(test_routers.clone()).unwrap(), + ); + InboundDomainSessions::::insert( + TEST_DOMAIN_ADDRESS.domain(), + session_id, + ); + + let handler = MockLiquidityPools::mock_handle(move |_, _| Ok(())); + + for router_message in test.router_messages { + let gateway_message = GatewayMessage::Inbound { + domain_address: TEST_DOMAIN_ADDRESS, + message: router_message.1, + router_hash: router_message.0, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_ok!(res); + } + + let expected_message_submitted_times = + test.expected_test_result.message_submitted_times; + let message_submitted_times = handler.times(); + + assert_eq!( + message_submitted_times, + expected_message_submitted_times, + "Expected message to be submitted {expected_message_submitted_times} times, was {message_submitted_times}" + ); + + for expected_storage_entry in + test.expected_test_result.expected_storage_entries + { + let expected_storage_entry_router_hash = expected_storage_entry.0; + let expected_inbound_entry = expected_storage_entry.1; + + let storage_entry = PendingInboundEntries::::get( + session_id, + (MESSAGE_PROOF, expected_storage_entry_router_hash), + ); + assert_eq!(storage_entry, expected_inbound_entry, "Expected inbound entry {expected_inbound_entry:?}, found {storage_entry:?}"); + } + }); + } } - /// Generate all `Message` combinations for a specific - /// number of messages, like: + /// Generate all `TestEntry` combinations like: /// /// vec![ - /// Message::Simple, - /// Message::Simple, + /// (*ROUTER_HASH_1, Message::Simple), + /// (*ROUTER_HASH_1, Message::Simple), /// ] /// vec![ - /// Message::Simple, - /// Message::Proof(MESSAGE_PROOF), + /// (*ROUTER_HASH_1, Message::Simple), + /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), /// ] /// vec![ - /// Message::Proof(MESSAGE_PROOF), - /// Message::Simple, + /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + /// (*ROUTER_HASH_1, Message::Simple), /// ] /// vec![ - /// Message::Proof(MESSAGE_PROOF), - /// Message::Proof(MESSAGE_PROOF), + /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), /// ] - pub fn generate_test_combinations(count: usize) -> Vec> { - std::iter::repeat(TEST_MESSAGES.clone().into_iter()) - .take(count) - .multi_cartesian_product() - .collect::>() - } - - pub struct ExpectedTestResult { - pub inbound_message: Option<(DomainAddress, Message, u32)>, - pub proof_count: u32, - pub mock_called_times: u32, - } - - pub fn gen_new(t: T, count: usize) -> Vec::Item>> + pub fn generate_test_combinations( + t: T, + count: usize, + ) -> Vec::Item>> where T: IntoIterator + Clone, T::IntoIter: Clone, @@ -670,6 +673,52 @@ mod message_processor_impl { .multi_cartesian_product() .collect::>() } + + pub type RouterMessage = (H256, Message); + + pub struct InboundMessageTestSuite { + pub routers: Vec, + pub tests: Vec, + } + + pub struct InboundMessageTest { + pub router_messages: Vec, + pub expected_test_result: ExpectedTestResult, + } + + #[derive(Clone, Debug)] + pub struct ExpectedTestResult { + pub message_submitted_times: u32, + pub expected_storage_entries: Vec<(H256, Option>)>, + } + + pub fn generate_test_suite( + routers: Vec, + test_data: Vec, + expected_results: HashMap, ExpectedTestResult>, + message_count: usize, + ) -> InboundMessageTestSuite { + let tests = generate_test_combinations(test_data, message_count); + + let tests = tests + .into_iter() + .map(|router_messages| { + let expected_test_result = expected_results + .get(&router_messages) + .expect( + format!("test for {router_messages:?} should be covered").as_str(), + ) + .clone(); + + InboundMessageTest { + router_messages, + expected_test_result, + } + }) + .collect::>(); + + InboundMessageTestSuite { routers, tests } + } } use util::*; @@ -681,6 +730,7 @@ mod message_processor_impl { fn success() { new_test_ext().execute_with(|| { let message = Message::Simple; + let message_proof = message.to_message_proof().get_message_proof().unwrap(); let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); let router_hash = *ROUTER_HASH_1; @@ -708,6 +758,12 @@ mod message_processor_impl { let (res, _) = LiquidityPoolsGateway::process(gateway_message); assert_ok!(res); assert_eq!(handler.times(), 1); + + assert!(PendingInboundEntries::::get( + session_id, + (message_proof, router_hash) + ) + .is_none()); }); } @@ -807,526 +863,1585 @@ mod message_processor_impl { } } - // mod combined_messages { - // use super::*; - // - // mod two_messages { - // use super::*; - // - // lazy_static! { - // static ref TEST_MAP: HashMap, ExpectedTestResult> = - // HashMap::from([ - // ( - // vec![Message::Simple, Message::Simple], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 4 - // )), - // proof_count: 0, - // mock_called_times: 0, - // } - // ), - // ( - // vec![Message::Proof(MESSAGE_PROOF), Message::Proof(MESSAGE_PROOF)], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 2, - // mock_called_times: 0, - // } - // ), - // ( - // vec![Message::Simple, Message::Proof(MESSAGE_PROOF)], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ( - // vec![Message::Proof(MESSAGE_PROOF), Message::Simple], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ]); - // } - // - // #[test] - // fn two_messages() { - // let tests = generate_test_combinations(2) - // .iter() - // .map(|x| { - // ( - // x.clone(), - // TEST_MAP - // .get(x) - // .expect(format!("test for {x:?} should be covered").as_str()), - // ) - // }) - // .collect::>(); - // - // run_tests!(tests); - // } - // } - // - // mod three_messages { - // use super::*; - // - // lazy_static! { - // static ref TEST_MAP: HashMap, ExpectedTestResult> = - // HashMap::from([ - // ( - // vec![Message::Simple, Message::Simple, Message::Simple,], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 6 - // )), - // proof_count: 0, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 3, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 4 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 4 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 4 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ) - // ]); - // } - // - // #[test] - // fn three_messages() { - // let tests = generate_test_combinations(3) - // .iter() - // .map(|x| { - // ( - // x.clone(), - // TEST_MAP - // .get(x) - // .expect(format!("test for {x:?} should be covered").as_str()), - // ) - // }) - // .collect::>(); - // - // run_tests!(tests); - // } - // } - // - // mod four_messages { - // use super::*; - // - // lazy_static! { - // static ref TEST_MAP: HashMap, ExpectedTestResult> = - // HashMap::from([ - // ( - // vec![ - // Message::Simple, - // Message::Simple, - // Message::Simple, - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 8 - // )), - // proof_count: 0, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 4, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 1, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 1, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 1, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 1, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 2 - // )), - // proof_count: 0, - // mock_called_times: 1, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Simple, - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 6 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 6 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Simple, - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 6 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ( - // vec![ - // Message::Proof(MESSAGE_PROOF), - // Message::Simple, - // Message::Simple, - // Message::Simple, - // ], - // ExpectedTestResult { - // inbound_message: Some(( - // DomainAddress::EVM(1, [1; 20]), - // Message::Simple, - // 6 - // )), - // proof_count: 1, - // mock_called_times: 0, - // } - // ), - // ]); - // } - // - // #[test] - // fn four_messages() { - // let tests = generate_test_combinations(4) - // .iter() - // .filter(|x| TEST_MAP.get(x.clone()).is_some()) - // .map(|x| { - // ( - // x.clone(), - // TEST_MAP - // .get(x) - // .expect(format!("test for {x:?} should be covered").as_str()), - // ) - // }) - // .collect::>(); - // - // run_tests!(tests); - // } - // } - // } - // - // #[test] - // fn two_non_proof_and_four_proofs() { - // let tests = generate_test_combinations(6) - // .into_iter() - // .filter(|x| { - // let r = x.iter().counts_by(|c| c.clone()); - // let non_proof_count = r.get(&Message::Simple); - // let proof_count = r.get(&Message::Proof(MESSAGE_PROOF)); - // - // match (non_proof_count, proof_count) { - // (Some(non_proof_count), Some(proof_count)) => { - // *non_proof_count == 2 && *proof_count == 4 - // } - // _ => false, - // } - // }) - // .map(|x| { - // ( - // x, - // ExpectedTestResult { - // inbound_message: None, - // proof_count: 0, - // mock_called_times: 2, - // }, - // ) - // }) - // .collect::>(); - // - // run_tests!(tests); - // } + mod two_routers { + use super::*; + + mod success { + use super::*; + + lazy_static! { + static ref TEST_DATA: Vec = vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ]; + } + + mod two_messages { + use super::*; + + const MESSAGE_COUNT: usize = 2; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![*ROUTER_HASH_1, *ROUTER_HASH_2], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + + mod three_messages { + use super::*; + + const MESSAGE_COUNT: usize = 3; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 3, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 3, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![*ROUTER_HASH_1, *ROUTER_HASH_2], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + + mod four_messages { + use super::*; + + const MESSAGE_COUNT: usize = 4; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 4, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![*ROUTER_HASH_1, *ROUTER_HASH_2], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + } + + mod failure { + use super::*; + + #[test] + fn message_expected_from_first_router() { + new_test_ext().execute_with(|| { + let session_id = 1; + + InboundRouters::::insert( + TEST_DOMAIN_ADDRESS.domain(), + BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) + .unwrap(), + ); + InboundDomainSessions::::insert( + TEST_DOMAIN_ADDRESS.domain(), + session_id, + ); + + let gateway_message = GatewayMessage::Inbound { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + router_hash: *ROUTER_HASH_2, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::MessageExpectedFromFirstRouter); + }); + } + + #[test] + fn proof_not_expected_from_first_router() { + new_test_ext().execute_with(|| { + let session_id = 1; + + InboundRouters::::insert( + TEST_DOMAIN_ADDRESS.domain(), + BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) + .unwrap(), + ); + InboundDomainSessions::::insert( + TEST_DOMAIN_ADDRESS.domain(), + session_id, + ); + + let gateway_message = GatewayMessage::Inbound { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Proof(MESSAGE_PROOF), + router_hash: *ROUTER_HASH_1, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::ProofNotExpectedFromFirstRouter); + }); + } + } + } + + mod three_routers { + use super::*; + + lazy_static! { + static ref TEST_DATA: Vec = vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ]; + } + + mod two_messages { + use super::*; + + const MESSAGE_COUNT: usize = 2; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![*ROUTER_HASH_1, *ROUTER_HASH_2, *ROUTER_HASH_3], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + + mod three_messages { + use super::*; + + const MESSAGE_COUNT: usize = 3; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 6, + }), + ), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 3, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 3, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + *ROUTER_HASH_1, + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + (*ROUTER_HASH_2, None), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_1, Message::Simple), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + (*ROUTER_HASH_2, None), + (*ROUTER_HASH_3, None), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (*ROUTER_HASH_1, None), + ( + *ROUTER_HASH_2, + Some(InboundEntry::::Proof { + current_count: 1, + }), + ), + ( + *ROUTER_HASH_3, + Some(InboundEntry::::Proof { + current_count: 2, + }), + ), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![*ROUTER_HASH_1, *ROUTER_HASH_2, *ROUTER_HASH_3], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + } #[test] fn inbound_message_handler_error() { From 2dda7f0f76351647d913e31b6dbf564329b6f7d7 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Sat, 10 Aug 2024 13:34:38 +0300 Subject: [PATCH 08/38] docs: Improve comments --- libs/traits/src/liquidity_pools.rs | 3 + pallets/liquidity-pools-gateway/src/lib.rs | 60 ++++++++++++++------ pallets/liquidity-pools-gateway/src/tests.rs | 23 +++++--- 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/libs/traits/src/liquidity_pools.rs b/libs/traits/src/liquidity_pools.rs index 607e90aa51..a28f29a5b3 100644 --- a/libs/traits/src/liquidity_pools.rs +++ b/libs/traits/src/liquidity_pools.rs @@ -34,7 +34,10 @@ pub trait LPEncoding: Sized { /// It's the identity message for composing messages with pack_with fn empty() -> Self; + /// Retrieves the message proof, if any. fn get_message_proof(&self) -> Option; + + /// Converts the message into a message proof type. fn to_message_proof(&self) -> Self; } diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 3ccc0a7c96..2cb66fe0e8 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -59,7 +59,7 @@ mod mock; #[cfg(test)] mod tests; -/// Type that stores the information required when processing inbound messages. +/// Type used when storing inbound message information. #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub enum InboundEntry { @@ -73,6 +73,7 @@ pub enum InboundEntry { }, } +/// Type used when processing inbound messages. #[derive(Clone)] pub struct InboundProcessingInfo { domain_address: DomainAddress, @@ -83,6 +84,8 @@ pub struct InboundProcessingInfo { #[frame_support::pallet] pub mod pallet { + use sp_arithmetic::traits::EnsureAdd; + use super::*; const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -248,13 +251,13 @@ pub mod pallet { pub type InboundRouters = StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; - /// Storage for the session ID of an inbound domain. + /// Storage for the inbound message session IDs. #[pallet::storage] - #[pallet::getter(fn inbound_domain_sessions)] - pub type InboundDomainSessions = + #[pallet::getter(fn inbound_message_sessions)] + pub type InboundMessageSessions = StorageMap<_, Blake2_128Concat, Domain, T::SessionId>; - /// Storage for inbound router session IDs. + /// Storage for inbound message session IDs. #[pallet::storage] pub type SessionIdStore = StorageValue<_, T::SessionId, ValueQuery>; @@ -480,13 +483,22 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - let session_id = SessionIdStore::::try_mutate(|n| { - n.ensure_add_assign(One::one())?; - Ok::(*n) + let (old_session_id, new_session_id) = SessionIdStore::::try_mutate(|n| { + let old_session_id = *n; + let new_session_id = n.ensure_add(One::one())?; + + *n = new_session_id; + + Ok::<(T::SessionId, T::SessionId), DispatchError>((old_session_id, new_session_id)) })?; InboundRouters::::insert(domain.clone(), router_hashes.clone()); - InboundDomainSessions::::insert(domain.clone(), session_id); + InboundMessageSessions::::insert(domain.clone(), new_session_id); + + //TODO(cdamian): The storages are updated with the new session. + // We can process the removal of entries associated with the old entries + // `on_idle`. + let _ = PendingInboundEntries::::clear_prefix(old_session_id, u32::MAX, None); Self::deposit_event(Event::InboundRoutersSet { domain, @@ -513,6 +525,8 @@ pub mod pallet { } impl Pallet { + /// Calculates and returns the proof count required for processing one + /// inbound message. fn get_expected_proof_count(domain: &Domain) -> Result { let routers = InboundRouters::::get(domain).ok_or(Error::::MultiRouterNotFound)?; @@ -522,6 +536,7 @@ pub mod pallet { Ok(expected_proof_count as u32) } + /// Gets the message proof for a message. fn get_message_proof(message: T::Message) -> Proof { match message.get_message_proof() { None => message @@ -532,6 +547,8 @@ pub mod pallet { } } + /// Creates an inbound entry based on whether the inbound message is a + /// proof or not. fn create_inbound_entry( domain_address: DomainAddress, message: T::Message, @@ -585,6 +602,8 @@ pub mod pallet { } } + /// Updates the inbound entry for a particular message, increasing the + /// counts accordingly. fn update_pending_entry( session_id: T::SessionId, message_proof: Proof, @@ -613,7 +632,6 @@ pub mod pallet { .. } => old.ensure_add_assign(new).map_err(|e| e.into()), InboundEntry::Proof { .. } => { - //TODO(cdamian): Test with 2 routers Err(Error::::ExpectedMessageType.into()) } }, @@ -630,6 +648,7 @@ pub mod pallet { ) } + /// Creates, validates and updates the inbound entry. fn validate_and_update_pending_entries( inbound_processing_info: &InboundProcessingInfo, message: T::Message, @@ -656,6 +675,8 @@ pub mod pallet { Ok(()) } + /// Checks if the number of proofs required for executing one message + /// were received, and returns the message if so. fn get_executable_message( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, @@ -692,6 +713,8 @@ pub mod pallet { None } + /// Decreases the counts for inbound entries and removes them if the + /// counts reach 0. fn decrease_pending_entries_counts( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, @@ -741,6 +764,8 @@ pub mod pallet { Ok(()) } + /// Retrieves the information required for processing an inbound + /// message. fn get_inbound_processing_info( domain_address: DomainAddress, weight: &mut Weight, @@ -750,7 +775,7 @@ pub mod pallet { weight.saturating_accrue(T::DbWeight::get().reads(1)); - let current_session_id = InboundDomainSessions::::get(domain_address.domain()) + let current_session_id = InboundMessageSessions::::get(domain_address.domain()) .ok_or(Error::::InboundDomainSessionNotFound)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -767,7 +792,8 @@ pub mod pallet { }) } - /// Give the message to the `InboundMessageHandler` to be processed. + /// Iterates over a batch of messages and checks if the requirements for + /// processing each message are met. fn process_inbound_message( domain_address: DomainAddress, message: T::Message, @@ -825,9 +851,8 @@ pub mod pallet { (Ok(()), LP_DEFENSIVE_WEIGHT.saturating_mul(count)) } - /// Retrieves the router stored for the provided domain, sends the - /// message using the router, and calculates and returns the required - /// weight for these operations in the `DispatchResultWithPostInfo`. + /// Retrieves the stored router, sends the message, and calculates and + /// returns the router operation result and the weight used. fn process_outbound_message( sender: T::AccountId, message: T::Message, @@ -853,6 +878,8 @@ pub mod pallet { (Ok(()), LP_DEFENSIVE_WEIGHT.saturating_mul(count)) } + /// Retrieves the hashes of the routers set for a domain and queues the + /// message and proofs accordingly. fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { let router_hashes = OutboundDomainRouters::::get(destination.clone()) .ok_or(Error::::MultiRouterNotFound)?; @@ -930,7 +957,8 @@ pub mod pallet { } } - /// Process a message. + /// Returns the max processing weight for a message, based on its + /// direction. fn max_processing_weight(msg: &Self::Message) -> Weight { match msg { GatewayMessage::Inbound { message, .. } => { diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index c2352ad917..74908488db 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -597,7 +597,7 @@ mod message_processor_impl { TEST_DOMAIN_ADDRESS.domain(), BoundedVec::try_from(test_routers.clone()).unwrap(), ); - InboundDomainSessions::::insert( + InboundMessageSessions::::insert( TEST_DOMAIN_ADDRESS.domain(), session_id, ); @@ -641,7 +641,7 @@ mod message_processor_impl { } } - /// Generate all `TestEntry` combinations like: + /// Used for generating all `RouterMessage` combinations like: /// /// vec![ /// (*ROUTER_HASH_1, Message::Simple), @@ -674,24 +674,33 @@ mod message_processor_impl { .collect::>() } + /// Type used for mapping a message to a router hash. pub type RouterMessage = (H256, Message); + /// Type used for aggregating tests for inbound messages. pub struct InboundMessageTestSuite { pub routers: Vec, pub tests: Vec, } + /// Type used for defining a test which contains a set of + /// `RouterMessage` combinations and the expected test result. pub struct InboundMessageTest { pub router_messages: Vec, pub expected_test_result: ExpectedTestResult, } + /// Type used for defining the number of expected inbound message + /// submission and the exected storage state. #[derive(Clone, Debug)] pub struct ExpectedTestResult { pub message_submitted_times: u32, pub expected_storage_entries: Vec<(H256, Option>)>, } + /// Generates the combinations of `RouterMessage` used when testing, + /// maps the `ExpectedTestResult` for each and creates the + /// `InboundMessageTestSuite`. pub fn generate_test_suite( routers: Vec, test_data: Vec, @@ -744,7 +753,7 @@ mod message_processor_impl { domain_address.domain(), BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), ); - InboundDomainSessions::::insert(domain_address.domain(), session_id); + InboundMessageSessions::::insert(domain_address.domain(), session_id); let handler = MockLiquidityPools::mock_handle( move |mock_domain_address, mock_message| { @@ -825,7 +834,7 @@ mod message_processor_impl { domain_address.domain(), BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), ); - InboundDomainSessions::::insert(domain_address.domain(), session_id); + InboundMessageSessions::::insert(domain_address.domain(), session_id); let (res, _) = LiquidityPoolsGateway::process(gateway_message); assert_noop!(res, Error::::UnknownInboundMessageRouter); @@ -850,7 +859,7 @@ mod message_processor_impl { domain_address.domain(), BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), ); - InboundDomainSessions::::insert(domain_address.domain(), session_id); + InboundMessageSessions::::insert(domain_address.domain(), session_id); PendingInboundEntries::::insert( session_id, (message_proof, router_hash), @@ -1480,7 +1489,7 @@ mod message_processor_impl { BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) .unwrap(), ); - InboundDomainSessions::::insert( + InboundMessageSessions::::insert( TEST_DOMAIN_ADDRESS.domain(), session_id, ); @@ -1506,7 +1515,7 @@ mod message_processor_impl { BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) .unwrap(), ); - InboundDomainSessions::::insert( + InboundMessageSessions::::insert( TEST_DOMAIN_ADDRESS.domain(), session_id, ); From 02340e34fce2da0669e26c203252d96f66c6a67d Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Sat, 10 Aug 2024 13:41:39 +0300 Subject: [PATCH 09/38] lp-gateway: Move message processing logic to a new file --- pallets/liquidity-pools-gateway/src/lib.rs | 415 +---------------- .../src/message_processing.rs | 417 ++++++++++++++++++ pallets/liquidity-pools-gateway/src/tests.rs | 2 +- 3 files changed, 421 insertions(+), 413 deletions(-) create mode 100644 pallets/liquidity-pools-gateway/src/message_processing.rs diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 2cb66fe0e8..844c9da020 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -42,9 +42,9 @@ pub use pallet::*; use parity_scale_codec::{EncodeLike, FullCodec}; use sp_arithmetic::traits::{BaseArithmetic, EnsureSub, One}; use sp_runtime::traits::EnsureAddAssign; -use sp_std::{cmp::Ordering, convert::TryInto, vec::Vec}; +use sp_std::{convert::TryInto, vec::Vec}; -use crate::weights::WeightInfo; +use crate::{message_processing::InboundEntry, weights::WeightInfo}; mod origin; pub use origin::*; @@ -56,32 +56,10 @@ pub mod weights; #[cfg(test)] mod mock; +mod message_processing; #[cfg(test)] mod tests; -/// Type used when storing inbound message information. -#[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub enum InboundEntry { - Message { - domain_address: DomainAddress, - message: T::Message, - expected_proof_count: u32, - }, - Proof { - current_count: u32, - }, -} - -/// Type used when processing inbound messages. -#[derive(Clone)] -pub struct InboundProcessingInfo { - domain_address: DomainAddress, - inbound_routers: BoundedVec, - current_session_id: T::SessionId, - expected_proof_count_per_message: u32, -} - #[frame_support::pallet] pub mod pallet { use sp_arithmetic::traits::EnsureAdd; @@ -524,393 +502,6 @@ pub mod pallet { } } - impl Pallet { - /// Calculates and returns the proof count required for processing one - /// inbound message. - fn get_expected_proof_count(domain: &Domain) -> Result { - let routers = - InboundRouters::::get(domain).ok_or(Error::::MultiRouterNotFound)?; - - let expected_proof_count = routers.len().ensure_sub(1)?; - - Ok(expected_proof_count as u32) - } - - /// Gets the message proof for a message. - fn get_message_proof(message: T::Message) -> Proof { - match message.get_message_proof() { - None => message - .to_message_proof() - .get_message_proof() - .expect("message proof ensured by 'to_message_proof'"), - Some(proof) => proof, - } - } - - /// Creates an inbound entry based on whether the inbound message is a - /// proof or not. - fn create_inbound_entry( - domain_address: DomainAddress, - message: T::Message, - expected_proof_count: u32, - ) -> InboundEntry { - match message.get_message_proof() { - None => InboundEntry::Message { - domain_address, - message, - expected_proof_count, - }, - Some(_) => InboundEntry::Proof { current_count: 1 }, - } - } - - /// Validation ensures that: - /// - /// - the router that sent the inbound message is a valid router for the - /// specific domain. - /// - messages are only sent by the first inbound router. - /// - proofs are not sent by the first inbound router. - fn validate_inbound_entry( - inbound_processing_info: &InboundProcessingInfo, - router_hash: T::Hash, - inbound_entry: &InboundEntry, - ) -> DispatchResult { - let inbound_routers = inbound_processing_info.inbound_routers.clone(); - - ensure!( - inbound_routers.iter().any(|x| x == &router_hash), - Error::::UnknownInboundMessageRouter - ); - - match inbound_entry { - InboundEntry::Message { .. } => { - ensure!( - inbound_routers.get(0) == Some(&router_hash), - Error::::MessageExpectedFromFirstRouter - ); - - Ok(()) - } - InboundEntry::Proof { .. } => { - ensure!( - inbound_routers.get(0) != Some(&router_hash), - Error::::ProofNotExpectedFromFirstRouter - ); - - Ok(()) - } - } - } - - /// Updates the inbound entry for a particular message, increasing the - /// counts accordingly. - fn update_pending_entry( - session_id: T::SessionId, - message_proof: Proof, - router_hash: T::Hash, - inbound_entry: InboundEntry, - weight: &mut Weight, - ) -> DispatchResult { - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - PendingInboundEntries::::try_mutate( - session_id, - (message_proof, router_hash), - |storage_entry| match storage_entry { - None => { - *storage_entry = Some(inbound_entry); - - Ok::<(), DispatchError>(()) - } - Some(stored_inbound_entry) => match stored_inbound_entry { - InboundEntry::Message { - expected_proof_count: old, - .. - } => match inbound_entry { - InboundEntry::Message { - expected_proof_count: new, - .. - } => old.ensure_add_assign(new).map_err(|e| e.into()), - InboundEntry::Proof { .. } => { - Err(Error::::ExpectedMessageType.into()) - } - }, - InboundEntry::Proof { current_count: old } => match inbound_entry { - InboundEntry::Proof { current_count: new } => { - old.ensure_add_assign(new).map_err(|e| e.into()) - } - InboundEntry::Message { .. } => { - Err(Error::::ExpectedMessageProofType.into()) - } - }, - }, - }, - ) - } - - /// Creates, validates and updates the inbound entry. - fn validate_and_update_pending_entries( - inbound_processing_info: &InboundProcessingInfo, - message: T::Message, - message_proof: Proof, - router_hash: T::Hash, - weight: &mut Weight, - ) -> DispatchResult { - let inbound_entry = Self::create_inbound_entry( - inbound_processing_info.domain_address.clone(), - message, - inbound_processing_info.expected_proof_count_per_message, - ); - - Self::validate_inbound_entry(&inbound_processing_info, router_hash, &inbound_entry)?; - - Self::update_pending_entry( - inbound_processing_info.current_session_id, - message_proof, - router_hash, - inbound_entry, - weight, - )?; - - Ok(()) - } - - /// Checks if the number of proofs required for executing one message - /// were received, and returns the message if so. - fn get_executable_message( - inbound_processing_info: &InboundProcessingInfo, - message_proof: Proof, - ) -> Option { - let mut message = None; - let mut votes = 0; - - for inbound_router in &inbound_processing_info.inbound_routers { - match PendingInboundEntries::::get( - inbound_processing_info.current_session_id, - (message_proof, inbound_router), - ) { - // We expected one InboundEntry for each router, if that's not the case, - // we can return. - None => return None, - Some(inbound_entry) => match inbound_entry { - InboundEntry::Message { - message: stored_message, - .. - } => message = Some(stored_message), - InboundEntry::Proof { current_count } => { - if current_count > 0 { - votes += 1; - } - } - }, - }; - } - - if votes == inbound_processing_info.expected_proof_count_per_message { - return message; - } - - None - } - - /// Decreases the counts for inbound entries and removes them if the - /// counts reach 0. - fn decrease_pending_entries_counts( - inbound_processing_info: &InboundProcessingInfo, - message_proof: Proof, - ) -> DispatchResult { - for inbound_router in &inbound_processing_info.inbound_routers { - match PendingInboundEntries::::try_mutate( - inbound_processing_info.current_session_id, - (message_proof, inbound_router), - |storage_entry| match storage_entry { - None => Err(Error::::PendingInboundEntryNotFound.into()), - Some(stored_inbound_entry) => match stored_inbound_entry { - InboundEntry::Message { - expected_proof_count, - .. - } => { - let updated_count = (*expected_proof_count).ensure_sub( - inbound_processing_info.expected_proof_count_per_message, - )?; - - if updated_count == 0 { - *storage_entry = None; - } else { - *expected_proof_count = updated_count; - } - - Ok::<(), DispatchError>(()) - } - InboundEntry::Proof { current_count } => { - let updated_count = (*current_count).ensure_sub(1)?; - - if updated_count == 0 { - *storage_entry = None; - } else { - *current_count = updated_count; - } - - Ok::<(), DispatchError>(()) - } - }, - }, - ) { - Ok(()) => {} - Err(e) => return Err(e), - } - } - - Ok(()) - } - - /// Retrieves the information required for processing an inbound - /// message. - fn get_inbound_processing_info( - domain_address: DomainAddress, - weight: &mut Weight, - ) -> Result, DispatchError> { - let inbound_routers = InboundRouters::::get(domain_address.domain()) - .ok_or(Error::::MultiRouterNotFound)?; - - weight.saturating_accrue(T::DbWeight::get().reads(1)); - - let current_session_id = InboundMessageSessions::::get(domain_address.domain()) - .ok_or(Error::::InboundDomainSessionNotFound)?; - - weight.saturating_accrue(T::DbWeight::get().reads(1)); - - let expected_proof_count = Self::get_expected_proof_count(&domain_address.domain())?; - - weight.saturating_accrue(T::DbWeight::get().reads(1)); - - Ok(InboundProcessingInfo { - domain_address, - inbound_routers, - current_session_id, - expected_proof_count_per_message: expected_proof_count, - }) - } - - /// Iterates over a batch of messages and checks if the requirements for - /// processing each message are met. - fn process_inbound_message( - domain_address: DomainAddress, - message: T::Message, - router_hash: T::Hash, - ) -> (DispatchResult, Weight) { - let mut weight = Default::default(); - - let inbound_processing_info = - match Self::get_inbound_processing_info(domain_address.clone(), &mut weight) { - Ok(i) => i, - Err(e) => return (Err(e), weight), - }; - - weight.saturating_accrue( - Weight::from_parts(0, T::Message::max_encoded_len() as u64) - .saturating_add(LP_DEFENSIVE_WEIGHT), - ); - - let mut count = 0; - - for submessage in message.submessages() { - count += 1; - - let message_proof = Self::get_message_proof(message.clone()); - - if let Err(e) = Self::validate_and_update_pending_entries( - &inbound_processing_info, - submessage.clone(), - message_proof, - router_hash, - &mut weight, - ) { - return (Err(e), weight); - } - - match Self::get_executable_message(&inbound_processing_info, message_proof) { - Some(m) => { - if let Err(e) = Self::decrease_pending_entries_counts( - &inbound_processing_info, - message_proof, - ) { - return (Err(e), weight.saturating_mul(count)); - } - - if let Err(e) = T::InboundMessageHandler::handle(domain_address.clone(), m) - { - // We only consume the processed weight if error during the batch - return (Err(e), weight.saturating_mul(count)); - } - } - None => continue, - } - } - - (Ok(()), LP_DEFENSIVE_WEIGHT.saturating_mul(count)) - } - - /// Retrieves the stored router, sends the message, and calculates and - /// returns the router operation result and the weight used. - fn process_outbound_message( - sender: T::AccountId, - message: T::Message, - router_hash: T::Hash, - ) -> (DispatchResult, Weight) { - let router_ids = T::RouterId::for_domain(domain); - - let Some(router) = OutboundRouters::::get(router_hash) else { - return (Err(Error::::RouterNotFound.into()), read_weight); - }; - - let mut count = 0; - let bytes = message.serialize(); - - for router_id in router_ids { - count += 1; - if let Err(e) = T::MessageSender::send(router_id, sender.clone(), bytes.clone()) { - return (Err(e), LP_DEFENSIVE_WEIGHT.saturating_mul(count)); - } - } - - // TODO: Should we fix weights? - (Ok(()), LP_DEFENSIVE_WEIGHT.saturating_mul(count)) - } - - /// Retrieves the hashes of the routers set for a domain and queues the - /// message and proofs accordingly. - fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { - let router_hashes = OutboundDomainRouters::::get(destination.clone()) - .ok_or(Error::::MultiRouterNotFound)?; - - let message_proof = message.to_message_proof(); - let mut message_opt = Some(message); - - for router_hash in router_hashes { - // Ensure that we only send the actual message once, using one router. - // The remaining routers will send the message proof. - let router_msg = match message_opt.take() { - Some(m) => m, - None => message_proof.clone(), - }; - - // We are using the sender specified in the pallet config so that we can - // ensure that the account is funded - let gateway_message = - GatewayMessage::::Outbound { - sender: T::Sender::get(), - message: router_msg, - router_hash, - }; - - T::MessageQueue::submit(gateway_message)?; - } - - Ok(()) - } - } - impl OutboundMessageHandler for Pallet { type Destination = Domain; type Message = T::Message; diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs new file mode 100644 index 0000000000..9b939329ef --- /dev/null +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -0,0 +1,417 @@ +use cfg_primitives::LP_DEFENSIVE_WEIGHT; +use cfg_traits::liquidity_pools::{InboundMessageHandler, LPEncoding, MessageQueue, Proof, Router}; +use cfg_types::domain_address::{Domain, DomainAddress}; +use frame_support::{ + dispatch::DispatchResult, + ensure, + pallet_prelude::{Decode, Encode, Get, TypeInfo}, + weights::Weight, + BoundedVec, +}; +use parity_scale_codec::MaxEncodedLen; +use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub}; +use sp_runtime::DispatchError; + +use crate::{ + message::GatewayMessage, Config, Error, InboundMessageSessions, InboundRouters, + OutboundDomainRouters, OutboundRouters, Pallet, PendingInboundEntries, +}; + +/// Type used when storing inbound message information. +#[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub enum InboundEntry { + Message { + domain_address: DomainAddress, + message: T::Message, + expected_proof_count: u32, + }, + Proof { + current_count: u32, + }, +} + +/// Type used when processing inbound messages. +#[derive(Clone)] +pub struct InboundProcessingInfo { + domain_address: DomainAddress, + inbound_routers: BoundedVec, + current_session_id: T::SessionId, + expected_proof_count_per_message: u32, +} + +impl Pallet { + /// Calculates and returns the proof count required for processing one + /// inbound message. + fn get_expected_proof_count(domain: &Domain) -> Result { + let routers = InboundRouters::::get(domain).ok_or(Error::::MultiRouterNotFound)?; + + let expected_proof_count = routers.len().ensure_sub(1)?; + + Ok(expected_proof_count as u32) + } + + /// Gets the message proof for a message. + fn get_message_proof(message: T::Message) -> Proof { + match message.get_message_proof() { + None => message + .to_message_proof() + .get_message_proof() + .expect("message proof ensured by 'to_message_proof'"), + Some(proof) => proof, + } + } + + /// Creates an inbound entry based on whether the inbound message is a + /// proof or not. + fn create_inbound_entry( + domain_address: DomainAddress, + message: T::Message, + expected_proof_count: u32, + ) -> InboundEntry { + match message.get_message_proof() { + None => InboundEntry::Message { + domain_address, + message, + expected_proof_count, + }, + Some(_) => InboundEntry::Proof { current_count: 1 }, + } + } + + /// Validation ensures that: + /// + /// - the router that sent the inbound message is a valid router for the + /// specific domain. + /// - messages are only sent by the first inbound router. + /// - proofs are not sent by the first inbound router. + fn validate_inbound_entry( + inbound_processing_info: &InboundProcessingInfo, + router_hash: T::Hash, + inbound_entry: &InboundEntry, + ) -> DispatchResult { + let inbound_routers = inbound_processing_info.inbound_routers.clone(); + + ensure!( + inbound_routers.iter().any(|x| x == &router_hash), + Error::::UnknownInboundMessageRouter + ); + + match inbound_entry { + InboundEntry::Message { .. } => { + ensure!( + inbound_routers.get(0) == Some(&router_hash), + Error::::MessageExpectedFromFirstRouter + ); + + Ok(()) + } + InboundEntry::Proof { .. } => { + ensure!( + inbound_routers.get(0) != Some(&router_hash), + Error::::ProofNotExpectedFromFirstRouter + ); + + Ok(()) + } + } + } + + /// Updates the inbound entry for a particular message, increasing the + /// counts accordingly. + fn update_pending_entry( + session_id: T::SessionId, + message_proof: Proof, + router_hash: T::Hash, + inbound_entry: InboundEntry, + weight: &mut Weight, + ) -> DispatchResult { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + PendingInboundEntries::::try_mutate( + session_id, + (message_proof, router_hash), + |storage_entry| match storage_entry { + None => { + *storage_entry = Some(inbound_entry); + + Ok::<(), DispatchError>(()) + } + Some(stored_inbound_entry) => match stored_inbound_entry { + InboundEntry::Message { + expected_proof_count: old, + .. + } => match inbound_entry { + InboundEntry::Message { + expected_proof_count: new, + .. + } => old.ensure_add_assign(new).map_err(|e| e.into()), + InboundEntry::Proof { .. } => Err(Error::::ExpectedMessageType.into()), + }, + InboundEntry::Proof { current_count: old } => match inbound_entry { + InboundEntry::Proof { current_count: new } => { + old.ensure_add_assign(new).map_err(|e| e.into()) + } + InboundEntry::Message { .. } => { + Err(Error::::ExpectedMessageProofType.into()) + } + }, + }, + }, + ) + } + + /// Creates, validates and updates the inbound entry. + fn validate_and_update_pending_entries( + inbound_processing_info: &InboundProcessingInfo, + message: T::Message, + message_proof: Proof, + router_hash: T::Hash, + weight: &mut Weight, + ) -> DispatchResult { + let inbound_entry = Self::create_inbound_entry( + inbound_processing_info.domain_address.clone(), + message, + inbound_processing_info.expected_proof_count_per_message, + ); + + Self::validate_inbound_entry(&inbound_processing_info, router_hash, &inbound_entry)?; + + Self::update_pending_entry( + inbound_processing_info.current_session_id, + message_proof, + router_hash, + inbound_entry, + weight, + )?; + + Ok(()) + } + + /// Checks if the number of proofs required for executing one message + /// were received, and returns the message if so. + fn get_executable_message( + inbound_processing_info: &InboundProcessingInfo, + message_proof: Proof, + ) -> Option { + let mut message = None; + let mut votes = 0; + + for inbound_router in &inbound_processing_info.inbound_routers { + match PendingInboundEntries::::get( + inbound_processing_info.current_session_id, + (message_proof, inbound_router), + ) { + // We expected one InboundEntry for each router, if that's not the case, + // we can return. + None => return None, + Some(inbound_entry) => match inbound_entry { + InboundEntry::Message { + message: stored_message, + .. + } => message = Some(stored_message), + InboundEntry::Proof { current_count } => { + if current_count > 0 { + votes += 1; + } + } + }, + }; + } + + if votes == inbound_processing_info.expected_proof_count_per_message { + return message; + } + + None + } + + /// Decreases the counts for inbound entries and removes them if the + /// counts reach 0. + fn decrease_pending_entries_counts( + inbound_processing_info: &InboundProcessingInfo, + message_proof: Proof, + ) -> DispatchResult { + for inbound_router in &inbound_processing_info.inbound_routers { + match PendingInboundEntries::::try_mutate( + inbound_processing_info.current_session_id, + (message_proof, inbound_router), + |storage_entry| match storage_entry { + None => Err(Error::::PendingInboundEntryNotFound.into()), + Some(stored_inbound_entry) => match stored_inbound_entry { + InboundEntry::Message { + expected_proof_count, + .. + } => { + let updated_count = (*expected_proof_count).ensure_sub( + inbound_processing_info.expected_proof_count_per_message, + )?; + + if updated_count == 0 { + *storage_entry = None; + } else { + *expected_proof_count = updated_count; + } + + Ok::<(), DispatchError>(()) + } + InboundEntry::Proof { current_count } => { + let updated_count = (*current_count).ensure_sub(1)?; + + if updated_count == 0 { + *storage_entry = None; + } else { + *current_count = updated_count; + } + + Ok::<(), DispatchError>(()) + } + }, + }, + ) { + Ok(()) => {} + Err(e) => return Err(e), + } + } + + Ok(()) + } + + /// Retrieves the information required for processing an inbound + /// message. + fn get_inbound_processing_info( + domain_address: DomainAddress, + weight: &mut Weight, + ) -> Result, DispatchError> { + let inbound_routers = InboundRouters::::get(domain_address.domain()) + .ok_or(Error::::MultiRouterNotFound)?; + + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + let current_session_id = InboundMessageSessions::::get(domain_address.domain()) + .ok_or(Error::::InboundDomainSessionNotFound)?; + + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + let expected_proof_count = Self::get_expected_proof_count(&domain_address.domain())?; + + weight.saturating_accrue(T::DbWeight::get().reads(1)); + + Ok(InboundProcessingInfo { + domain_address, + inbound_routers, + current_session_id, + expected_proof_count_per_message: expected_proof_count, + }) + } + + /// Iterates over a batch of messages and checks if the requirements for + /// processing each message are met. + pub(crate) fn process_inbound_message( + domain_address: DomainAddress, + message: T::Message, + router_hash: T::Hash, + ) -> (DispatchResult, Weight) { + let mut weight = Default::default(); + + let inbound_processing_info = + match Self::get_inbound_processing_info(domain_address.clone(), &mut weight) { + Ok(i) => i, + Err(e) => return (Err(e), weight), + }; + + weight.saturating_accrue( + Weight::from_parts(0, T::Message::max_encoded_len() as u64) + .saturating_add(LP_DEFENSIVE_WEIGHT), + ); + + let mut count = 0; + + for submessage in message.submessages() { + count += 1; + + let message_proof = Self::get_message_proof(message.clone()); + + if let Err(e) = Self::validate_and_update_pending_entries( + &inbound_processing_info, + submessage.clone(), + message_proof, + router_hash, + &mut weight, + ) { + return (Err(e), weight); + } + + match Self::get_executable_message(&inbound_processing_info, message_proof) { + Some(m) => { + if let Err(e) = Self::decrease_pending_entries_counts( + &inbound_processing_info, + message_proof, + ) { + return (Err(e), weight.saturating_mul(count)); + } + + if let Err(e) = T::InboundMessageHandler::handle(domain_address.clone(), m) { + // We only consume the processed weight if error during the batch + return (Err(e), weight.saturating_mul(count)); + } + } + None => continue, + } + } + + (Ok(()), LP_DEFENSIVE_WEIGHT.saturating_mul(count)) + } + + /// Retrieves the stored router, sends the message, and calculates and + /// returns the router operation result and the weight used. + pub(crate) fn process_outbound_message( + sender: T::AccountId, + message: T::Message, + router_hash: T::Hash, + ) -> (DispatchResult, Weight) { + let read_weight = T::DbWeight::get().reads(1); + + let Some(router) = OutboundRouters::::get(router_hash) else { + return (Err(Error::::RouterNotFound.into()), read_weight); + }; + + let (result, router_weight) = match router.send(sender, message.serialize()) { + Ok(dispatch_info) => (Ok(()), dispatch_info.actual_weight), + Err(e) => (Err(e.error), e.post_info.actual_weight), + }; + + (result, router_weight.unwrap_or(read_weight)) + } + + /// Retrieves the hashes of the routers set for a domain and queues the + /// message and proofs accordingly. + pub(crate) fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { + let router_hashes = OutboundDomainRouters::::get(destination.clone()) + .ok_or(Error::::MultiRouterNotFound)?; + + let message_proof = message.to_message_proof(); + let mut message_opt = Some(message); + + for router_hash in router_hashes { + // Ensure that we only send the actual message once, using one router. + // The remaining routers will send the message proof. + let router_msg = match message_opt.take() { + Some(m) => m, + None => message_proof.clone(), + }; + + // We are using the sender specified in the pallet config so that we can + // ensure that the account is funded + let gateway_message = GatewayMessage::::Outbound { + sender: T::Sender::get(), + message: router_msg, + router_hash, + }; + + T::MessageQueue::submit(gateway_message)?; + } + + Ok(()) + } +} diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 74908488db..772f070d4d 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -23,7 +23,7 @@ use super::{ origin::*, pallet::*, }; -use crate::{GatewayMessage, InboundEntry}; +use crate::{message_processing::InboundEntry, GatewayMessage}; pub const TEST_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(0, [1; 20]); From 57a10a074118d398fc035d3f2cb8f8918626e08b Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:28:23 +0300 Subject: [PATCH 10/38] lp-gateway: Merge inbound/outbound routers extrinsics into one, add logic for removing invalid session IDs on idle --- pallets/liquidity-pools-gateway/src/lib.rs | 176 +++++++----------- .../src/message_processing.rs | 120 ++++++++---- .../liquidity-pools-gateway/src/weights.rs | 52 +----- 3 files changed, 162 insertions(+), 186 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 844c9da020..b303500dac 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -62,6 +62,7 @@ mod tests; #[frame_support::pallet] pub mod pallet { + use frame_system::pallet_prelude::BlockNumberFor; use sp_arithmetic::traits::EnsureAdd; use super::*; @@ -75,6 +76,13 @@ pub mod pallet { #[pallet::origin] pub type Origin = GatewayOrigin; + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_idle(_now: BlockNumberFor, max_weight: Weight) -> Weight { + Self::clear_invalid_session_ids(max_weight) + } + } + #[pallet::config] pub trait Config: frame_system::Config { /// The origin type. @@ -144,6 +152,13 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub (super) fn deposit_event)] pub enum Event { + /// The routers for a given domain were set. + RoutersSet { + domain: Domain, + //TODO(cdamian): Use T::RouterId + router_ids: BoundedVec, + }, + /// An instance was added to a domain. InstanceAdded { instance: DomainAddress }, @@ -155,19 +170,24 @@ pub mod pallet { domain: Domain, hook_address: [u8; 20], }, + } - /// The outbound routers for a given domain were set. - OutboundRoutersSet { - domain: Domain, - routers: BoundedVec, - }, + // TODO(cdamian): Add migration to clear this storage. + // /// Storage for domain routers. + // /// + // /// This can only be set by an admin. + // #[pallet::storage] + // #[pallet::getter(fn domain_routers)] + // pub type DomainRouters = StorageMap<_, Blake2_128Concat, Domain, + // T::Router>; - /// Inbound routers were set. - InboundRoutersSet { - domain: Domain, - router_hashes: BoundedVec, - }, - } + /// Storage for routers specific for a domain. + /// + /// This can only be set by an admin. + #[pallet::storage] + #[pallet::getter(fn routers)] + pub type Routers = + StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; /// Storage that contains a limited number of whitelisted instances of /// deployed liquidity pools for a particular domain. @@ -194,21 +214,6 @@ pub mod pallet { pub(crate) type PackedMessage = StorageMap<_, Blake2_128Concat, (T::AccountId, Domain), T::Message>; - /// Storage for outbound routers. - /// - /// This can only be set by an admin. - #[pallet::storage] - #[pallet::getter(fn routers)] - pub type OutboundRouters = StorageMap<_, Blake2_128Concat, T::Hash, T::Router>; - - /// Storage for outbound routers specific for a domain. - /// - /// This can only be set by an admin. - #[pallet::storage] - #[pallet::getter(fn outbound_domain_routers)] - pub type OutboundDomainRouters = - StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; - /// Storage for pending inbound messages. #[pallet::storage] #[pallet::getter(fn pending_inbound_entries)] @@ -221,14 +226,6 @@ pub mod pallet { InboundEntry, >; - /// Storage for inbound routers specific for a domain. - /// - /// This can only be set by an admin. - #[pallet::storage] - #[pallet::getter(fn inbound_routers)] - pub type InboundRouters = - StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; - /// Storage for the inbound message session IDs. #[pallet::storage] #[pallet::getter(fn inbound_message_sessions)] @@ -239,6 +236,14 @@ pub mod pallet { #[pallet::storage] pub type SessionIdStore = StorageValue<_, T::SessionId, ValueQuery>; + /// Storage that keeps track of invalid session IDs. + /// + /// Any `PendingInboundEntries` mapped to the invalid IDs are removed from + /// storage during `on_idle`. + #[pallet::storage] + #[pallet::getter(fn invalid_session_ids)] + pub type InvalidSessionIds = StorageMap<_, Blake2_128Concat, T::SessionId, ()>; + #[pallet::error] pub enum Error { /// The origin of the message to be processed is invalid. @@ -303,6 +308,38 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Sets the router IDs used for a specific domain, + #[pallet::weight(T::WeightInfo::set_domain_routers())] + #[pallet::call_index(0)] + pub fn set_domain_routers( + origin: OriginFor, + domain: Domain, + //TODO(cdamian): Use T::RouterId + router_ids: BoundedVec, + ) -> DispatchResult { + T::AdminOrigin::ensure_origin(origin)?; + + //TODO(cdamian): Outbound - Call router.init() for each router? + + >::insert(domain.clone(), router_ids.clone()); + + let (old_session_id, new_session_id) = SessionIdStore::::try_mutate(|n| { + let old_session_id = *n; + let new_session_id = old_session_id.ensure_add(One::one())?; + + *n = new_session_id; + + Ok::<(T::SessionId, T::SessionId), DispatchError>((old_session_id, new_session_id)) + })?; + + InboundMessageSessions::::insert(domain.clone(), new_session_id); + InvalidSessionIds::::insert(old_session_id, ()); + + Self::deposit_event(Event::RoutersSet { domain, router_ids }); + + Ok(()) + } + /// Add a known instance of a deployed liquidity pools integration for a /// specific domain. #[pallet::weight(T::WeightInfo::add_instance())] @@ -417,81 +454,12 @@ pub mod pallet { } } - /// Set outbound routers for a particular domain. - #[pallet::weight(T::WeightInfo::set_outbound_routers())] - #[pallet::call_index(11)] - pub fn set_outbound_routers( - origin: OriginFor, - domain: Domain, - routers: BoundedVec, - ) -> DispatchResult { - T::AdminOrigin::ensure_origin(origin)?; - - ensure!(domain != Domain::Centrifuge, Error::::DomainNotSupported); - - let mut router_hashes = Vec::new(); - - for router in &routers { - router.init().map_err(|_| Error::::RouterInitFailed)?; - - let router_hash = router.hash(); - - router_hashes.push(router_hash); - - OutboundRouters::::insert(router_hash, router); - } - - >::insert( - domain.clone(), - BoundedVec::try_from(router_hashes).map_err(|_| Error::::InvalidMultiRouter)?, - ); - - Self::deposit_event(Event::OutboundRoutersSet { domain, routers }); - - Ok(()) - } - - /// Set inbound routers. - #[pallet::weight(T::WeightInfo::set_inbound_routers())] - #[pallet::call_index(12)] - pub fn set_inbound_routers( - origin: OriginFor, - domain: Domain, - router_hashes: BoundedVec, - ) -> DispatchResult { - T::AdminOrigin::ensure_origin(origin)?; - - let (old_session_id, new_session_id) = SessionIdStore::::try_mutate(|n| { - let old_session_id = *n; - let new_session_id = n.ensure_add(One::one())?; - - *n = new_session_id; - - Ok::<(T::SessionId, T::SessionId), DispatchError>((old_session_id, new_session_id)) - })?; - - InboundRouters::::insert(domain.clone(), router_hashes.clone()); - InboundMessageSessions::::insert(domain.clone(), new_session_id); - - //TODO(cdamian): The storages are updated with the new session. - // We can process the removal of entries associated with the old entries - // `on_idle`. - let _ = PendingInboundEntries::::clear_prefix(old_session_id, u32::MAX, None); - - Self::deposit_event(Event::InboundRoutersSet { - domain, - router_hashes, - }); - - Ok(()) - } - /// Manually increase the proof count for a particular message and /// executes it if the required count is reached. /// /// Can only be called by `AdminOrigin`. #[pallet::weight(T::WeightInfo::execute_message_recovery())] - #[pallet::call_index(13)] + #[pallet::call_index(11)] pub fn execute_message_recovery( origin: OriginFor, message_proof: Proof, diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 9b939329ef..e65b70f41d 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -13,10 +13,14 @@ use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub}; use sp_runtime::DispatchError; use crate::{ - message::GatewayMessage, Config, Error, InboundMessageSessions, InboundRouters, - OutboundDomainRouters, OutboundRouters, Pallet, PendingInboundEntries, + message::GatewayMessage, Config, Error, InboundMessageSessions, InvalidSessionIds, Pallet, + PendingInboundEntries, Routers, }; +/// The limit used when clearing the `PendingInboundEntries` for invalid +/// session IDs. +const INVALID_ID_REMOVAL_LIMIT: u32 = 100; + /// Type used when storing inbound message information. #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] @@ -35,7 +39,7 @@ pub enum InboundEntry { #[derive(Clone)] pub struct InboundProcessingInfo { domain_address: DomainAddress, - inbound_routers: BoundedVec, + routers: BoundedVec, current_session_id: T::SessionId, expected_proof_count_per_message: u32, } @@ -44,7 +48,7 @@ impl Pallet { /// Calculates and returns the proof count required for processing one /// inbound message. fn get_expected_proof_count(domain: &Domain) -> Result { - let routers = InboundRouters::::get(domain).ok_or(Error::::MultiRouterNotFound)?; + let routers = Routers::::get(domain).ok_or(Error::::MultiRouterNotFound)?; let expected_proof_count = routers.len().ensure_sub(1)?; @@ -90,17 +94,17 @@ impl Pallet { router_hash: T::Hash, inbound_entry: &InboundEntry, ) -> DispatchResult { - let inbound_routers = inbound_processing_info.inbound_routers.clone(); + let routers = inbound_processing_info.routers.clone(); ensure!( - inbound_routers.iter().any(|x| x == &router_hash), + routers.iter().any(|x| x == &router_hash), Error::::UnknownInboundMessageRouter ); match inbound_entry { InboundEntry::Message { .. } => { ensure!( - inbound_routers.get(0) == Some(&router_hash), + routers.get(0) == Some(&router_hash), Error::::MessageExpectedFromFirstRouter ); @@ -108,7 +112,7 @@ impl Pallet { } InboundEntry::Proof { .. } => { ensure!( - inbound_routers.get(0) != Some(&router_hash), + routers.get(0) != Some(&router_hash), Error::::ProofNotExpectedFromFirstRouter ); @@ -117,9 +121,9 @@ impl Pallet { } } - /// Updates the inbound entry for a particular message, increasing the - /// counts accordingly. - fn update_pending_entry( + /// Upserts an inbound entry for a particular message, increasing the + /// relevant counts accordingly. + fn upsert_pending_entry( session_id: T::SessionId, message_proof: Proof, router_hash: T::Hash, @@ -161,8 +165,8 @@ impl Pallet { ) } - /// Creates, validates and updates the inbound entry. - fn validate_and_update_pending_entries( + /// Creates, validates and upserts the inbound entry. + fn validate_and_upsert_pending_entries( inbound_processing_info: &InboundProcessingInfo, message: T::Message, message_proof: Proof, @@ -177,7 +181,7 @@ impl Pallet { Self::validate_inbound_entry(&inbound_processing_info, router_hash, &inbound_entry)?; - Self::update_pending_entry( + Self::upsert_pending_entry( inbound_processing_info.current_session_id, message_proof, router_hash, @@ -197,10 +201,10 @@ impl Pallet { let mut message = None; let mut votes = 0; - for inbound_router in &inbound_processing_info.inbound_routers { + for router in &inbound_processing_info.routers { match PendingInboundEntries::::get( inbound_processing_info.current_session_id, - (message_proof, inbound_router), + (message_proof, router), ) { // We expected one InboundEntry for each router, if that's not the case, // we can return. @@ -232,10 +236,10 @@ impl Pallet { inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, ) -> DispatchResult { - for inbound_router in &inbound_processing_info.inbound_routers { + for router in &inbound_processing_info.routers { match PendingInboundEntries::::try_mutate( inbound_processing_info.current_session_id, - (message_proof, inbound_router), + (message_proof, router), |storage_entry| match storage_entry { None => Err(Error::::PendingInboundEntryNotFound.into()), Some(stored_inbound_entry) => match stored_inbound_entry { @@ -283,8 +287,8 @@ impl Pallet { domain_address: DomainAddress, weight: &mut Weight, ) -> Result, DispatchError> { - let inbound_routers = InboundRouters::::get(domain_address.domain()) - .ok_or(Error::::MultiRouterNotFound)?; + let routers = + Routers::::get(domain_address.domain()).ok_or(Error::::MultiRouterNotFound)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -299,7 +303,7 @@ impl Pallet { Ok(InboundProcessingInfo { domain_address, - inbound_routers, + routers, current_session_id, expected_proof_count_per_message: expected_proof_count, }) @@ -332,7 +336,7 @@ impl Pallet { let message_proof = Self::get_message_proof(message.clone()); - if let Err(e) = Self::validate_and_update_pending_entries( + if let Err(e) = Self::validate_and_upsert_pending_entries( &inbound_processing_info, submessage.clone(), message_proof, @@ -372,23 +376,27 @@ impl Pallet { ) -> (DispatchResult, Weight) { let read_weight = T::DbWeight::get().reads(1); - let Some(router) = OutboundRouters::::get(router_hash) else { - return (Err(Error::::RouterNotFound.into()), read_weight); - }; + // TODO(cdamian): Update when the router refactor is done. - let (result, router_weight) = match router.send(sender, message.serialize()) { - Ok(dispatch_info) => (Ok(()), dispatch_info.actual_weight), - Err(e) => (Err(e.error), e.post_info.actual_weight), - }; + // let Some(router) = Routers::::get(router_hash) else { + // return (Err(Error::::RouterNotFound.into()), read_weight); + // }; + // + // let (result, router_weight) = match router.send(sender, message.serialize()) + // { Ok(dispatch_info) => (Ok(()), dispatch_info.actual_weight), + // Err(e) => (Err(e.error), e.post_info.actual_weight), + // }; + // + // (result, router_weight.unwrap_or(read_weight)) - (result, router_weight.unwrap_or(read_weight)) + (Ok(()), read_weight) } /// Retrieves the hashes of the routers set for a domain and queues the /// message and proofs accordingly. pub(crate) fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { - let router_hashes = OutboundDomainRouters::::get(destination.clone()) - .ok_or(Error::::MultiRouterNotFound)?; + let router_hashes = + Routers::::get(destination.clone()).ok_or(Error::::MultiRouterNotFound)?; let message_proof = message.to_message_proof(); let mut message_opt = Some(message); @@ -414,4 +422,52 @@ impl Pallet { Ok(()) } + + /// Clears `PendingInboundEntries` mapped to invalid session IDs as long as + /// there is enough weight available for this operation. + /// + /// The invalid session IDs are removed from storage if all entries mapped + /// to them were cleared. + pub(crate) fn clear_invalid_session_ids(max_weight: Weight) -> Weight { + let invalid_session_ids = InvalidSessionIds::::iter_keys().collect::>(); + + let mut weight = T::DbWeight::get().reads(1); + + for invalid_session_id in invalid_session_ids { + let mut cursor: Option> = None; + + loop { + let res = PendingInboundEntries::::clear_prefix( + invalid_session_id, + INVALID_ID_REMOVAL_LIMIT, + cursor.as_ref().map(|x| x.as_ref()), + ); + + weight.saturating_accrue( + T::DbWeight::get().reads_writes(res.loops.into(), res.unique.into()), + ); + + if weight.all_gte(max_weight) { + return weight; + } + + cursor = match res.maybe_cursor { + None => { + InvalidSessionIds::::remove(invalid_session_id); + + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + if weight.all_gte(max_weight) { + return weight; + } + + break; + } + Some(c) => Some(c), + }; + } + } + + weight + } } diff --git a/pallets/liquidity-pools-gateway/src/weights.rs b/pallets/liquidity-pools-gateway/src/weights.rs index c568dfc4bf..aaf598ec91 100644 --- a/pallets/liquidity-pools-gateway/src/weights.rs +++ b/pallets/liquidity-pools-gateway/src/weights.rs @@ -13,20 +13,16 @@ use frame_support::weights::{constants::RocksDbWeight, Weight}; pub trait WeightInfo { - fn set_domain_router() -> Weight; + fn set_domain_routers() -> Weight; fn add_instance() -> Weight; fn remove_instance() -> Weight; fn add_relayer() -> Weight; fn remove_relayer() -> Weight; fn receive_message() -> Weight; - fn process_outbound_message() -> Weight; - fn process_failed_outbound_message() -> Weight; fn start_batch_message() -> Weight; fn end_batch_message() -> Weight; fn set_domain_hook_address() -> Weight; - fn set_outbound_routers() -> Weight; fn execute_message_recovery() -> Weight; - fn set_inbound_routers() -> Weight; } // NOTE: We use temporary weights here. `execute_epoch` is by far our heaviest @@ -35,7 +31,7 @@ pub trait WeightInfo { const N: u64 = 4; impl WeightInfo for () { - fn set_domain_router() -> Weight { + fn set_domain_routers() -> Weight { // TODO: BENCHMARK CORRECTLY // // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` @@ -107,28 +103,6 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 17774).saturating_mul(N)) } - fn process_outbound_message() -> Weight { - // TODO: BENCHMARK CORRECTLY - // - // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` - // This one has one read and one write for sure and possible one - // read for `AdminOrigin` - Weight::from_parts(30_117_000, 5991) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - - fn process_failed_outbound_message() -> Weight { - // TODO: BENCHMARK CORRECTLY - // - // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` - // This one has one read and one write for sure and possible one - // read for `AdminOrigin` - Weight::from_parts(30_117_000, 5991) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - fn start_batch_message() -> Weight { // TODO: BENCHMARK CORRECTLY // @@ -162,17 +136,6 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(2)) } - fn set_outbound_routers() -> Weight { - // TODO: BENCHMARK CORRECTLY - // - // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` - // This one has one read and one write for sure and possible one - // read for `AdminOrigin` - Weight::from_parts(30_117_000, 5991) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - fn execute_message_recovery() -> Weight { // TODO: BENCHMARK CORRECTLY // @@ -183,15 +146,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(2)) } - - fn set_inbound_routers() -> Weight { - // TODO: BENCHMARK CORRECTLY - // - // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` - // This one has one read and one write for sure and possible one - // read for `AdminOrigin` - Weight::from_parts(30_117_000, 5991) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(2)) - } } From d1d032e423e85d9abf718fa0474a8693279f1c48 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Mon, 12 Aug 2024 21:01:47 +0300 Subject: [PATCH 11/38] lp-gateway: Unit tests WIP --- pallets/liquidity-pools-gateway/src/lib.rs | 31 +- .../liquidity-pools-gateway/src/message.rs | 10 +- .../src/message_processing.rs | 59 ++- pallets/liquidity-pools-gateway/src/mock.rs | 2 - pallets/liquidity-pools-gateway/src/tests.rs | 429 +++++++++++------- 5 files changed, 314 insertions(+), 217 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index b303500dac..5d91616e26 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -40,9 +40,8 @@ use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; use parity_scale_codec::{EncodeLike, FullCodec}; -use sp_arithmetic::traits::{BaseArithmetic, EnsureSub, One}; -use sp_runtime::traits::EnsureAddAssign; -use sp_std::{convert::TryInto, vec::Vec}; +use sp_arithmetic::traits::{BaseArithmetic, One}; +use sp_std::convert::TryInto; use crate::{message_processing::InboundEntry, weights::WeightInfo}; @@ -131,7 +130,7 @@ pub mod pallet { /// Type used for queueing messages. type MessageQueue: MessageQueue< - Message = GatewayMessage, + Message = GatewayMessage, >; /// Maximum number of routers allowed for a domain. @@ -155,8 +154,7 @@ pub mod pallet { /// The routers for a given domain were set. RoutersSet { domain: Domain, - //TODO(cdamian): Use T::RouterId - router_ids: BoundedVec, + router_ids: BoundedVec, }, /// An instance was added to a domain. @@ -187,7 +185,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn routers)] pub type Routers = - StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; + StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; /// Storage that contains a limited number of whitelisted instances of /// deployed liquidity pools for a particular domain. @@ -222,7 +220,7 @@ pub mod pallet { Blake2_128Concat, T::SessionId, Blake2_128Concat, - (Proof, T::Hash), + (Proof, T::RouterId), InboundEntry, >; @@ -314,11 +312,12 @@ pub mod pallet { pub fn set_domain_routers( origin: OriginFor, domain: Domain, - //TODO(cdamian): Use T::RouterId - router_ids: BoundedVec, + router_ids: BoundedVec, ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; + ensure!(domain != Domain::Centrifuge, Error::::DomainNotSupported); + //TODO(cdamian): Outbound - Call router.init() for each router? >::insert(domain.clone(), router_ids.clone()); @@ -462,8 +461,8 @@ pub mod pallet { #[pallet::call_index(11)] pub fn execute_message_recovery( origin: OriginFor, + domain: Domain, message_proof: Proof, - proof_count: u32, ) -> DispatchResult { //TODO(cdamian): Implement this. unimplemented!() @@ -499,20 +498,20 @@ pub mod pallet { } impl MessageProcessor for Pallet { - type Message = GatewayMessage; + type Message = GatewayMessage; fn process(msg: Self::Message) -> (DispatchResult, Weight) { match msg { GatewayMessage::Inbound { domain_address, message, - router_hash, - } => Self::process_inbound_message(domain_address, message, router_hash), + router_id, + } => Self::process_inbound_message(domain_address, message, router_id), GatewayMessage::Outbound { sender, message, - router_hash, - } => Self::process_outbound_message(sender, message, router_hash), + router_id, + } => Self::process_outbound_message(sender, message, router_id), } } diff --git a/pallets/liquidity-pools-gateway/src/message.rs b/pallets/liquidity-pools-gateway/src/message.rs index 42226a46eb..0d6fc4ff38 100644 --- a/pallets/liquidity-pools-gateway/src/message.rs +++ b/pallets/liquidity-pools-gateway/src/message.rs @@ -1,18 +1,18 @@ -use cfg_types::domain_address::{Domain, DomainAddress}; +use cfg_types::domain_address::DomainAddress; use frame_support::pallet_prelude::{Decode, Encode, MaxEncodedLen, TypeInfo}; /// Message type used by the LP gateway. #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] -pub enum GatewayMessage { +pub enum GatewayMessage { Inbound { domain_address: DomainAddress, message: Message, - router_hash: Hash, + router_id: RouterId, }, Outbound { sender: AccountId, message: Message, - router_hash: Hash, + router_id: RouterId, }, } @@ -23,7 +23,7 @@ impl Default GatewayMessage::Inbound { domain_address: Default::default(), message: Default::default(), - router_hash: Default::default(), + router_id: Default::default(), } } } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index e65b70f41d..c627aa3d9c 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -1,5 +1,5 @@ use cfg_primitives::LP_DEFENSIVE_WEIGHT; -use cfg_traits::liquidity_pools::{InboundMessageHandler, LPEncoding, MessageQueue, Proof, Router}; +use cfg_traits::liquidity_pools::{InboundMessageHandler, LPEncoding, MessageQueue, Proof}; use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{ dispatch::DispatchResult, @@ -39,7 +39,7 @@ pub enum InboundEntry { #[derive(Clone)] pub struct InboundProcessingInfo { domain_address: DomainAddress, - routers: BoundedVec, + routers: BoundedVec, current_session_id: T::SessionId, expected_proof_count_per_message: u32, } @@ -91,20 +91,20 @@ impl Pallet { /// - proofs are not sent by the first inbound router. fn validate_inbound_entry( inbound_processing_info: &InboundProcessingInfo, - router_hash: T::Hash, + router_id: &T::RouterId, inbound_entry: &InboundEntry, ) -> DispatchResult { let routers = inbound_processing_info.routers.clone(); ensure!( - routers.iter().any(|x| x == &router_hash), + routers.iter().any(|x| x == router_id), Error::::UnknownInboundMessageRouter ); match inbound_entry { InboundEntry::Message { .. } => { ensure!( - routers.get(0) == Some(&router_hash), + routers.get(0) == Some(&router_id), Error::::MessageExpectedFromFirstRouter ); @@ -112,7 +112,7 @@ impl Pallet { } InboundEntry::Proof { .. } => { ensure!( - routers.get(0) != Some(&router_hash), + routers.get(0) != Some(&router_id), Error::::ProofNotExpectedFromFirstRouter ); @@ -126,7 +126,7 @@ impl Pallet { fn upsert_pending_entry( session_id: T::SessionId, message_proof: Proof, - router_hash: T::Hash, + router_id: T::RouterId, inbound_entry: InboundEntry, weight: &mut Weight, ) -> DispatchResult { @@ -134,7 +134,7 @@ impl Pallet { PendingInboundEntries::::try_mutate( session_id, - (message_proof, router_hash), + (message_proof, router_id), |storage_entry| match storage_entry { None => { *storage_entry = Some(inbound_entry); @@ -170,7 +170,7 @@ impl Pallet { inbound_processing_info: &InboundProcessingInfo, message: T::Message, message_proof: Proof, - router_hash: T::Hash, + router_id: T::RouterId, weight: &mut Weight, ) -> DispatchResult { let inbound_entry = Self::create_inbound_entry( @@ -179,12 +179,12 @@ impl Pallet { inbound_processing_info.expected_proof_count_per_message, ); - Self::validate_inbound_entry(&inbound_processing_info, router_hash, &inbound_entry)?; + Self::validate_inbound_entry(&inbound_processing_info, &router_id, &inbound_entry)?; Self::upsert_pending_entry( inbound_processing_info.current_session_id, message_proof, - router_hash, + router_id, inbound_entry, weight, )?; @@ -197,11 +197,14 @@ impl Pallet { fn get_executable_message( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, + weight: &mut Weight, ) -> Option { let mut message = None; let mut votes = 0; for router in &inbound_processing_info.routers { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + match PendingInboundEntries::::get( inbound_processing_info.current_session_id, (message_proof, router), @@ -235,8 +238,11 @@ impl Pallet { fn decrease_pending_entries_counts( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, + weight: &mut Weight, ) -> DispatchResult { for router in &inbound_processing_info.routers { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + match PendingInboundEntries::::try_mutate( inbound_processing_info.current_session_id, (message_proof, router), @@ -314,7 +320,7 @@ impl Pallet { pub(crate) fn process_inbound_message( domain_address: DomainAddress, message: T::Message, - router_hash: T::Hash, + router_id: T::RouterId, ) -> (DispatchResult, Weight) { let mut weight = Default::default(); @@ -340,17 +346,19 @@ impl Pallet { &inbound_processing_info, submessage.clone(), message_proof, - router_hash, + router_id.clone(), &mut weight, ) { return (Err(e), weight); } - match Self::get_executable_message(&inbound_processing_info, message_proof) { + match Self::get_executable_message(&inbound_processing_info, message_proof, &mut weight) + { Some(m) => { if let Err(e) = Self::decrease_pending_entries_counts( &inbound_processing_info, message_proof, + &mut weight, ) { return (Err(e), weight.saturating_mul(count)); } @@ -364,7 +372,7 @@ impl Pallet { } } - (Ok(()), LP_DEFENSIVE_WEIGHT.saturating_mul(count)) + (Ok(()), weight.saturating_mul(count)) } /// Retrieves the stored router, sends the message, and calculates and @@ -372,13 +380,13 @@ impl Pallet { pub(crate) fn process_outbound_message( sender: T::AccountId, message: T::Message, - router_hash: T::Hash, + router_id: T::RouterId, ) -> (DispatchResult, Weight) { let read_weight = T::DbWeight::get().reads(1); // TODO(cdamian): Update when the router refactor is done. - // let Some(router) = Routers::::get(router_hash) else { + // let Some(router) = Routers::::get(router_id) else { // return (Err(Error::::RouterNotFound.into()), read_weight); // }; // @@ -392,16 +400,16 @@ impl Pallet { (Ok(()), read_weight) } - /// Retrieves the hashes of the routers set for a domain and queues the + /// Retrieves the IDs of the routers set for a domain and queues the /// message and proofs accordingly. pub(crate) fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { - let router_hashes = + let router_ids = Routers::::get(destination.clone()).ok_or(Error::::MultiRouterNotFound)?; let message_proof = message.to_message_proof(); let mut message_opt = Some(message); - for router_hash in router_hashes { + for router_id in router_ids { // Ensure that we only send the actual message once, using one router. // The remaining routers will send the message proof. let router_msg = match message_opt.take() { @@ -411,11 +419,12 @@ impl Pallet { // We are using the sender specified in the pallet config so that we can // ensure that the account is funded - let gateway_message = GatewayMessage::::Outbound { - sender: T::Sender::get(), - message: router_msg, - router_hash, - }; + let gateway_message = + GatewayMessage::::Outbound { + sender: T::Sender::get(), + message: router_msg, + router_id, + }; T::MessageQueue::submit(gateway_message)?; } diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index d423806265..92664ae081 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -171,8 +171,6 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type WeightInfo = (); } -/* pub fn new_test_ext() -> sp_io::TestExternalities { System::externalities() } -*/ diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 772f070d4d..f8da936f1a 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; -use cfg_mocks::*; use cfg_primitives::LP_DEFENSIVE_WEIGHT; -use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler, Proof}; +use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler}; use cfg_types::domain_address::*; use frame_support::{ assert_err, assert_noop, assert_ok, dispatch::PostDispatchInfo, pallet_prelude::Pays, @@ -12,7 +11,7 @@ use itertools::Itertools; use lazy_static::lazy_static; use parity_scale_codec::MaxEncodedLen; use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160, H256}; -use sp_runtime::{DispatchError, DispatchError::BadOrigin, DispatchErrorWithPostInfo}; +use sp_runtime::{DispatchError, DispatchError::BadOrigin}; use sp_std::sync::{ atomic::{AtomicU32, Ordering}, Arc, @@ -54,63 +53,77 @@ mod utils { use utils::*; -mod set_domain_router { +mod set_domain_routers { use super::*; #[test] fn success() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); - let router = RouterMock::::default(); - router.mock_init(move || Ok(())); - assert_ok!(LiquidityPoolsGateway::set_domain_router( + let router_id_1 = H256::from_low_u64_be(1); + let router_id_2 = H256::from_low_u64_be(2); + let router_id_3 = H256::from_low_u64_be(3); + + //TODO(cdamian): Enable this after we figure out router init? + // let router = RouterMock::::default(); + // router.mock_init(move || Ok(())); + + let router_ids = + BoundedVec::try_from(vec![router_id_1, router_id_2, router_id_3]).unwrap(); + + assert_ok!(LiquidityPoolsGateway::set_domain_routers( RuntimeOrigin::root(), domain.clone(), - router.clone(), + router_ids.clone(), )); - let storage_entry = DomainRouters::::get(domain.clone()); - assert_eq!(storage_entry.unwrap(), router); - - event_exists(Event::::DomainRouterSet { domain, router }); - }); - } - #[test] - fn router_init_error() { - new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let router = RouterMock::::default(); - router.mock_init(move || Err(DispatchError::Other("error"))); - - assert_noop!( - LiquidityPoolsGateway::set_domain_router( - RuntimeOrigin::root(), - domain.clone(), - router, - ), - Error::::RouterInitFailed, + assert_eq!(Routers::::get(domain.clone()).unwrap(), router_ids); + assert_eq!( + InboundMessageSessions::::get(domain.clone()), + Some(1) ); + assert_eq!(InvalidSessionIds::::get(0), Some(())); + + event_exists(Event::::RoutersSet { domain, router_ids }); }); } + //TODO(cdamian): Enable this after we figure out router init? + // + // fn router_init_error() { + // new_test_ext().execute_with(|| { + // let domain = Domain::EVM(0); + // let router = RouterMock::::default(); + // router.mock_init(move || Err(DispatchError::Other("error"))); + // + // assert_noop!( + // LiquidityPoolsGateway::set_domain_router( + // RuntimeOrigin::root(), + // domain.clone(), + // router, + // ), + // Error::::RouterInitFailed, + // ); + // }); + // } #[test] fn bad_origin() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); - let router = RouterMock::::default(); assert_noop!( - LiquidityPoolsGateway::set_domain_router( + LiquidityPoolsGateway::set_domain_routers( RuntimeOrigin::signed(get_test_account_id()), domain.clone(), - router, + BoundedVec::try_from(vec![]).unwrap(), ), BadOrigin ); - let storage_entry = DomainRouters::::get(domain); - assert!(storage_entry.is_none()); + assert!(Routers::::get(domain.clone()).is_none()); + assert!(InboundMessageSessions::::get(domain).is_none()); + assert!(InvalidSessionIds::::get(0).is_none()); }); } @@ -118,19 +131,19 @@ mod set_domain_router { fn unsupported_domain() { new_test_ext().execute_with(|| { let domain = Domain::Centrifuge; - let router = RouterMock::::default(); assert_noop!( - LiquidityPoolsGateway::set_domain_router( + LiquidityPoolsGateway::set_domain_routers( RuntimeOrigin::root(), domain.clone(), - router + BoundedVec::try_from(vec![]).unwrap(), ), Error::::DomainNotSupported ); - let storage_entry = DomainRouters::::get(domain); - assert!(storage_entry.is_none()); + assert!(Routers::::get(domain.clone()).is_none()); + assert!(InboundMessageSessions::::get(domain).is_none()); + assert!(InvalidSessionIds::::get(0).is_none()); }); } } @@ -295,6 +308,8 @@ mod receive_message_domain { let domain_address = DomainAddress::EVM(0, address.into()); let message = Message::Simple; + let router_id = H256::from_low_u64_be(1); + assert_ok!(LiquidityPoolsGateway::add_instance( RuntimeOrigin::root(), domain_address.clone(), @@ -305,7 +320,7 @@ mod receive_message_domain { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_hash: H256::from_low_u64_be(1), + router_id, }; MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { @@ -315,6 +330,7 @@ mod receive_message_domain { assert_ok!(LiquidityPoolsGateway::receive_message( GatewayOrigin::Domain(domain_address).into(), + router_id, BoundedVec::::try_from(encoded_msg).unwrap() )); }); @@ -325,9 +341,12 @@ mod receive_message_domain { new_test_ext().execute_with(|| { let encoded_msg = Message::Simple.serialize(); + let router_id = H256::from_low_u64_be(1); + assert_noop!( LiquidityPoolsGateway::receive_message( RuntimeOrigin::signed(AccountId32::new([0u8; 32])), + router_id, BoundedVec::::try_from(encoded_msg).unwrap() ), BadOrigin, @@ -340,10 +359,12 @@ mod receive_message_domain { new_test_ext().execute_with(|| { let domain_address = DomainAddress::Centrifuge(get_test_account_id().into()); let encoded_msg = Message::Simple.serialize(); + let router_id = H256::from_low_u64_be(1); assert_noop!( LiquidityPoolsGateway::receive_message( GatewayOrigin::Domain(domain_address).into(), + router_id, BoundedVec::::try_from(encoded_msg).unwrap() ), Error::::InvalidMessageOrigin, @@ -357,10 +378,12 @@ mod receive_message_domain { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); let domain_address = DomainAddress::EVM(0, address.into()); let encoded_msg = Message::Simple.serialize(); + let router_id = H256::from_low_u64_be(1); assert_noop!( LiquidityPoolsGateway::receive_message( GatewayOrigin::Domain(domain_address).into(), + router_id, BoundedVec::::try_from(encoded_msg).unwrap() ), Error::::UnknownInstance, @@ -375,6 +398,8 @@ mod receive_message_domain { let domain_address = DomainAddress::EVM(0, address.into()); let message = Message::Simple; + let router_id = H256::from_low_u64_be(1); + assert_ok!(LiquidityPoolsGateway::add_instance( RuntimeOrigin::root(), domain_address.clone(), @@ -387,7 +412,7 @@ mod receive_message_domain { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_hash: H256::from_low_u64_be(1), + router_id, }; MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { @@ -398,6 +423,7 @@ mod receive_message_domain { assert_noop!( LiquidityPoolsGateway::receive_message( GatewayOrigin::Domain(domain_address).into(), + router_id, BoundedVec::::try_from(encoded_msg).unwrap() ), err, @@ -417,25 +443,30 @@ mod outbound_message_handler_impl { let msg = Message::Simple; let message_proof = msg.to_message_proof().get_message_proof().unwrap(); - let router_hash_1 = H256::from_low_u64_be(1); - let router_hash_2 = H256::from_low_u64_be(2); - let router_hash_3 = H256::from_low_u64_be(3); - - let router_mock_1 = RouterMock::::default(); - let router_mock_2 = RouterMock::::default(); - let router_mock_3 = RouterMock::::default(); - - router_mock_1.mock_init(move || Ok(())); - router_mock_1.mock_hash(move || router_hash_1); - router_mock_2.mock_init(move || Ok(())); - router_mock_2.mock_hash(move || router_hash_2); - router_mock_3.mock_init(move || Ok(())); - router_mock_3.mock_hash(move || router_hash_3); - - assert_ok!(LiquidityPoolsGateway::set_outbound_routers( + let router_id_1 = H256::from_low_u64_be(1); + let router_id_2 = H256::from_low_u64_be(2); + let router_id_3 = H256::from_low_u64_be(3); + + //TODO(cdamian): Router init + // let router_hash_1 = H256::from_low_u64_be(1); + // let router_hash_2 = H256::from_low_u64_be(2); + // let router_hash_3 = H256::from_low_u64_be(3); + // + // let router_mock_1 = RouterMock::::default(); + // let router_mock_2 = RouterMock::::default(); + // let router_mock_3 = RouterMock::::default(); + // + // router_mock_1.mock_init(move || Ok(())); + // router_mock_1.mock_hash(move || router_hash_1); + // router_mock_2.mock_init(move || Ok(())); + // router_mock_2.mock_hash(move || router_hash_2); + // router_mock_3.mock_init(move || Ok(())); + // router_mock_3.mock_hash(move || router_hash_3); + + assert_ok!(LiquidityPoolsGateway::set_domain_routers( RuntimeOrigin::root(), domain.clone(), - BoundedVec::try_from(vec![router_mock_1, router_mock_2, router_mock_3]).unwrap(), + BoundedVec::try_from(vec![router_id_1, router_id_2, router_id_3]).unwrap(), )); MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { @@ -485,42 +516,48 @@ mod outbound_message_handler_impl { let sender = get_test_account_id(); let msg = Message::Simple; - let router_hash_1 = H256::from_low_u64_be(1); - let router_hash_2 = H256::from_low_u64_be(2); - let router_hash_3 = H256::from_low_u64_be(3); - - let router_mock_1 = RouterMock::::default(); - let router_mock_2 = RouterMock::::default(); - let router_mock_3 = RouterMock::::default(); - - router_mock_1.mock_init(move || Ok(())); - router_mock_1.mock_hash(move || router_hash_1); - router_mock_2.mock_init(move || Ok(())); - router_mock_2.mock_hash(move || router_hash_2); - router_mock_3.mock_init(move || Ok(())); - router_mock_3.mock_hash(move || router_hash_3); - - assert_ok!(LiquidityPoolsGateway::set_outbound_routers( + let router_id_1 = H256::from_low_u64_be(1); + let router_id_2 = H256::from_low_u64_be(2); + let router_id_3 = H256::from_low_u64_be(3); + + //TODO(cdamian): Router init? + // let router_hash_1 = H256::from_low_u64_be(1); + // let router_hash_2 = H256::from_low_u64_be(2); + // let router_hash_3 = H256::from_low_u64_be(3); + // + // let router_mock_1 = RouterMock::::default(); + // let router_mock_2 = RouterMock::::default(); + // let router_mock_3 = RouterMock::::default(); + // + // router_mock_1.mock_init(move || Ok(())); + // router_mock_1.mock_hash(move || router_hash_1); + // router_mock_2.mock_init(move || Ok(())); + // router_mock_2.mock_hash(move || router_hash_2); + // router_mock_3.mock_init(move || Ok(())); + // router_mock_3.mock_hash(move || router_hash_3); + + assert_ok!(LiquidityPoolsGateway::set_domain_routers( RuntimeOrigin::root(), domain.clone(), - BoundedVec::try_from(vec![router_mock_1, router_mock_2, router_mock_3]).unwrap(), + BoundedVec::try_from(vec![router_id_1, router_id_2, router_id_3]).unwrap(), )); let gateway_message = GatewayMessage::Outbound { sender: ::Sender::get(), message: msg.clone(), - router_hash: router_hash_3, + router_id: router_id_1, }; let err = DispatchError::Unavailable; - MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { assert_eq!(mock_msg, gateway_message); Err(err) }); assert_noop!(LiquidityPoolsGateway::handle(sender, domain, msg), err); + assert_eq!(handler.times(), 1); }); } } @@ -593,7 +630,7 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - InboundRouters::::insert( + Routers::::insert( TEST_DOMAIN_ADDRESS.domain(), BoundedVec::try_from(test_routers.clone()).unwrap(), ); @@ -608,7 +645,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, message: router_message.1, - router_hash: router_message.0, + router_id: router_message.0, }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -746,10 +783,10 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_hash, + router_id: router_hash, }; - InboundRouters::::insert( + Routers::::insert( domain_address.domain(), BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), ); @@ -785,7 +822,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_hash, + router_id: router_hash, }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -802,10 +839,10 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_hash, + router_id: router_hash, }; - InboundRouters::::insert( + Routers::::insert( domain_address.domain(), BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), ); @@ -827,10 +864,10 @@ mod message_processor_impl { message: message.clone(), // The router stored has a different hash, this should trigger the expected // error. - router_hash: *ROUTER_HASH_2, + router_id: *ROUTER_HASH_2, }; - InboundRouters::::insert( + Routers::::insert( domain_address.domain(), BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), ); @@ -852,10 +889,10 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_hash, + router_id: router_hash, }; - InboundRouters::::insert( + Routers::::insert( domain_address.domain(), BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), ); @@ -1484,7 +1521,7 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - InboundRouters::::insert( + Routers::::insert( TEST_DOMAIN_ADDRESS.domain(), BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) .unwrap(), @@ -1497,7 +1534,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - router_hash: *ROUTER_HASH_2, + router_id: *ROUTER_HASH_2, }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -1510,7 +1547,7 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - InboundRouters::::insert( + Routers::::insert( TEST_DOMAIN_ADDRESS.domain(), BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) .unwrap(), @@ -1523,7 +1560,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Proof(MESSAGE_PROOF), - router_hash: *ROUTER_HASH_1, + router_id: *ROUTER_HASH_1, }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -2457,31 +2494,19 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let domain_address = DomainAddress::EVM(1, [1; 20]); - let message = Message::Proof(MESSAGE_PROOF); - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_hash: H256::from_low_u64_be(1), - }; + let router_id = H256::from_low_u64_be(1); - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_ok!(res); - - let message = Message::Proof(MESSAGE_PROOF); - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_hash: H256::from_low_u64_be(1), - }; - - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_ok!(res); + Routers::::insert( + domain_address.domain(), + BoundedVec::try_from(vec![router_id]).unwrap(), + ); + InboundMessageSessions::::insert(domain_address.domain(), 1); let message = Message::Simple; let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_hash: H256::from_low_u64_be(1), + router_id, }; let err = DispatchError::Unavailable; @@ -2493,9 +2518,8 @@ mod message_processor_impl { Err(err) }); - let (res, weight) = LiquidityPoolsGateway::process(gateway_message); + let (res, _) = LiquidityPoolsGateway::process(gateway_message); assert_noop!(res, err); - assert_eq!(weight, LP_DEFENSIVE_WEIGHT); }); } } @@ -2518,18 +2542,21 @@ mod message_processor_impl { pays_fee: Pays::Yes, }; - let router_hash = H256::from_low_u64_be(1); - - let router_mock = RouterMock::::default(); - router_mock.mock_send(move |mock_sender, mock_message| { - assert_eq!(mock_sender, expected_sender); - assert_eq!(mock_message, expected_message.serialize()); - - Ok(router_post_info) - }); - router_mock.mock_hash(move || router_hash); - - DomainRouters::::insert(domain.clone(), router_mock); + let router_id = H256::from_low_u64_be(1); + + //TODO(cdamian): Drop mock? + // let router_hash = H256::from_low_u64_be(1); + // + // let router_mock = RouterMock::::default(); + // router_mock.mock_send(move |mock_sender, mock_message| { + // assert_eq!(mock_sender, expected_sender); + // assert_eq!(mock_message, expected_message.serialize()); + // + // Ok(router_post_info) + // }); + // router_mock.mock_hash(move || router_hash); + // + // DomainRouters::::insert(domain.clone(), router_mock); let min_expected_weight = ::DbWeight::get() .reads(1) + router_post_info.actual_weight.unwrap() @@ -2538,7 +2565,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Outbound { sender, message: message.clone(), - router_hash, + router_id, }; let (res, weight) = LiquidityPoolsGateway::process(gateway_message); @@ -2547,25 +2574,27 @@ mod message_processor_impl { }); } - #[test] - fn router_not_found() { - new_test_ext().execute_with(|| { - let sender = get_test_account_id(); - let message = Message::Simple; - - let expected_weight = ::DbWeight::get().reads(1); - - let gateway_message = GatewayMessage::Outbound { - sender, - message, - router_hash: H256::from_low_u64_be(1), - }; - - let (res, weight) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::RouterNotFound); - assert_eq!(weight, expected_weight); - }); - } + //TODO(cdamian): Fix when bi-directional routers are in. + // #[test] + // fn router_not_found() { + // new_test_ext().execute_with(|| { + // let sender = get_test_account_id(); + // let message = Message::Simple; + // + // let expected_weight = ::DbWeight::get().reads(1); + // + // let gateway_message = GatewayMessage::Outbound { + // sender, + // message, + // router_id: H256::from_low_u64_be(1), + // }; + // + // let (res, weight) = LiquidityPoolsGateway::process(gateway_message); + // assert_noop!(res, Error::::RouterNotFound); + // assert_eq!(weight, expected_weight); + // }); + // } #[test] fn router_error() { @@ -2582,20 +2611,20 @@ mod message_processor_impl { pays_fee: Pays::Yes, }; - let router_err = DispatchError::Unavailable; - - let router_mock = RouterMock::::default(); - router_mock.mock_send(move |mock_sender, mock_message| { - assert_eq!(mock_sender, expected_sender); - assert_eq!(mock_message, expected_message.serialize()); - - Err(DispatchErrorWithPostInfo { - post_info: router_post_info, - error: router_err, - }) - }); - - DomainRouters::::insert(domain.clone(), router_mock); + // let router_err = DispatchError::Unavailable; + // + // let router_mock = RouterMock::::default(); + // router_mock.mock_send(move |mock_sender, mock_message| { + // assert_eq!(mock_sender, expected_sender); + // assert_eq!(mock_message, expected_message.serialize()); + // + // Err(DispatchErrorWithPostInfo { + // post_info: router_post_info, + // error: router_err, + // }) + // }); + // + // DomainRouters::::insert(domain.clone(), router_mock); let min_expected_weight = ::DbWeight::get() .reads(1) + router_post_info.actual_weight.unwrap() @@ -2604,11 +2633,13 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Outbound { sender, message: message.clone(), - router_hash: H256::from_low_u64_be(1), + router_id: H256::from_low_u64_be(1), }; let (res, weight) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, router_err); + //TODO(cdamian): Error out + assert_ok!(res); + // assert_noop!(res, router_err) assert!(weight.all_lte(min_expected_weight)); }); } @@ -2649,6 +2680,10 @@ mod batches { // Ok Batched assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); + let router_id_1 = H256::from_low_u64_be(1); + + Routers::::insert(DOMAIN, BoundedVec::try_from(vec![router_id_1]).unwrap()); + // Not batched, it belong to OTHER assert_ok!(LiquidityPoolsGateway::handle( OTHER, @@ -2656,6 +2691,11 @@ mod batches { Message::Simple )); + Routers::::insert( + Domain::EVM(2), + BoundedVec::try_from(vec![router_id_1]).unwrap(), + ); + // Not batched, it belong to EVM 2 assert_ok!(LiquidityPoolsGateway::handle( USER, @@ -2698,6 +2738,10 @@ mod batches { DispatchError::Other(MAX_PACKED_MESSAGES_ERR) ); + let router_id_1 = H256::from_low_u64_be(1); + + Routers::::insert(DOMAIN, BoundedVec::try_from(vec![router_id_1]).unwrap()); + assert_ok!(LiquidityPoolsGateway::end_batch_message( RuntimeOrigin::signed(USER), DOMAIN @@ -2736,16 +2780,54 @@ mod batches { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); let domain_address = DomainAddress::EVM(0, address.into()); - MockLiquidityPools::mock_handle(|_, _| Ok(())); + let router_id_1 = H256::from_low_u64_be(1); + + Routers::::insert( + domain_address.domain(), + BoundedVec::try_from(vec![router_id_1]).unwrap(), + ); + InboundMessageSessions::::insert(domain_address.domain(), 1); + + let handler = MockLiquidityPools::mock_handle(|_, _| Ok(())); + + let submessage_count = 5; let (result, weight) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { domain_address, - message: Message::deserialize(&(1..=5).collect::>()).unwrap(), - router_hash: *ROUTER_HASH_1, + message: Message::deserialize(&(1..=submessage_count).collect::>()).unwrap(), + router_id: *ROUTER_HASH_1, }); - assert_eq!(weight, LP_DEFENSIVE_WEIGHT * 5); + let expected_weight = Weight::default() + // get_inbound_processing_info + .saturating_add(::DbWeight::get().reads(3)) + // process_inbound_message + .saturating_add(Weight::from_parts(0, Message::max_encoded_len() as u64)) + .saturating_add(LP_DEFENSIVE_WEIGHT) + // upsert_pending_entry + .saturating_add( + ::DbWeight::get() + .writes(1) + .saturating_mul(submessage_count.into()), + ) + // get_executable_message + .saturating_add( + ::DbWeight::get() + .reads(1) + .saturating_mul(submessage_count.into()), + ) + // decrease_pending_entries_counts + .saturating_add( + ::DbWeight::get() + .writes(1) + .saturating_mul(submessage_count.into()), + ) + // process_inbound_message + .saturating_mul(submessage_count.into()); + assert_ok!(result); + assert_eq!(weight, expected_weight); + assert_eq!(handler.times(), submessage_count as u32); }); } @@ -2755,23 +2837,32 @@ mod batches { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); let domain_address = DomainAddress::EVM(0, address.into()); + let router_id_1 = H256::from_low_u64_be(1); + + Routers::::insert( + domain_address.domain(), + BoundedVec::try_from(vec![router_id_1]).unwrap(), + ); + InboundMessageSessions::::insert(domain_address.domain(), 1); + let counter = Arc::new(AtomicU32::new(0)); - MockLiquidityPools::mock_handle(move |_, _| { + + let handler = MockLiquidityPools::mock_handle(move |_, _| { match counter.fetch_add(1, Ordering::Relaxed) { 2 => Err(DispatchError::Unavailable), _ => Ok(()), } }); - let (result, weight) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { + let (result, _) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { domain_address, message: Message::deserialize(&(1..=5).collect::>()).unwrap(), - router_hash: *ROUTER_HASH_1, + router_id: *ROUTER_HASH_1, }); - // 2 correct messages and 1 failed message processed. - assert_eq!(weight, LP_DEFENSIVE_WEIGHT * 3); assert_err!(result, DispatchError::Unavailable); + // 2 correct messages and 1 failed message processed. + assert_eq!(handler.times(), 3); }); } } From 1215fe0c50784bb2b1e1bc00461c5c43f4c3ad19 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Mon, 12 Aug 2024 23:27:54 +0300 Subject: [PATCH 12/38] lp-gateway: Add extrinsic for executing message recovery --- pallets/liquidity-pools-gateway/src/lib.rs | 85 ++++-- .../src/message_processing.rs | 12 +- pallets/liquidity-pools-gateway/src/mock.rs | 2 +- pallets/liquidity-pools-gateway/src/tests.rs | 286 ++++++++++++++++-- 4 files changed, 329 insertions(+), 56 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 5d91616e26..5ad416e6d0 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -62,7 +62,7 @@ mod tests; #[frame_support::pallet] pub mod pallet { use frame_system::pallet_prelude::BlockNumberFor; - use sp_arithmetic::traits::EnsureAdd; + use sp_arithmetic::traits::{EnsureAdd, EnsureAddAssign}; use super::*; @@ -155,6 +155,7 @@ pub mod pallet { RoutersSet { domain: Domain, router_ids: BoundedVec, + session_id: T::SessionId, }, /// An instance was added to a domain. @@ -168,6 +169,13 @@ pub mod pallet { domain: Domain, hook_address: [u8; 20], }, + + /// Message recovery was executed. + MessageRecoveryExecuted { + domain: Domain, + proof: Proof, + router_id: T::RouterId, + }, } // TODO(cdamian): Add migration to clear this storage. @@ -239,8 +247,8 @@ pub mod pallet { /// Any `PendingInboundEntries` mapped to the invalid IDs are removed from /// storage during `on_idle`. #[pallet::storage] - #[pallet::getter(fn invalid_session_ids)] - pub type InvalidSessionIds = StorageMap<_, Blake2_128Concat, T::SessionId, ()>; + #[pallet::getter(fn invalid_message_sessions)] + pub type InvalidMessageSessions = StorageMap<_, Blake2_128Concat, T::SessionId, ()>; #[pallet::error] pub enum Error { @@ -259,8 +267,8 @@ pub mod pallet { /// Unknown instance. UnknownInstance, - /// Router not found. - RouterConfigurationNotFound, + /// Routers not found. + RoutersNotFound, /// Emitted when you call `start_batch_messages()` but that was already /// called. You should finalize the message with `end_batch_messages()` @@ -294,9 +302,6 @@ pub mod pallet { /// Pending inbound entry not found. PendingInboundEntryNotFound, - /// Multi-router not found. - MultiRouterNotFound, - /// Message proof cannot be retrieved. MessageProofRetrieval, @@ -322,19 +327,23 @@ pub mod pallet { >::insert(domain.clone(), router_ids.clone()); - let (old_session_id, new_session_id) = SessionIdStore::::try_mutate(|n| { - let old_session_id = *n; - let new_session_id = old_session_id.ensure_add(One::one())?; + if let Some(old_session_id) = InboundMessageSessions::::get(domain.clone()) { + InvalidMessageSessions::::insert(old_session_id, ()); + } - *n = new_session_id; + let session_id = SessionIdStore::::try_mutate(|n| { + n.ensure_add_assign(One::one())?; - Ok::<(T::SessionId, T::SessionId), DispatchError>((old_session_id, new_session_id)) + Ok::(*n) })?; - InboundMessageSessions::::insert(domain.clone(), new_session_id); - InvalidSessionIds::::insert(old_session_id, ()); + InboundMessageSessions::::insert(domain.clone(), session_id); - Self::deposit_event(Event::RoutersSet { domain, router_ids }); + Self::deposit_event(Event::RoutersSet { + domain, + router_ids, + session_id, + }); Ok(()) } @@ -462,10 +471,48 @@ pub mod pallet { pub fn execute_message_recovery( origin: OriginFor, domain: Domain, - message_proof: Proof, + proof: Proof, + router_id: T::RouterId, ) -> DispatchResult { - //TODO(cdamian): Implement this. - unimplemented!() + T::AdminOrigin::ensure_origin(origin)?; + + let session_id = InboundMessageSessions::::get(&domain) + .ok_or(Error::::InboundDomainSessionNotFound)?; + + let routers = Routers::::get(&domain).ok_or(Error::::RoutersNotFound)?; + + ensure!( + routers.iter().any(|x| x == &router_id), + Error::::UnknownInboundMessageRouter + ); + + PendingInboundEntries::::try_mutate( + session_id, + (proof, router_id.clone()), + |storage_entry| match storage_entry { + Some(entry) => match entry { + InboundEntry::Proof { current_count } => { + current_count.ensure_add_assign(1).map_err(|e| e.into()) + } + InboundEntry::Message { .. } => { + Err(Error::::ExpectedMessageProofType.into()) + } + }, + None => { + *storage_entry = Some(InboundEntry::::Proof { current_count: 1 }); + + Ok::<(), DispatchError>(()) + } + }, + )?; + + Self::deposit_event(Event::::MessageRecoveryExecuted { + domain, + proof, + router_id, + }); + + Ok(()) } } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index c627aa3d9c..80828991a1 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -13,7 +13,7 @@ use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub}; use sp_runtime::DispatchError; use crate::{ - message::GatewayMessage, Config, Error, InboundMessageSessions, InvalidSessionIds, Pallet, + message::GatewayMessage, Config, Error, InboundMessageSessions, InvalidMessageSessions, Pallet, PendingInboundEntries, Routers, }; @@ -48,7 +48,7 @@ impl Pallet { /// Calculates and returns the proof count required for processing one /// inbound message. fn get_expected_proof_count(domain: &Domain) -> Result { - let routers = Routers::::get(domain).ok_or(Error::::MultiRouterNotFound)?; + let routers = Routers::::get(domain).ok_or(Error::::RoutersNotFound)?; let expected_proof_count = routers.len().ensure_sub(1)?; @@ -294,7 +294,7 @@ impl Pallet { weight: &mut Weight, ) -> Result, DispatchError> { let routers = - Routers::::get(domain_address.domain()).ok_or(Error::::MultiRouterNotFound)?; + Routers::::get(domain_address.domain()).ok_or(Error::::RoutersNotFound)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -404,7 +404,7 @@ impl Pallet { /// message and proofs accordingly. pub(crate) fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { let router_ids = - Routers::::get(destination.clone()).ok_or(Error::::MultiRouterNotFound)?; + Routers::::get(destination.clone()).ok_or(Error::::RoutersNotFound)?; let message_proof = message.to_message_proof(); let mut message_opt = Some(message); @@ -438,7 +438,7 @@ impl Pallet { /// The invalid session IDs are removed from storage if all entries mapped /// to them were cleared. pub(crate) fn clear_invalid_session_ids(max_weight: Weight) -> Weight { - let invalid_session_ids = InvalidSessionIds::::iter_keys().collect::>(); + let invalid_session_ids = InvalidMessageSessions::::iter_keys().collect::>(); let mut weight = T::DbWeight::get().reads(1); @@ -462,7 +462,7 @@ impl Pallet { cursor = match res.maybe_cursor { None => { - InvalidSessionIds::::remove(invalid_session_id); + InvalidMessageSessions::::remove(invalid_session_id); weight.saturating_accrue(T::DbWeight::get().writes(1)); diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 92664ae081..211dc61844 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -167,7 +167,7 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type Sender = Sender; - type SessionId = u64; + type SessionId = u32; type WeightInfo = (); } diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index f8da936f1a..7e01d1c45b 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -10,8 +10,12 @@ use frame_support::{ use itertools::Itertools; use lazy_static::lazy_static; use parity_scale_codec::MaxEncodedLen; +use sp_arithmetic::ArithmeticError::Overflow; use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160, H256}; -use sp_runtime::{DispatchError, DispatchError::BadOrigin}; +use sp_runtime::{ + DispatchError, + DispatchError::{Arithmetic, BadOrigin}, +}; use sp_std::sync::{ atomic::{AtomicU32, Ordering}, Arc, @@ -61,15 +65,13 @@ mod set_domain_routers { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); + let mut session_id = 1; + let router_id_1 = H256::from_low_u64_be(1); let router_id_2 = H256::from_low_u64_be(2); let router_id_3 = H256::from_low_u64_be(3); - //TODO(cdamian): Enable this after we figure out router init? - // let router = RouterMock::::default(); - // router.mock_init(move || Ok(())); - - let router_ids = + let mut router_ids = BoundedVec::try_from(vec![router_id_1, router_id_2, router_id_3]).unwrap(); assert_ok!(LiquidityPoolsGateway::set_domain_routers( @@ -81,32 +83,44 @@ mod set_domain_routers { assert_eq!(Routers::::get(domain.clone()).unwrap(), router_ids); assert_eq!( InboundMessageSessions::::get(domain.clone()), - Some(1) + Some(session_id) + ); + assert_eq!(InvalidMessageSessions::::get(session_id - 1), None); + + event_exists(Event::::RoutersSet { + domain: domain.clone(), + router_ids, + session_id, + }); + + router_ids = BoundedVec::try_from(vec![router_id_3, router_id_2, router_id_1]).unwrap(); + + session_id += 1; + + assert_ok!(LiquidityPoolsGateway::set_domain_routers( + RuntimeOrigin::root(), + domain.clone(), + router_ids.clone(), + )); + + assert_eq!(Routers::::get(domain.clone()).unwrap(), router_ids); + assert_eq!( + InboundMessageSessions::::get(domain.clone()), + Some(session_id) + ); + assert_eq!( + InvalidMessageSessions::::get(session_id - 1), + Some(()) ); - assert_eq!(InvalidSessionIds::::get(0), Some(())); - event_exists(Event::::RoutersSet { domain, router_ids }); + event_exists(Event::::RoutersSet { + domain, + router_ids, + session_id, + }); }); } - //TODO(cdamian): Enable this after we figure out router init? - // - // fn router_init_error() { - // new_test_ext().execute_with(|| { - // let domain = Domain::EVM(0); - // let router = RouterMock::::default(); - // router.mock_init(move || Err(DispatchError::Other("error"))); - // - // assert_noop!( - // LiquidityPoolsGateway::set_domain_router( - // RuntimeOrigin::root(), - // domain.clone(), - // router, - // ), - // Error::::RouterInitFailed, - // ); - // }); - // } #[test] fn bad_origin() { new_test_ext().execute_with(|| { @@ -123,7 +137,7 @@ mod set_domain_routers { assert!(Routers::::get(domain.clone()).is_none()); assert!(InboundMessageSessions::::get(domain).is_none()); - assert!(InvalidSessionIds::::get(0).is_none()); + assert!(InvalidMessageSessions::::get(0).is_none()); }); } @@ -143,7 +157,25 @@ mod set_domain_routers { assert!(Routers::::get(domain.clone()).is_none()); assert!(InboundMessageSessions::::get(domain).is_none()); - assert!(InvalidSessionIds::::get(0).is_none()); + assert!(InvalidMessageSessions::::get(0).is_none()); + }); + } + + #[test] + fn session_id_overflow() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + + SessionIdStore::::set(u32::MAX); + + assert_noop!( + LiquidityPoolsGateway::set_domain_routers( + RuntimeOrigin::root(), + domain, + BoundedVec::try_from(vec![]).unwrap(), + ), + Arithmetic(Overflow) + ); }); } } @@ -826,7 +858,7 @@ mod message_processor_impl { }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::MultiRouterNotFound); + assert_noop!(res, Error::::RoutersNotFound); }); } @@ -2866,3 +2898,197 @@ mod batches { }); } } + +mod execute_message_recovery { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let router_id = H256::from_low_u64_be(1); + let session_id = 1; + + Routers::::insert( + domain.clone(), + BoundedVec::try_from(vec![router_id]).unwrap(), + ); + InboundMessageSessions::::insert(domain.clone(), session_id); + + assert_ok!(LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + domain.clone(), + MESSAGE_PROOF, + router_id + )); + + event_exists(Event::::MessageRecoveryExecuted { + domain: domain.clone(), + proof: MESSAGE_PROOF, + router_id: router_id.clone(), + }); + + let inbound_entry = + PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, router_id)) + .expect("inbound entry is stored"); + + assert_eq!( + inbound_entry, + InboundEntry::::Proof { current_count: 1 } + ); + + assert_ok!(LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + domain.clone(), + MESSAGE_PROOF, + router_id + )); + + let inbound_entry = + PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, router_id)) + .expect("inbound entry is stored"); + + assert_eq!( + inbound_entry, + InboundEntry::::Proof { current_count: 2 } + ); + + event_exists(Event::::MessageRecoveryExecuted { + domain: domain.clone(), + proof: MESSAGE_PROOF, + router_id: router_id.clone(), + }); + }); + } + + #[test] + fn inbound_domain_session_not_found() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let router_id = H256::from_low_u64_be(1); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + domain.clone(), + MESSAGE_PROOF, + router_id + ), + Error::::InboundDomainSessionNotFound + ); + }); + } + + #[test] + fn routers_not_found() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let router_id = H256::from_low_u64_be(1); + let session_id = 1; + + InboundMessageSessions::::insert(domain.clone(), session_id); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + domain.clone(), + MESSAGE_PROOF, + router_id + ), + Error::::RoutersNotFound + ); + }); + } + + #[test] + fn unknown_inbound_message_router() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let router_id_1 = H256::from_low_u64_be(1); + let router_id_2 = H256::from_low_u64_be(2); + let session_id = 1; + + Routers::::insert( + domain.clone(), + BoundedVec::try_from(vec![router_id_1]).unwrap(), + ); + InboundMessageSessions::::insert(domain.clone(), session_id); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + domain.clone(), + MESSAGE_PROOF, + router_id_2 + ), + Error::::UnknownInboundMessageRouter + ); + }); + } + + #[test] + fn proof_count_overflow() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let router_id = H256::from_low_u64_be(1); + let session_id = 1; + + Routers::::insert( + domain.clone(), + BoundedVec::try_from(vec![router_id]).unwrap(), + ); + InboundMessageSessions::::insert(domain.clone(), session_id); + PendingInboundEntries::::insert( + session_id, + (MESSAGE_PROOF, router_id), + InboundEntry::::Proof { + current_count: u32::MAX, + }, + ); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + domain.clone(), + MESSAGE_PROOF, + router_id + ), + Arithmetic(Overflow) + ); + }); + } + + #[test] + fn expected_message_proof_type() { + new_test_ext().execute_with(|| { + let domain_address = TEST_DOMAIN_ADDRESS; + let router_id = H256::from_low_u64_be(1); + let session_id = 1; + + Routers::::insert( + domain_address.domain(), + BoundedVec::try_from(vec![router_id]).unwrap(), + ); + InboundMessageSessions::::insert(domain_address.domain(), session_id); + PendingInboundEntries::::insert( + session_id, + (MESSAGE_PROOF, router_id), + InboundEntry::::Message { + domain_address: domain_address.clone(), + message: Message::Simple, + expected_proof_count: 2, + }, + ); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + domain_address.domain(), + MESSAGE_PROOF, + router_id + ), + Error::::ExpectedMessageProofType + ); + }); + } +} From 743d153c0b2455e5ce37b708779f78a4d926ced3 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Tue, 13 Aug 2024 12:51:16 +0300 Subject: [PATCH 13/38] rebase: WIP --- .../src/liquidity_pools_gateway_routers.rs | 0 pallets/liquidity-pools-gateway/src/lib.rs | 26 +++++++------------ .../liquidity-pools-gateway/src/message.rs | 8 +++--- .../src/message_processing.rs | 13 +++++----- pallets/liquidity-pools-gateway/src/mock.rs | 14 ++++------ 5 files changed, 24 insertions(+), 37 deletions(-) delete mode 100644 libs/mocks/src/liquidity_pools_gateway_routers.rs diff --git a/libs/mocks/src/liquidity_pools_gateway_routers.rs b/libs/mocks/src/liquidity_pools_gateway_routers.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 5ad416e6d0..f04b7c4543 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -31,16 +31,16 @@ use core::fmt::Debug; use cfg_primitives::LP_DEFENSIVE_WEIGHT; use cfg_traits::liquidity_pools::{ InboundMessageHandler, LPEncoding, MessageProcessor, MessageQueue, MessageReceiver, - MessageSender, OutboundMessageHandler, RouterSupport, + MessageSender, OutboundMessageHandler, Proof, RouterSupport, }; use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; -use frame_system::pallet_prelude::{ensure_signed, OriginFor}; +use frame_system::pallet_prelude::{ensure_signed, BlockNumberFor, OriginFor}; use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; -use parity_scale_codec::{EncodeLike, FullCodec}; -use sp_arithmetic::traits::{BaseArithmetic, One}; +use parity_scale_codec::FullCodec; +use sp_arithmetic::traits::{BaseArithmetic, EnsureAddAssign, One}; use sp_std::convert::TryInto; use crate::{message_processing::InboundEntry, weights::WeightInfo}; @@ -61,9 +61,6 @@ mod tests; #[frame_support::pallet] pub mod pallet { - use frame_system::pallet_prelude::BlockNumberFor; - use sp_arithmetic::traits::{EnsureAdd, EnsureAddAssign}; - use super::*; const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -109,7 +106,7 @@ pub mod pallet { type MessageSender: MessageSender; /// An identification of a router - type RouterId: RouterSupport + Parameter; + type RouterId: RouterSupport + Parameter + Default + MaxEncodedLen; /// The type that processes inbound messages. type InboundMessageHandler: InboundMessageHandler< @@ -129,9 +126,7 @@ pub mod pallet { type Sender: Get; /// Type used for queueing messages. - type MessageQueue: MessageQueue< - Message = GatewayMessage, - >; + type MessageQueue: MessageQueue>; /// Maximum number of routers allowed for a domain. #[pallet::constant] @@ -545,7 +540,7 @@ pub mod pallet { } impl MessageProcessor for Pallet { - type Message = GatewayMessage; + type Message = GatewayMessage; fn process(msg: Self::Message) -> (DispatchResult, Weight) { match msg { @@ -579,20 +574,19 @@ pub mod pallet { type Origin = DomainAddress; fn receive( - _router_id: T::RouterId, + router_id: T::RouterId, origin_address: DomainAddress, message: Vec, ) -> DispatchResult { - // TODO handle router ids logic with votes and session_id - ensure!( Allowlist::::contains_key(origin_address.domain(), origin_address.clone()), Error::::UnknownInstance, ); - let gateway_message = GatewayMessage::::Inbound { + let gateway_message = GatewayMessage::::Inbound { domain_address: origin_address, message: T::Message::deserialize(&message)?, + router_id, }; T::MessageQueue::submit(gateway_message) diff --git a/pallets/liquidity-pools-gateway/src/message.rs b/pallets/liquidity-pools-gateway/src/message.rs index 0d6fc4ff38..0c6707814b 100644 --- a/pallets/liquidity-pools-gateway/src/message.rs +++ b/pallets/liquidity-pools-gateway/src/message.rs @@ -3,22 +3,20 @@ use frame_support::pallet_prelude::{Decode, Encode, MaxEncodedLen, TypeInfo}; /// Message type used by the LP gateway. #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] -pub enum GatewayMessage { +pub enum GatewayMessage { Inbound { domain_address: DomainAddress, message: Message, router_id: RouterId, }, Outbound { - sender: AccountId, + sender: DomainAddress, message: Message, router_id: RouterId, }, } -impl Default - for GatewayMessage -{ +impl Default for GatewayMessage { fn default() -> Self { GatewayMessage::Inbound { domain_address: Default::default(), diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 80828991a1..ef46531522 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -378,7 +378,7 @@ impl Pallet { /// Retrieves the stored router, sends the message, and calculates and /// returns the router operation result and the weight used. pub(crate) fn process_outbound_message( - sender: T::AccountId, + sender: DomainAddress, message: T::Message, router_id: T::RouterId, ) -> (DispatchResult, Weight) { @@ -419,12 +419,11 @@ impl Pallet { // We are using the sender specified in the pallet config so that we can // ensure that the account is funded - let gateway_message = - GatewayMessage::::Outbound { - sender: T::Sender::get(), - message: router_msg, - router_id, - }; + let gateway_message = GatewayMessage::::Outbound { + sender: T::Sender::get(), + message: router_msg, + router_id, + }; T::MessageQueue::submit(gateway_message)?; } diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 211dc61844..157e06c3ed 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -1,11 +1,8 @@ use std::fmt::{Debug, Formatter}; -use cfg_mocks::{ - pallet_mock_liquidity_pools, pallet_mock_liquidity_pools_gateway_queue, pallet_mock_routers, - RouterMock, -}; -use cfg_traits::liquidity_pools::{LPEncoding, Proof}; -use cfg_types::domain_address::DomainAddress; +use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_liquidity_pools_gateway_queue}; +use cfg_traits::liquidity_pools::{LPEncoding, Proof, RouterSupport}; +use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{derive_impl, weights::constants::RocksDbWeight}; use frame_system::EnsureRoot; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -105,7 +102,7 @@ impl LPEncoding for Message { } } -#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] +#[derive(Default, Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct RouterId(u32); impl RouterSupport for RouterId { @@ -138,7 +135,7 @@ impl pallet_mock_liquidity_pools::Config for Runtime { } impl pallet_mock_liquidity_pools_gateway_queue::Config for Runtime { - type Message = GatewayMessage; + type Message = GatewayMessage; } impl cfg_mocks::router_message::pallet::Config for Runtime { @@ -161,7 +158,6 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type MaxRouterCount = MaxRouterCount; type Message = Message; type MessageQueue = MockLiquidityPoolsGatewayQueue; - type Router = RouterMock; type MessageSender = MockMessageSender; type RouterId = RouterId; type RuntimeEvent = RuntimeEvent; From e04c300e571e2c7a86ceaa4efb10d13a2c2457a2 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:00:00 +0300 Subject: [PATCH 14/38] Don't use domain when storing routers (#1962) * lp-gateway: Unit tests WIP * lp-gateway: Don't store routers under domain * wip --- pallets/liquidity-pools-gateway/src/lib.rs | 67 +- .../src/message_processing.rs | 78 +- pallets/liquidity-pools-gateway/src/mock.rs | 4 +- pallets/liquidity-pools-gateway/src/tests.rs | 996 +++++++++--------- 4 files changed, 534 insertions(+), 611 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index f04b7c4543..f2a7925f46 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -40,7 +40,7 @@ use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; use parity_scale_codec::FullCodec; -use sp_arithmetic::traits::{BaseArithmetic, EnsureAddAssign, One}; +use sp_arithmetic::traits::{BaseArithmetic, EnsureAdd, EnsureAddAssign, One}; use sp_std::convert::TryInto; use crate::{message_processing::InboundEntry, weights::WeightInfo}; @@ -102,7 +102,7 @@ pub mod pallet { /// The Liquidity Pools message type. type Message: LPEncoding + Clone + Debug + PartialEq + MaxEncodedLen + TypeInfo + FullCodec; - /// The target of of the messages comming from this chain + /// The target of the messages coming from this chain type MessageSender: MessageSender; /// An identification of a router @@ -148,7 +148,6 @@ pub mod pallet { pub enum Event { /// The routers for a given domain were set. RoutersSet { - domain: Domain, router_ids: BoundedVec, session_id: T::SessionId, }, @@ -167,7 +166,6 @@ pub mod pallet { /// Message recovery was executed. MessageRecoveryExecuted { - domain: Domain, proof: Proof, router_id: T::RouterId, }, @@ -182,13 +180,13 @@ pub mod pallet { // pub type DomainRouters = StorageMap<_, Blake2_128Concat, Domain, // T::Router>; - /// Storage for routers specific for a domain. + /// Storage for routers. /// /// This can only be set by an admin. #[pallet::storage] #[pallet::getter(fn routers)] pub type Routers = - StorageMap<_, Blake2_128Concat, Domain, BoundedVec>; + StorageValue<_, BoundedVec, ValueQuery>; /// Storage that contains a limited number of whitelisted instances of /// deployed liquidity pools for a particular domain. @@ -227,11 +225,11 @@ pub mod pallet { InboundEntry, >; - /// Storage for the inbound message session IDs. - #[pallet::storage] - #[pallet::getter(fn inbound_message_sessions)] - pub type InboundMessageSessions = - StorageMap<_, Blake2_128Concat, Domain, T::SessionId>; + // /// Storage for the inbound message session IDs. + // #[pallet::storage] + // #[pallet::getter(fn inbound_message_sessions)] + // pub type InboundMessageSessions = + // StorageMap<_, Blake2_128Concat, Domain, T::SessionId>; /// Storage for inbound message session IDs. #[pallet::storage] @@ -279,8 +277,8 @@ pub mod pallet { /// Inbound domain session not found. InboundDomainSessionNotFound, - /// The router that sent the inbound message is unknown. - UnknownInboundMessageRouter, + /// Unknown router. + UnknownRouter, /// The router that sent the message is not the first one. MessageExpectedFromFirstRouter, @@ -309,35 +307,28 @@ pub mod pallet { /// Sets the router IDs used for a specific domain, #[pallet::weight(T::WeightInfo::set_domain_routers())] #[pallet::call_index(0)] - pub fn set_domain_routers( + pub fn set_routers( origin: OriginFor, - domain: Domain, router_ids: BoundedVec, ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - ensure!(domain != Domain::Centrifuge, Error::::DomainNotSupported); - - //TODO(cdamian): Outbound - Call router.init() for each router? + >::set(router_ids.clone()); - >::insert(domain.clone(), router_ids.clone()); + let (old_session_id, new_session_id) = SessionIdStore::::try_mutate(|n| { + let old_session_id = *n; + let new_session_id = n.ensure_add(One::one())?; - if let Some(old_session_id) = InboundMessageSessions::::get(domain.clone()) { - InvalidMessageSessions::::insert(old_session_id, ()); - } + *n = new_session_id; - let session_id = SessionIdStore::::try_mutate(|n| { - n.ensure_add_assign(One::one())?; - - Ok::(*n) + Ok::<(T::SessionId, T::SessionId), DispatchError>((old_session_id, new_session_id)) })?; - InboundMessageSessions::::insert(domain.clone(), session_id); + InvalidMessageSessions::::insert(old_session_id, ()); Self::deposit_event(Event::RoutersSet { - domain, router_ids, - session_id, + session_id: new_session_id, }); Ok(()) @@ -452,7 +443,7 @@ pub mod pallet { match PackedMessage::::take((&sender, &destination)) { Some(msg) if msg.submessages().is_empty() => Ok(()), //No-op - Some(message) => Self::queue_message(destination, message), + Some(message) => Self::queue_outbound_message(destination, message), None => Err(Error::::MessagePackingNotStarted.into()), } } @@ -465,20 +456,18 @@ pub mod pallet { #[pallet::call_index(11)] pub fn execute_message_recovery( origin: OriginFor, - domain: Domain, proof: Proof, router_id: T::RouterId, ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - let session_id = InboundMessageSessions::::get(&domain) - .ok_or(Error::::InboundDomainSessionNotFound)?; + let session_id = SessionIdStore::::get(); - let routers = Routers::::get(&domain).ok_or(Error::::RoutersNotFound)?; + let routers = Routers::::get(); ensure!( routers.iter().any(|x| x == &router_id), - Error::::UnknownInboundMessageRouter + Error::::UnknownRouter ); PendingInboundEntries::::try_mutate( @@ -501,11 +490,7 @@ pub mod pallet { }, )?; - Self::deposit_event(Event::::MessageRecoveryExecuted { - domain, - proof, - router_id, - }); + Self::deposit_event(Event::::MessageRecoveryExecuted { proof, router_id }); Ok(()) } @@ -528,7 +513,7 @@ pub mod pallet { PackedMessage::::mutate((&from, destination.clone()), |batch| match batch { Some(batch) => batch.pack_with(message), - None => Self::queue_message(destination, message), + None => Self::queue_outbound_message(destination, message), }) } } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index ef46531522..acf99a5572 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -1,5 +1,7 @@ use cfg_primitives::LP_DEFENSIVE_WEIGHT; -use cfg_traits::liquidity_pools::{InboundMessageHandler, LPEncoding, MessageQueue, Proof}; +use cfg_traits::liquidity_pools::{ + InboundMessageHandler, LPEncoding, MessageQueue, MessageSender, Proof, RouterSupport, +}; use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{ dispatch::DispatchResult, @@ -13,8 +15,8 @@ use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub}; use sp_runtime::DispatchError; use crate::{ - message::GatewayMessage, Config, Error, InboundMessageSessions, InvalidMessageSessions, Pallet, - PendingInboundEntries, Routers, + message::GatewayMessage, Config, Error, InvalidMessageSessions, Pallet, PendingInboundEntries, + Routers, SessionIdStore, }; /// The limit used when clearing the `PendingInboundEntries` for invalid @@ -39,7 +41,7 @@ pub enum InboundEntry { #[derive(Clone)] pub struct InboundProcessingInfo { domain_address: DomainAddress, - routers: BoundedVec, + router_ids: Vec, current_session_id: T::SessionId, expected_proof_count_per_message: u32, } @@ -47,10 +49,10 @@ pub struct InboundProcessingInfo { impl Pallet { /// Calculates and returns the proof count required for processing one /// inbound message. - fn get_expected_proof_count(domain: &Domain) -> Result { - let routers = Routers::::get(domain).ok_or(Error::::RoutersNotFound)?; + fn get_expected_proof_count(domain: Domain) -> Result { + let routers_count = T::RouterId::for_domain(domain).len(); - let expected_proof_count = routers.len().ensure_sub(1)?; + let expected_proof_count = routers_count.ensure_sub(1)?; Ok(expected_proof_count as u32) } @@ -94,17 +96,17 @@ impl Pallet { router_id: &T::RouterId, inbound_entry: &InboundEntry, ) -> DispatchResult { - let routers = inbound_processing_info.routers.clone(); + let router_ids = inbound_processing_info.router_ids.clone(); ensure!( - routers.iter().any(|x| x == router_id), - Error::::UnknownInboundMessageRouter + router_ids.iter().any(|x| x == router_id), + Error::::UnknownRouter ); match inbound_entry { InboundEntry::Message { .. } => { ensure!( - routers.get(0) == Some(&router_id), + router_ids.get(0) == Some(&router_id), Error::::MessageExpectedFromFirstRouter ); @@ -112,7 +114,7 @@ impl Pallet { } InboundEntry::Proof { .. } => { ensure!( - routers.get(0) != Some(&router_id), + router_ids.get(0) != Some(&router_id), Error::::ProofNotExpectedFromFirstRouter ); @@ -202,12 +204,12 @@ impl Pallet { let mut message = None; let mut votes = 0; - for router in &inbound_processing_info.routers { + for router_id in &inbound_processing_info.router_ids { weight.saturating_accrue(T::DbWeight::get().reads(1)); match PendingInboundEntries::::get( inbound_processing_info.current_session_id, - (message_proof, router), + (message_proof, router_id), ) { // We expected one InboundEntry for each router, if that's not the case, // we can return. @@ -240,12 +242,12 @@ impl Pallet { message_proof: Proof, weight: &mut Weight, ) -> DispatchResult { - for router in &inbound_processing_info.routers { + for router_id in &inbound_processing_info.router_ids { weight.saturating_accrue(T::DbWeight::get().writes(1)); match PendingInboundEntries::::try_mutate( inbound_processing_info.current_session_id, - (message_proof, router), + (message_proof, router_id), |storage_entry| match storage_entry { None => Err(Error::::PendingInboundEntryNotFound.into()), Some(stored_inbound_entry) => match stored_inbound_entry { @@ -290,26 +292,24 @@ impl Pallet { /// Retrieves the information required for processing an inbound /// message. fn get_inbound_processing_info( - domain_address: DomainAddress, + domain: Domain, weight: &mut Weight, ) -> Result, DispatchError> { - let routers = - Routers::::get(domain_address.domain()).ok_or(Error::::RoutersNotFound)?; + let router_ids = T::RouterId::for_domain(domain.clone()); weight.saturating_accrue(T::DbWeight::get().reads(1)); - let current_session_id = InboundMessageSessions::::get(domain_address.domain()) - .ok_or(Error::::InboundDomainSessionNotFound)?; + let current_session_id = SessionIdStore::::get(); weight.saturating_accrue(T::DbWeight::get().reads(1)); - let expected_proof_count = Self::get_expected_proof_count(&domain_address.domain())?; + let expected_proof_count = Self::get_expected_proof_count(domain)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); Ok(InboundProcessingInfo { domain_address, - routers, + router_ids, current_session_id, expected_proof_count_per_message: expected_proof_count, }) @@ -325,7 +325,7 @@ impl Pallet { let mut weight = Default::default(); let inbound_processing_info = - match Self::get_inbound_processing_info(domain_address.clone(), &mut weight) { + match Self::get_inbound_processing_info(domain_address.domain(), &mut weight) { Ok(i) => i, Err(e) => return (Err(e), weight), }; @@ -382,29 +382,21 @@ impl Pallet { message: T::Message, router_id: T::RouterId, ) -> (DispatchResult, Weight) { - let read_weight = T::DbWeight::get().reads(1); - - // TODO(cdamian): Update when the router refactor is done. - - // let Some(router) = Routers::::get(router_id) else { - // return (Err(Error::::RouterNotFound.into()), read_weight); - // }; - // - // let (result, router_weight) = match router.send(sender, message.serialize()) - // { Ok(dispatch_info) => (Ok(()), dispatch_info.actual_weight), - // Err(e) => (Err(e.error), e.post_info.actual_weight), - // }; - // - // (result, router_weight.unwrap_or(read_weight)) - - (Ok(()), read_weight) + let weight = LP_DEFENSIVE_WEIGHT; + + match T::MessageSender::send(router_id, sender, message.serialize()) { + Ok(_) => (Ok(()), weight), + Err(e) => (Err(e), weight), + } } /// Retrieves the IDs of the routers set for a domain and queues the /// message and proofs accordingly. - pub(crate) fn queue_message(destination: Domain, message: T::Message) -> DispatchResult { - let router_ids = - Routers::::get(destination.clone()).ok_or(Error::::RoutersNotFound)?; + pub(crate) fn queue_outbound_message( + destination: Domain, + message: T::Message, + ) -> DispatchResult { + let router_ids = T::RouterId::for_domain(destination); let message_proof = message.to_message_proof(); let mut message_opt = Some(message); diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 157e06c3ed..ed9bd50f45 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -102,8 +102,8 @@ impl LPEncoding for Message { } } -#[derive(Default, Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub struct RouterId(u32); +#[derive(Default, Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen, Hash)] +pub struct RouterId(pub u32); impl RouterSupport for RouterId { fn for_domain(_domain: Domain) -> Vec { diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 7e01d1c45b..1fcbb1a7fd 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -11,7 +11,7 @@ use itertools::Itertools; use lazy_static::lazy_static; use parity_scale_codec::MaxEncodedLen; use sp_arithmetic::ArithmeticError::Overflow; -use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160, H256}; +use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160}; use sp_runtime::{ DispatchError, DispatchError::{Arithmetic, BadOrigin}, @@ -30,11 +30,9 @@ use crate::{message_processing::InboundEntry, GatewayMessage}; pub const TEST_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(0, [1; 20]); -lazy_static! { - static ref ROUTER_HASH_1: H256 = H256::from_low_u64_be(1); - static ref ROUTER_HASH_2: H256 = H256::from_low_u64_be(2); - static ref ROUTER_HASH_3: H256 = H256::from_low_u64_be(3); -} +pub const ROUTER_ID_1: RouterId = RouterId(1); +pub const ROUTER_ID_2: RouterId = RouterId(2); +pub const ROUTER_ID_3: RouterId = RouterId(3); mod utils { use super::*; @@ -67,12 +65,8 @@ mod set_domain_routers { let mut session_id = 1; - let router_id_1 = H256::from_low_u64_be(1); - let router_id_2 = H256::from_low_u64_be(2); - let router_id_3 = H256::from_low_u64_be(3); - let mut router_ids = - BoundedVec::try_from(vec![router_id_1, router_id_2, router_id_3]).unwrap(); + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(); assert_ok!(LiquidityPoolsGateway::set_domain_routers( RuntimeOrigin::root(), @@ -93,7 +87,7 @@ mod set_domain_routers { session_id, }); - router_ids = BoundedVec::try_from(vec![router_id_3, router_id_2, router_id_1]).unwrap(); + router_ids = BoundedVec::try_from(vec![ROUTER_ID_3, ROUTER_ID_2, ROUTER_ID_1]).unwrap(); session_id += 1; @@ -340,7 +334,7 @@ mod receive_message_domain { let domain_address = DomainAddress::EVM(0, address.into()); let message = Message::Simple; - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; assert_ok!(LiquidityPoolsGateway::add_instance( RuntimeOrigin::root(), @@ -352,7 +346,7 @@ mod receive_message_domain { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_id, + router_id: router_id.clone(), }; MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { @@ -373,7 +367,7 @@ mod receive_message_domain { new_test_ext().execute_with(|| { let encoded_msg = Message::Simple.serialize(); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; assert_noop!( LiquidityPoolsGateway::receive_message( @@ -391,7 +385,7 @@ mod receive_message_domain { new_test_ext().execute_with(|| { let domain_address = DomainAddress::Centrifuge(get_test_account_id().into()); let encoded_msg = Message::Simple.serialize(); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; assert_noop!( LiquidityPoolsGateway::receive_message( @@ -410,7 +404,7 @@ mod receive_message_domain { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); let domain_address = DomainAddress::EVM(0, address.into()); let encoded_msg = Message::Simple.serialize(); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; assert_noop!( LiquidityPoolsGateway::receive_message( @@ -430,7 +424,7 @@ mod receive_message_domain { let domain_address = DomainAddress::EVM(0, address.into()); let message = Message::Simple; - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; assert_ok!(LiquidityPoolsGateway::add_instance( RuntimeOrigin::root(), @@ -444,7 +438,7 @@ mod receive_message_domain { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_id, + router_id: router_id.clone(), }; MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { @@ -475,14 +469,14 @@ mod outbound_message_handler_impl { let msg = Message::Simple; let message_proof = msg.to_message_proof().get_message_proof().unwrap(); - let router_id_1 = H256::from_low_u64_be(1); - let router_id_2 = H256::from_low_u64_be(2); - let router_id_3 = H256::from_low_u64_be(3); + let router_id_1 = ROUTER_ID_1; + let router_id_2 = ROUTER_ID_2; + let router_id_3 = ROUTER_ID_3; //TODO(cdamian): Router init - // let router_hash_1 = H256::from_low_u64_be(1); - // let router_hash_2 = H256::from_low_u64_be(2); - // let router_hash_3 = H256::from_low_u64_be(3); + // let router_hash_1 = ROUTER_ID_1; + // let router_hash_2 = ROUTER_ID_2; + // let router_hash_3 = ROUTER_ID_3; // // let router_mock_1 = RouterMock::::default(); // let router_mock_2 = RouterMock::::default(); @@ -548,30 +542,14 @@ mod outbound_message_handler_impl { let sender = get_test_account_id(); let msg = Message::Simple; - let router_id_1 = H256::from_low_u64_be(1); - let router_id_2 = H256::from_low_u64_be(2); - let router_id_3 = H256::from_low_u64_be(3); - - //TODO(cdamian): Router init? - // let router_hash_1 = H256::from_low_u64_be(1); - // let router_hash_2 = H256::from_low_u64_be(2); - // let router_hash_3 = H256::from_low_u64_be(3); - // - // let router_mock_1 = RouterMock::::default(); - // let router_mock_2 = RouterMock::::default(); - // let router_mock_3 = RouterMock::::default(); - // - // router_mock_1.mock_init(move || Ok(())); - // router_mock_1.mock_hash(move || router_hash_1); - // router_mock_2.mock_init(move || Ok(())); - // router_mock_2.mock_hash(move || router_hash_2); - // router_mock_3.mock_init(move || Ok(())); - // router_mock_3.mock_hash(move || router_hash_3); + let router_id_1 = ROUTER_ID_1; + let router_id_2 = ROUTER_ID_2; + let router_id_3 = ROUTER_ID_3; assert_ok!(LiquidityPoolsGateway::set_domain_routers( RuntimeOrigin::root(), domain.clone(), - BoundedVec::try_from(vec![router_id_1, router_id_2, router_id_3]).unwrap(), + BoundedVec::try_from(vec![router_id_1.clone(), router_id_2, router_id_3]).unwrap(), )); let gateway_message = GatewayMessage::Outbound { @@ -713,20 +691,20 @@ mod message_processor_impl { /// Used for generating all `RouterMessage` combinations like: /// /// vec![ - /// (*ROUTER_HASH_1, Message::Simple), - /// (*ROUTER_HASH_1, Message::Simple), + /// (ROUTER_ID_1, Message::Simple), + /// (ROUTER_ID_1, Message::Simple), /// ] /// vec![ - /// (*ROUTER_HASH_1, Message::Simple), - /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + /// (ROUTER_ID_1, Message::Simple), + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), /// ] /// vec![ - /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - /// (*ROUTER_HASH_1, Message::Simple), + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + /// (ROUTER_ID_1, Message::Simple), /// ] /// vec![ - /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - /// (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), /// ] pub fn generate_test_combinations( t: T, @@ -744,11 +722,11 @@ mod message_processor_impl { } /// Type used for mapping a message to a router hash. - pub type RouterMessage = (H256, Message); + pub type RouterMessage = (RouterId, Message); /// Type used for aggregating tests for inbound messages. pub struct InboundMessageTestSuite { - pub routers: Vec, + pub routers: Vec, pub tests: Vec, } @@ -764,14 +742,14 @@ mod message_processor_impl { #[derive(Clone, Debug)] pub struct ExpectedTestResult { pub message_submitted_times: u32, - pub expected_storage_entries: Vec<(H256, Option>)>, + pub expected_storage_entries: Vec<(RouterId, Option>)>, } /// Generates the combinations of `RouterMessage` used when testing, /// maps the `ExpectedTestResult` for each and creates the /// `InboundMessageTestSuite`. pub fn generate_test_suite( - routers: Vec, + routers: Vec, test_data: Vec, expected_results: HashMap, ExpectedTestResult>, message_count: usize, @@ -811,16 +789,16 @@ mod message_processor_impl { let message_proof = message.to_message_proof().get_message_proof().unwrap(); let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_hash = *ROUTER_HASH_1; + let router_id = ROUTER_ID_1; let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_id: router_hash, + router_id: router_id.clone(), }; Routers::::insert( domain_address.domain(), - BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), ); InboundMessageSessions::::insert(domain_address.domain(), session_id); @@ -839,7 +817,7 @@ mod message_processor_impl { assert!(PendingInboundEntries::::get( session_id, - (message_proof, router_hash) + (message_proof, router_id) ) .is_none()); }); @@ -850,7 +828,7 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let message = Message::Simple; let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_hash = *ROUTER_HASH_1; + let router_hash = ROUTER_ID_1; let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), @@ -867,16 +845,16 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let message = Message::Simple; let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_hash = *ROUTER_HASH_1; + let router_id = ROUTER_ID_1; let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_id: router_hash, + router_id: router_id.clone(), }; Routers::::insert( domain_address.domain(), - BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + BoundedVec::<_, _>::try_from(vec![router_id]).unwrap(), ); let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -890,13 +868,13 @@ mod message_processor_impl { let message = Message::Simple; let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_hash = *ROUTER_HASH_1; + let router_hash = ROUTER_ID_1; let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), // The router stored has a different hash, this should trigger the expected // error. - router_id: *ROUTER_HASH_2, + router_id: ROUTER_ID_2, }; Routers::::insert( @@ -906,7 +884,7 @@ mod message_processor_impl { InboundMessageSessions::::insert(domain_address.domain(), session_id); let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::UnknownInboundMessageRouter); + assert_noop!(res, Error::::UnknownRouter); }); } @@ -917,21 +895,21 @@ mod message_processor_impl { let message_proof = message.to_message_proof().get_message_proof().unwrap(); let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_hash = *ROUTER_HASH_1; + let router_id = ROUTER_ID_1; let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_id: router_hash, + router_id: router_id.clone(), }; Routers::::insert( domain_address.domain(), - BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), ); InboundMessageSessions::::insert(domain_address.domain(), session_id); PendingInboundEntries::::insert( session_id, - (message_proof, router_hash), + (message_proof, router_id), InboundEntry::::Proof { current_count: 0 }, ); @@ -949,8 +927,8 @@ mod message_processor_impl { lazy_static! { static ref TEST_DATA: Vec = vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ]; } @@ -965,35 +943,35 @@ mod message_processor_impl { HashMap::from([ ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), @@ -1003,34 +981,34 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ]); let suite = generate_test_suite( - vec![*ROUTER_HASH_1, *ROUTER_HASH_2], + vec![ROUTER_ID_1, ROUTER_ID_2], TEST_DATA.clone(), expected_results, MESSAGE_COUNT, @@ -1051,37 +1029,37 @@ mod message_processor_impl { HashMap::from([ ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 3, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 3, }), @@ -1091,58 +1069,58 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1152,37 +1130,37 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1192,16 +1170,16 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1212,7 +1190,7 @@ mod message_processor_impl { ]); let suite = generate_test_suite( - vec![*ROUTER_HASH_1, *ROUTER_HASH_2], + vec![ROUTER_ID_1, ROUTER_ID_2], TEST_DATA.clone(), expected_results, MESSAGE_COUNT, @@ -1233,39 +1211,39 @@ mod message_processor_impl { HashMap::from([ ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 4, }), @@ -1275,195 +1253,195 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 2, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 2, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 2, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 2, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 2, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 2, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), @@ -1473,17 +1451,17 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), @@ -1493,17 +1471,17 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), @@ -1513,17 +1491,17 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), @@ -1534,7 +1512,7 @@ mod message_processor_impl { ]); let suite = generate_test_suite( - vec![*ROUTER_HASH_1, *ROUTER_HASH_2], + vec![ROUTER_ID_1, ROUTER_ID_2], TEST_DATA.clone(), expected_results, MESSAGE_COUNT, @@ -1555,8 +1533,7 @@ mod message_processor_impl { Routers::::insert( TEST_DOMAIN_ADDRESS.domain(), - BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) - .unwrap(), + BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), ); InboundMessageSessions::::insert( TEST_DOMAIN_ADDRESS.domain(), @@ -1566,7 +1543,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - router_id: *ROUTER_HASH_2, + router_id: ROUTER_ID_2, }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -1581,8 +1558,7 @@ mod message_processor_impl { Routers::::insert( TEST_DOMAIN_ADDRESS.domain(), - BoundedVec::<_, _>::try_from(vec![*ROUTER_HASH_1, *ROUTER_HASH_2]) - .unwrap(), + BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), ); InboundMessageSessions::::insert( TEST_DOMAIN_ADDRESS.domain(), @@ -1592,7 +1568,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Proof(MESSAGE_PROOF), - router_id: *ROUTER_HASH_1, + router_id: ROUTER_ID_1, }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -1607,9 +1583,9 @@ mod message_processor_impl { lazy_static! { static ref TEST_DATA: Vec = vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ]; } @@ -1624,56 +1600,56 @@ mod message_processor_impl { HashMap::from([ ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, }), ), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 2, }), @@ -1683,21 +1659,21 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1707,21 +1683,21 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1731,14 +1707,14 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -1746,34 +1722,34 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1783,23 +1759,23 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1809,14 +1785,14 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -1824,34 +1800,34 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -1862,7 +1838,7 @@ mod message_processor_impl { ]); let suite = generate_test_suite( - vec![*ROUTER_HASH_1, *ROUTER_HASH_2, *ROUTER_HASH_3], + vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], TEST_DATA.clone(), expected_results, MESSAGE_COUNT, @@ -1883,59 +1859,59 @@ mod message_processor_impl { HashMap::from([ ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 6, }), ), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 3, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 3, }), @@ -1945,15 +1921,15 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -1961,26 +1937,26 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -1988,26 +1964,26 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -2015,35 +1991,35 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 2, }), @@ -2053,24 +2029,24 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 2, }), @@ -2080,24 +2056,24 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 2, }), @@ -2107,15 +2083,15 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -2123,26 +2099,26 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -2150,35 +2126,35 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -2188,15 +2164,15 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, @@ -2204,35 +2180,35 @@ mod message_processor_impl { }), ), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), - (*ROUTER_HASH_3, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -2242,24 +2218,24 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ ( - *ROUTER_HASH_1, + ROUTER_ID_1, Some(InboundEntry::::Message { domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, }), ), - (*ROUTER_HASH_2, None), + (ROUTER_ID_2, None), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -2269,112 +2245,112 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_1, Message::Simple), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), - (*ROUTER_HASH_2, None), - (*ROUTER_HASH_3, None), + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -2384,22 +2360,22 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -2409,22 +2385,22 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 2, }), @@ -2434,22 +2410,22 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 2, }), @@ -2459,22 +2435,22 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 2, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 1, }), @@ -2484,22 +2460,22 @@ mod message_processor_impl { ), ( vec![ - (*ROUTER_HASH_2, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), - (*ROUTER_HASH_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (*ROUTER_HASH_1, None), + (ROUTER_ID_1, None), ( - *ROUTER_HASH_2, + ROUTER_ID_2, Some(InboundEntry::::Proof { current_count: 1, }), ), ( - *ROUTER_HASH_3, + ROUTER_ID_3, Some(InboundEntry::::Proof { current_count: 2, }), @@ -2510,7 +2486,7 @@ mod message_processor_impl { ]); let suite = generate_test_suite( - vec![*ROUTER_HASH_1, *ROUTER_HASH_2, *ROUTER_HASH_3], + vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], TEST_DATA.clone(), expected_results, MESSAGE_COUNT, @@ -2526,11 +2502,11 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; Routers::::insert( domain_address.domain(), - BoundedVec::try_from(vec![router_id]).unwrap(), + BoundedVec::try_from(vec![router_id.clone()]).unwrap(), ); InboundMessageSessions::::insert(domain_address.domain(), 1); @@ -2562,33 +2538,15 @@ mod message_processor_impl { #[test] fn success() { new_test_ext().execute_with(|| { - let sender = get_test_account_id(); - let domain = Domain::EVM(1); + let sender = TEST_DOMAIN_ADDRESS; let message = Message::Simple; - let expected_sender = sender.clone(); - let expected_message = message.clone(); - let router_post_info = PostDispatchInfo { actual_weight: Some(Weight::from_parts(1, 1)), pays_fee: Pays::Yes, }; - let router_id = H256::from_low_u64_be(1); - - //TODO(cdamian): Drop mock? - // let router_hash = H256::from_low_u64_be(1); - // - // let router_mock = RouterMock::::default(); - // router_mock.mock_send(move |mock_sender, mock_message| { - // assert_eq!(mock_sender, expected_sender); - // assert_eq!(mock_message, expected_message.serialize()); - // - // Ok(router_post_info) - // }); - // router_mock.mock_hash(move || router_hash); - // - // DomainRouters::::insert(domain.clone(), router_mock); + let router_id = ROUTER_ID_1; let min_expected_weight = ::DbWeight::get() .reads(1) + router_post_info.actual_weight.unwrap() @@ -2619,7 +2577,7 @@ mod message_processor_impl { // let gateway_message = GatewayMessage::Outbound { // sender, // message, - // router_id: H256::from_low_u64_be(1), + // router_id: ROUTER_ID_1, // }; // // let (res, weight) = LiquidityPoolsGateway::process(gateway_message); @@ -2631,33 +2589,14 @@ mod message_processor_impl { #[test] fn router_error() { new_test_ext().execute_with(|| { - let sender = get_test_account_id(); - let domain = Domain::EVM(1); + let sender = TEST_DOMAIN_ADDRESS; let message = Message::Simple; - let expected_sender = sender.clone(); - let expected_message = message.clone(); - let router_post_info = PostDispatchInfo { actual_weight: Some(Weight::from_parts(1, 1)), pays_fee: Pays::Yes, }; - // let router_err = DispatchError::Unavailable; - // - // let router_mock = RouterMock::::default(); - // router_mock.mock_send(move |mock_sender, mock_message| { - // assert_eq!(mock_sender, expected_sender); - // assert_eq!(mock_message, expected_message.serialize()); - // - // Err(DispatchErrorWithPostInfo { - // post_info: router_post_info, - // error: router_err, - // }) - // }); - // - // DomainRouters::::insert(domain.clone(), router_mock); - let min_expected_weight = ::DbWeight::get() .reads(1) + router_post_info.actual_weight.unwrap() + Weight::from_parts(0, message.serialize().len() as u64); @@ -2665,7 +2604,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Outbound { sender, message: message.clone(), - router_id: H256::from_low_u64_be(1), + router_id: ROUTER_ID_1, }; let (res, weight) = LiquidityPoolsGateway::process(gateway_message); @@ -2712,9 +2651,12 @@ mod batches { // Ok Batched assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - let router_id_1 = H256::from_low_u64_be(1); + let router_id_1 = ROUTER_ID_1; - Routers::::insert(DOMAIN, BoundedVec::try_from(vec![router_id_1]).unwrap()); + Routers::::insert( + DOMAIN, + BoundedVec::try_from(vec![router_id_1.clone()]).unwrap(), + ); // Not batched, it belong to OTHER assert_ok!(LiquidityPoolsGateway::handle( @@ -2770,7 +2712,7 @@ mod batches { DispatchError::Other(MAX_PACKED_MESSAGES_ERR) ); - let router_id_1 = H256::from_low_u64_be(1); + let router_id_1 = ROUTER_ID_1; Routers::::insert(DOMAIN, BoundedVec::try_from(vec![router_id_1]).unwrap()); @@ -2812,7 +2754,7 @@ mod batches { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); let domain_address = DomainAddress::EVM(0, address.into()); - let router_id_1 = H256::from_low_u64_be(1); + let router_id_1 = ROUTER_ID_1; Routers::::insert( domain_address.domain(), @@ -2827,7 +2769,7 @@ mod batches { let (result, weight) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { domain_address, message: Message::deserialize(&(1..=submessage_count).collect::>()).unwrap(), - router_id: *ROUTER_HASH_1, + router_id: ROUTER_ID_1, }); let expected_weight = Weight::default() @@ -2869,7 +2811,7 @@ mod batches { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); let domain_address = DomainAddress::EVM(0, address.into()); - let router_id_1 = H256::from_low_u64_be(1); + let router_id_1 = ROUTER_ID_1; Routers::::insert( domain_address.domain(), @@ -2889,7 +2831,7 @@ mod batches { let (result, _) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { domain_address, message: Message::deserialize(&(1..=5).collect::>()).unwrap(), - router_id: *ROUTER_HASH_1, + router_id: ROUTER_ID_1, }); assert_err!(result, DispatchError::Unavailable); @@ -2906,12 +2848,12 @@ mod execute_message_recovery { fn success() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; let session_id = 1; Routers::::insert( domain.clone(), - BoundedVec::try_from(vec![router_id]).unwrap(), + BoundedVec::try_from(vec![router_id.clone()]).unwrap(), ); InboundMessageSessions::::insert(domain.clone(), session_id); @@ -2919,7 +2861,7 @@ mod execute_message_recovery { RuntimeOrigin::root(), domain.clone(), MESSAGE_PROOF, - router_id + router_id.clone(), )); event_exists(Event::::MessageRecoveryExecuted { @@ -2928,9 +2870,11 @@ mod execute_message_recovery { router_id: router_id.clone(), }); - let inbound_entry = - PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, router_id)) - .expect("inbound entry is stored"); + let inbound_entry = PendingInboundEntries::::get( + session_id, + (MESSAGE_PROOF, router_id.clone()), + ) + .expect("inbound entry is stored"); assert_eq!( inbound_entry, @@ -2941,12 +2885,14 @@ mod execute_message_recovery { RuntimeOrigin::root(), domain.clone(), MESSAGE_PROOF, - router_id + router_id.clone() )); - let inbound_entry = - PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, router_id)) - .expect("inbound entry is stored"); + let inbound_entry = PendingInboundEntries::::get( + session_id, + (MESSAGE_PROOF, router_id.clone()), + ) + .expect("inbound entry is stored"); assert_eq!( inbound_entry, @@ -2956,7 +2902,7 @@ mod execute_message_recovery { event_exists(Event::::MessageRecoveryExecuted { domain: domain.clone(), proof: MESSAGE_PROOF, - router_id: router_id.clone(), + router_id, }); }); } @@ -2965,7 +2911,7 @@ mod execute_message_recovery { fn inbound_domain_session_not_found() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; assert_noop!( LiquidityPoolsGateway::execute_message_recovery( @@ -2983,7 +2929,7 @@ mod execute_message_recovery { fn routers_not_found() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; let session_id = 1; InboundMessageSessions::::insert(domain.clone(), session_id); @@ -3004,8 +2950,8 @@ mod execute_message_recovery { fn unknown_inbound_message_router() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); - let router_id_1 = H256::from_low_u64_be(1); - let router_id_2 = H256::from_low_u64_be(2); + let router_id_1 = ROUTER_ID_1; + let router_id_2 = ROUTER_ID_2; let session_id = 1; Routers::::insert( @@ -3021,7 +2967,7 @@ mod execute_message_recovery { MESSAGE_PROOF, router_id_2 ), - Error::::UnknownInboundMessageRouter + Error::::UnknownRouter ); }); } @@ -3030,17 +2976,17 @@ mod execute_message_recovery { fn proof_count_overflow() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; let session_id = 1; Routers::::insert( domain.clone(), - BoundedVec::try_from(vec![router_id]).unwrap(), + BoundedVec::try_from(vec![router_id.clone()]).unwrap(), ); InboundMessageSessions::::insert(domain.clone(), session_id); PendingInboundEntries::::insert( session_id, - (MESSAGE_PROOF, router_id), + (MESSAGE_PROOF, router_id.clone()), InboundEntry::::Proof { current_count: u32::MAX, }, @@ -3062,17 +3008,17 @@ mod execute_message_recovery { fn expected_message_proof_type() { new_test_ext().execute_with(|| { let domain_address = TEST_DOMAIN_ADDRESS; - let router_id = H256::from_low_u64_be(1); + let router_id = ROUTER_ID_1; let session_id = 1; Routers::::insert( domain_address.domain(), - BoundedVec::try_from(vec![router_id]).unwrap(), + BoundedVec::try_from(vec![router_id.clone()]).unwrap(), ); InboundMessageSessions::::insert(domain_address.domain(), session_id); PendingInboundEntries::::insert( session_id, - (MESSAGE_PROOF, router_id), + (MESSAGE_PROOF, router_id.clone()), InboundEntry::::Message { domain_address: domain_address.clone(), message: Message::Simple, From a0115d73987e3c237ab399d8cc69dce0370e6b10 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:34:43 +0300 Subject: [PATCH 15/38] wip --- pallets/liquidity-pools-gateway/src/lib.rs | 17 +---------------- .../src/message_processing.rs | 13 ++++++------- pallets/liquidity-pools-gateway/src/mock.rs | 2 +- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index f2a7925f46..047f31854a 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -171,15 +171,6 @@ pub mod pallet { }, } - // TODO(cdamian): Add migration to clear this storage. - // /// Storage for domain routers. - // /// - // /// This can only be set by an admin. - // #[pallet::storage] - // #[pallet::getter(fn domain_routers)] - // pub type DomainRouters = StorageMap<_, Blake2_128Concat, Domain, - // T::Router>; - /// Storage for routers. /// /// This can only be set by an admin. @@ -206,7 +197,7 @@ pub mod pallet { pub type DomainHookAddress = StorageMap<_, Blake2_128Concat, Domain, [u8; 20], OptionQuery>; - /// Stores a batch message, not ready yet to be enqueue. + /// Stores a batch message, not ready yet to be enqueued. /// Lifetime handled by `start_batch_message()` and `end_batch_message()` /// extrinsics. #[pallet::storage] @@ -225,12 +216,6 @@ pub mod pallet { InboundEntry, >; - // /// Storage for the inbound message session IDs. - // #[pallet::storage] - // #[pallet::getter(fn inbound_message_sessions)] - // pub type InboundMessageSessions = - // StorageMap<_, Blake2_128Concat, Domain, T::SessionId>; - /// Storage for inbound message session IDs. #[pallet::storage] pub type SessionIdStore = StorageValue<_, T::SessionId, ValueQuery>; diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index acf99a5572..9ceaf1d976 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -8,7 +8,6 @@ use frame_support::{ ensure, pallet_prelude::{Decode, Encode, Get, TypeInfo}, weights::Weight, - BoundedVec, }; use parity_scale_codec::MaxEncodedLen; use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub}; @@ -16,7 +15,7 @@ use sp_runtime::DispatchError; use crate::{ message::GatewayMessage, Config, Error, InvalidMessageSessions, Pallet, PendingInboundEntries, - Routers, SessionIdStore, + SessionIdStore, }; /// The limit used when clearing the `PendingInboundEntries` for invalid @@ -41,7 +40,7 @@ pub enum InboundEntry { #[derive(Clone)] pub struct InboundProcessingInfo { domain_address: DomainAddress, - router_ids: Vec, + router_ids: Vec, current_session_id: T::SessionId, expected_proof_count_per_message: u32, } @@ -292,10 +291,10 @@ impl Pallet { /// Retrieves the information required for processing an inbound /// message. fn get_inbound_processing_info( - domain: Domain, + domain_address: DomainAddress, weight: &mut Weight, ) -> Result, DispatchError> { - let router_ids = T::RouterId::for_domain(domain.clone()); + let router_ids = T::RouterId::for_domain(domain_address.domain()); weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -303,7 +302,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads(1)); - let expected_proof_count = Self::get_expected_proof_count(domain)?; + let expected_proof_count = Self::get_expected_proof_count(domain_address.domain())?; weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -325,7 +324,7 @@ impl Pallet { let mut weight = Default::default(); let inbound_processing_info = - match Self::get_inbound_processing_info(domain_address.domain(), &mut weight) { + match Self::get_inbound_processing_info(domain_address.clone(), &mut weight) { Ok(i) => i, Err(e) => return (Err(e), weight), }; diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index ed9bd50f45..ba38f35610 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -144,7 +144,7 @@ impl cfg_mocks::router_message::pallet::Config for Runtime { } frame_support::parameter_types! { - pub Sender: DomainAddress = DomainAddress::Centrifuge(AccountId32::from(H256::from_low_u64_be(1).to_fixed_bytes()).into()); + pub Sender: DomainAddress = DomainAddress::Centrifuge(AccountId32::from(H256::from_low_u64_be(123).to_fixed_bytes()).into()); pub const MaxIncomingMessageSize: u32 = 1024; pub const LpAdminAccount: AccountId32 = LP_ADMIN_ACCOUNT; pub const MaxRouterCount: u32 = 8; From a4dfd56f28d5c027f9a45a5aa51513d8eadac800 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:02:27 +0300 Subject: [PATCH 16/38] lp-gateway: Unit test WIP --- pallets/liquidity-pools-gateway/src/lib.rs | 35 +- .../src/message_processing.rs | 34 +- pallets/liquidity-pools-gateway/src/mock.rs | 19 +- pallets/liquidity-pools-gateway/src/tests.rs | 315 +++++------------- 4 files changed, 156 insertions(+), 247 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 047f31854a..6fc5819942 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -40,7 +40,7 @@ use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; use parity_scale_codec::FullCodec; -use sp_arithmetic::traits::{BaseArithmetic, EnsureAdd, EnsureAddAssign, One}; +use sp_arithmetic::traits::{BaseArithmetic, EnsureAdd, EnsureAddAssign, One, Zero}; use sp_std::convert::TryInto; use crate::{message_processing::InboundEntry, weights::WeightInfo}; @@ -177,7 +177,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn routers)] pub type Routers = - StorageValue<_, BoundedVec, ValueQuery>; + StorageValue<_, BoundedVec, OptionQuery>; /// Storage that contains a limited number of whitelisted instances of /// deployed liquidity pools for a particular domain. @@ -218,7 +218,7 @@ pub mod pallet { /// Storage for inbound message session IDs. #[pallet::storage] - pub type SessionIdStore = StorageValue<_, T::SessionId, ValueQuery>; + pub type SessionIdStore = StorageValue<_, T::SessionId, OptionQuery>; /// Storage that keeps track of invalid session IDs. /// @@ -259,8 +259,8 @@ pub mod pallet { /// Invalid multi router. InvalidMultiRouter, - /// Inbound domain session not found. - InboundDomainSessionNotFound, + /// Session ID not found. + SessionIdNotFound, /// Unknown router. UnknownRouter, @@ -285,6 +285,9 @@ pub mod pallet { /// Recovery message not found. RecoveryMessageNotFound, + + /// Not enough routers are stored for a domain. + NotEnoughRoutersForDomain, } #[pallet::call] @@ -298,16 +301,20 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - >::set(router_ids.clone()); + >::set(Some(router_ids.clone())); - let (old_session_id, new_session_id) = SessionIdStore::::try_mutate(|n| { - let old_session_id = *n; - let new_session_id = n.ensure_add(One::one())?; + let (old_session_id, new_session_id) = + SessionIdStore::::try_mutate(|storage_entry| { + let old_session_id = storage_entry.unwrap_or(T::SessionId::zero()); + let new_session_id = old_session_id.ensure_add(One::one())?; - *n = new_session_id; + *storage_entry = Some(new_session_id); - Ok::<(T::SessionId, T::SessionId), DispatchError>((old_session_id, new_session_id)) - })?; + Ok::<(T::SessionId, T::SessionId), DispatchError>(( + old_session_id, + new_session_id, + )) + })?; InvalidMessageSessions::::insert(old_session_id, ()); @@ -446,9 +453,9 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - let session_id = SessionIdStore::::get(); + let session_id = SessionIdStore::::get().ok_or(Error::::SessionIdNotFound)?; - let routers = Routers::::get(); + let routers = Routers::::get().ok_or(Error::::RoutersNotFound)?; ensure!( routers.iter().any(|x| x == &router_id), diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 9ceaf1d976..a999a9d015 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -15,7 +15,7 @@ use sp_runtime::DispatchError; use crate::{ message::GatewayMessage, Config, Error, InvalidMessageSessions, Pallet, PendingInboundEntries, - SessionIdStore, + Routers, SessionIdStore, }; /// The limit used when clearing the `PendingInboundEntries` for invalid @@ -46,12 +46,34 @@ pub struct InboundProcessingInfo { } impl Pallet { + /// Retrieves all available routers for a domain and then filters them based + /// on the routers that we have in storage. + fn get_router_ids_for_domain(domain: Domain) -> Result, DispatchError> { + let all_routers_for_domain = T::RouterId::for_domain(domain); + + let stored_routers = Routers::::get().ok_or(Error::::RoutersNotFound)?; + + let res = all_routers_for_domain + .iter() + .filter(|x| stored_routers.iter().any(|y| *x == y)) + .map(|x| x.clone()) + .collect::>(); + + if res.is_empty() { + return Err(Error::::NotEnoughRoutersForDomain.into()); + } + + Ok(res) + } + /// Calculates and returns the proof count required for processing one /// inbound message. fn get_expected_proof_count(domain: Domain) -> Result { - let routers_count = T::RouterId::for_domain(domain).len(); + let routers_count = Self::get_router_ids_for_domain(domain)?.len(); - let expected_proof_count = routers_count.ensure_sub(1)?; + let expected_proof_count = routers_count + .ensure_sub(1) + .map_err(|_| Error::::NotEnoughRoutersForDomain)?; Ok(expected_proof_count as u32) } @@ -294,11 +316,11 @@ impl Pallet { domain_address: DomainAddress, weight: &mut Weight, ) -> Result, DispatchError> { - let router_ids = T::RouterId::for_domain(domain_address.domain()); + let router_ids = Self::get_router_ids_for_domain(domain_address.domain())?; weight.saturating_accrue(T::DbWeight::get().reads(1)); - let current_session_id = SessionIdStore::::get(); + let current_session_id = SessionIdStore::::get().ok_or(Error::::SessionIdNotFound)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -395,7 +417,7 @@ impl Pallet { destination: Domain, message: T::Message, ) -> DispatchResult { - let router_ids = T::RouterId::for_domain(destination); + let router_ids = Self::get_router_ids_for_domain(destination)?; let message_proof = message.to_message_proof(); let mut message_opt = Some(message); diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index ba38f35610..de08a1216b 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -2,7 +2,10 @@ use std::fmt::{Debug, Formatter}; use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_liquidity_pools_gateway_queue}; use cfg_traits::liquidity_pools::{LPEncoding, Proof, RouterSupport}; -use cfg_types::domain_address::{Domain, DomainAddress}; +use cfg_types::{ + domain_address::{Domain, DomainAddress}, + EVMChainId, +}; use frame_support::{derive_impl, weights::constants::RocksDbWeight}; use frame_system::EnsureRoot; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; @@ -12,6 +15,13 @@ use sp_runtime::{traits::IdentityLookup, DispatchError, DispatchResult}; use crate::{pallet as pallet_liquidity_pools_gateway, EnsureLocal, GatewayMessage}; +pub const TEST_EVM_CHAIN: EVMChainId = 1; +pub const TEST_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(TEST_EVM_CHAIN, [1; 20]); + +pub const ROUTER_ID_1: RouterId = RouterId(1); +pub const ROUTER_ID_2: RouterId = RouterId(2); +pub const ROUTER_ID_3: RouterId = RouterId(3); + pub const LP_ADMIN_ACCOUNT: AccountId32 = AccountId32::new([u8::MAX; 32]); pub const MAX_PACKED_MESSAGES_ERR: &str = "packed limit error"; @@ -106,8 +116,11 @@ impl LPEncoding for Message { pub struct RouterId(pub u32); impl RouterSupport for RouterId { - fn for_domain(_domain: Domain) -> Vec { - vec![] // TODO + fn for_domain(domain: Domain) -> Vec { + match domain { + Domain::Centrifuge => vec![], + Domain::EVM(_) => vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + } } } diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 1fcbb1a7fd..6432962431 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -28,12 +28,6 @@ use super::{ }; use crate::{message_processing::InboundEntry, GatewayMessage}; -pub const TEST_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(0, [1; 20]); - -pub const ROUTER_ID_1: RouterId = RouterId(1); -pub const ROUTER_ID_2: RouterId = RouterId(2); -pub const ROUTER_ID_3: RouterId = RouterId(3); - mod utils { use super::*; @@ -55,34 +49,30 @@ mod utils { use utils::*; -mod set_domain_routers { +mod set_routers { use super::*; #[test] fn success() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let mut session_id = 1; let mut router_ids = BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(); - assert_ok!(LiquidityPoolsGateway::set_domain_routers( + assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - domain.clone(), router_ids.clone(), )); - assert_eq!(Routers::::get(domain.clone()).unwrap(), router_ids); + assert_eq!(Routers::::get(), Some(router_ids.clone())); + assert_eq!(SessionIdStore::::get(), Some(session_id)); assert_eq!( - InboundMessageSessions::::get(domain.clone()), - Some(session_id) + InvalidMessageSessions::::get(session_id - 1), + Some(()) ); - assert_eq!(InvalidMessageSessions::::get(session_id - 1), None); event_exists(Event::::RoutersSet { - domain: domain.clone(), router_ids, session_id, }); @@ -91,24 +81,19 @@ mod set_domain_routers { session_id += 1; - assert_ok!(LiquidityPoolsGateway::set_domain_routers( + assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - domain.clone(), router_ids.clone(), )); - assert_eq!(Routers::::get(domain.clone()).unwrap(), router_ids); - assert_eq!( - InboundMessageSessions::::get(domain.clone()), - Some(session_id) - ); + assert_eq!(Routers::::get(), Some(router_ids.clone())); + assert_eq!(SessionIdStore::::get(), Some(session_id)); assert_eq!( InvalidMessageSessions::::get(session_id - 1), Some(()) ); event_exists(Event::::RoutersSet { - domain, router_ids, session_id, }); @@ -118,39 +103,16 @@ mod set_domain_routers { #[test] fn bad_origin() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - assert_noop!( - LiquidityPoolsGateway::set_domain_routers( + LiquidityPoolsGateway::set_routers( RuntimeOrigin::signed(get_test_account_id()), - domain.clone(), BoundedVec::try_from(vec![]).unwrap(), ), BadOrigin ); - assert!(Routers::::get(domain.clone()).is_none()); - assert!(InboundMessageSessions::::get(domain).is_none()); - assert!(InvalidMessageSessions::::get(0).is_none()); - }); - } - - #[test] - fn unsupported_domain() { - new_test_ext().execute_with(|| { - let domain = Domain::Centrifuge; - - assert_noop!( - LiquidityPoolsGateway::set_domain_routers( - RuntimeOrigin::root(), - domain.clone(), - BoundedVec::try_from(vec![]).unwrap(), - ), - Error::::DomainNotSupported - ); - - assert!(Routers::::get(domain.clone()).is_none()); - assert!(InboundMessageSessions::::get(domain).is_none()); + assert!(Routers::::get().is_none()); + assert!(SessionIdStore::::get().is_none()); assert!(InvalidMessageSessions::::get(0).is_none()); }); } @@ -158,14 +120,11 @@ mod set_domain_routers { #[test] fn session_id_overflow() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - - SessionIdStore::::set(u32::MAX); + SessionIdStore::::set(Some(u32::MAX)); assert_noop!( - LiquidityPoolsGateway::set_domain_routers( + LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - domain, BoundedVec::try_from(vec![]).unwrap(), ), Arithmetic(Overflow) @@ -469,30 +428,9 @@ mod outbound_message_handler_impl { let msg = Message::Simple; let message_proof = msg.to_message_proof().get_message_proof().unwrap(); - let router_id_1 = ROUTER_ID_1; - let router_id_2 = ROUTER_ID_2; - let router_id_3 = ROUTER_ID_3; - - //TODO(cdamian): Router init - // let router_hash_1 = ROUTER_ID_1; - // let router_hash_2 = ROUTER_ID_2; - // let router_hash_3 = ROUTER_ID_3; - // - // let router_mock_1 = RouterMock::::default(); - // let router_mock_2 = RouterMock::::default(); - // let router_mock_3 = RouterMock::::default(); - // - // router_mock_1.mock_init(move || Ok(())); - // router_mock_1.mock_hash(move || router_hash_1); - // router_mock_2.mock_init(move || Ok(())); - // router_mock_2.mock_hash(move || router_hash_2); - // router_mock_3.mock_init(move || Ok(())); - // router_mock_3.mock_hash(move || router_hash_3); - - assert_ok!(LiquidityPoolsGateway::set_domain_routers( + assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - domain.clone(), - BoundedVec::try_from(vec![router_id_1, router_id_2, router_id_3]).unwrap(), + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), )); MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { @@ -546,9 +484,8 @@ mod outbound_message_handler_impl { let router_id_2 = ROUTER_ID_2; let router_id_3 = ROUTER_ID_3; - assert_ok!(LiquidityPoolsGateway::set_domain_routers( + assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - domain.clone(), BoundedVec::try_from(vec![router_id_1.clone(), router_id_2, router_id_3]).unwrap(), )); @@ -640,13 +577,11 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - Routers::::insert( - TEST_DOMAIN_ADDRESS.domain(), - BoundedVec::try_from(test_routers.clone()).unwrap(), + Routers::::set( + Some(BoundedVec::try_from(test_routers.clone()).unwrap()), ); - InboundMessageSessions::::insert( - TEST_DOMAIN_ADDRESS.domain(), - session_id, + SessionIdStore::::set( + Some(session_id), ); let handler = MockLiquidityPools::mock_handle(move |_, _| Ok(())); @@ -796,11 +731,10 @@ mod message_processor_impl { router_id: router_id.clone(), }; - Routers::::insert( - domain_address.domain(), + Routers::::set(Some( BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), - ); - InboundMessageSessions::::insert(domain_address.domain(), session_id); + )); + SessionIdStore::::set(Some(session_id)); let handler = MockLiquidityPools::mock_handle( move |mock_domain_address, mock_message| { @@ -852,13 +786,12 @@ mod message_processor_impl { router_id: router_id.clone(), }; - Routers::::insert( - domain_address.domain(), + Routers::::set(Some( BoundedVec::<_, _>::try_from(vec![router_id]).unwrap(), - ); + )); let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::InboundDomainSessionNotFound); + assert_noop!(res, Error::::SessionIdNotFound); }); } @@ -877,11 +810,10 @@ mod message_processor_impl { router_id: ROUTER_ID_2, }; - Routers::::insert( - domain_address.domain(), + Routers::::set(Some( BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), - ); - InboundMessageSessions::::insert(domain_address.domain(), session_id); + )); + SessionIdStore::::set(Some(session_id)); let (res, _) = LiquidityPoolsGateway::process(gateway_message); assert_noop!(res, Error::::UnknownRouter); @@ -902,11 +834,10 @@ mod message_processor_impl { router_id: router_id.clone(), }; - Routers::::insert( - domain_address.domain(), + Routers::::set(Some( BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), - ); - InboundMessageSessions::::insert(domain_address.domain(), session_id); + )); + SessionIdStore::::set(Some(session_id)); PendingInboundEntries::::insert( session_id, (message_proof, router_id), @@ -1531,14 +1462,10 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - Routers::::insert( - TEST_DOMAIN_ADDRESS.domain(), + Routers::::set(Some( BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - ); - InboundMessageSessions::::insert( - TEST_DOMAIN_ADDRESS.domain(), - session_id, - ); + )); + SessionIdStore::::set(Some(session_id)); let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, @@ -1556,14 +1483,10 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - Routers::::insert( - TEST_DOMAIN_ADDRESS.domain(), + Routers::::set(Some( BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - ); - InboundMessageSessions::::insert( - TEST_DOMAIN_ADDRESS.domain(), - session_id, - ); + )); + SessionIdStore::::set(Some(session_id)); let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, @@ -2504,11 +2427,10 @@ mod message_processor_impl { let router_id = ROUTER_ID_1; - Routers::::insert( - domain_address.domain(), + Routers::::set(Some( BoundedVec::try_from(vec![router_id.clone()]).unwrap(), - ); - InboundMessageSessions::::insert(domain_address.domain(), 1); + )); + SessionIdStore::::set(Some(1)); let message = Message::Simple; let gateway_message = GatewayMessage::Inbound { @@ -2541,26 +2463,23 @@ mod message_processor_impl { let sender = TEST_DOMAIN_ADDRESS; let message = Message::Simple; - let router_post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(1, 1)), - pays_fee: Pays::Yes, - }; - - let router_id = ROUTER_ID_1; - - let min_expected_weight = ::DbWeight::get() - .reads(1) + router_post_info.actual_weight.unwrap() - + Weight::from_parts(0, message.serialize().len() as u64); - let gateway_message = GatewayMessage::Outbound { - sender, + sender: sender.clone(), message: message.clone(), - router_id, + router_id: ROUTER_ID_1, }; + MockMessageSender::mock_send(move |mock_router_id, mock_sender, mock_message| { + assert_eq!(mock_router_id, ROUTER_ID_1); + assert_eq!(mock_sender, sender); + assert_eq!(mock_message, message.serialize()); + + Ok(()) + }); + let (res, weight) = LiquidityPoolsGateway::process(gateway_message); assert_ok!(res); - assert!(weight.all_lte(min_expected_weight)); + assert!(weight.eq(&LP_DEFENSIVE_WEIGHT)); }); } @@ -2592,26 +2511,25 @@ mod message_processor_impl { let sender = TEST_DOMAIN_ADDRESS; let message = Message::Simple; - let router_post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(1, 1)), - pays_fee: Pays::Yes, - }; - - let min_expected_weight = ::DbWeight::get() - .reads(1) + router_post_info.actual_weight.unwrap() - + Weight::from_parts(0, message.serialize().len() as u64); - let gateway_message = GatewayMessage::Outbound { - sender, + sender: sender.clone(), message: message.clone(), router_id: ROUTER_ID_1, }; + let router_err = DispatchError::Unavailable; + + MockMessageSender::mock_send(move |mock_router_id, mock_sender, mock_message| { + assert_eq!(mock_router_id, ROUTER_ID_1); + assert_eq!(mock_sender, sender); + assert_eq!(mock_message, message.serialize()); + + Err(router_err) + }); + let (res, weight) = LiquidityPoolsGateway::process(gateway_message); - //TODO(cdamian): Error out - assert_ok!(res); - // assert_noop!(res, router_err) - assert!(weight.all_lte(min_expected_weight)); + assert_noop!(res, router_err); + assert!(weight.eq(&LP_DEFENSIVE_WEIGHT)); }); } } @@ -2622,7 +2540,7 @@ mod batches { const USER: AccountId32 = AccountId32::new([1; 32]); const OTHER: AccountId32 = AccountId32::new([2; 32]); - const DOMAIN: Domain = Domain::EVM(1); + const DOMAIN: Domain = Domain::EVM(TEST_EVM_CHAIN); #[test] fn pack_empty() { @@ -2651,26 +2569,16 @@ mod batches { // Ok Batched assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - let router_id_1 = ROUTER_ID_1; - - Routers::::insert( - DOMAIN, - BoundedVec::try_from(vec![router_id_1.clone()]).unwrap(), - ); + Routers::::set(Some(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap())); - // Not batched, it belong to OTHER + // Not batched, it belongs to OTHER assert_ok!(LiquidityPoolsGateway::handle( OTHER, DOMAIN, Message::Simple )); - Routers::::insert( - Domain::EVM(2), - BoundedVec::try_from(vec![router_id_1]).unwrap(), - ); - - // Not batched, it belong to EVM 2 + // Not batched, it belongs to EVM 2 assert_ok!(LiquidityPoolsGateway::handle( USER, Domain::EVM(2), @@ -2680,7 +2588,7 @@ mod batches { // Ok Batched assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - // Just the two non-packed messages + // Two non-packed messages assert_eq!(handle.times(), 2); assert_ok!(LiquidityPoolsGateway::end_batch_message( @@ -2714,7 +2622,7 @@ mod batches { let router_id_1 = ROUTER_ID_1; - Routers::::insert(DOMAIN, BoundedVec::try_from(vec![router_id_1]).unwrap()); + Routers::::set(Some(BoundedVec::try_from(vec![router_id_1]).unwrap())); assert_ok!(LiquidityPoolsGateway::end_batch_message( RuntimeOrigin::signed(USER), @@ -2752,15 +2660,12 @@ mod batches { fn process_inbound() { new_test_ext().execute_with(|| { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); + let domain_address = DomainAddress::EVM(TEST_EVM_CHAIN, address.into()); let router_id_1 = ROUTER_ID_1; - Routers::::insert( - domain_address.domain(), - BoundedVec::try_from(vec![router_id_1]).unwrap(), - ); - InboundMessageSessions::::insert(domain_address.domain(), 1); + Routers::::set(Some(BoundedVec::try_from(vec![router_id_1]).unwrap())); + SessionIdStore::::set(Some(1)); let handler = MockLiquidityPools::mock_handle(|_, _| Ok(())); @@ -2809,15 +2714,12 @@ mod batches { fn process_inbound_with_errors() { new_test_ext().execute_with(|| { let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); + let domain_address = DomainAddress::EVM(1, address.into()); let router_id_1 = ROUTER_ID_1; - Routers::::insert( - domain_address.domain(), - BoundedVec::try_from(vec![router_id_1]).unwrap(), - ); - InboundMessageSessions::::insert(domain_address.domain(), 1); + Routers::::set(Some(BoundedVec::try_from(vec![router_id_1]).unwrap())); + SessionIdStore::::set(Some(1)); let counter = Arc::new(AtomicU32::new(0)); @@ -2847,25 +2749,19 @@ mod execute_message_recovery { #[test] fn success() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); let router_id = ROUTER_ID_1; let session_id = 1; - Routers::::insert( - domain.clone(), - BoundedVec::try_from(vec![router_id.clone()]).unwrap(), - ); - InboundMessageSessions::::insert(domain.clone(), session_id); + Routers::::set(Some(BoundedVec::try_from(vec![router_id.clone()]).unwrap())); + SessionIdStore::::set(Some(session_id)); assert_ok!(LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), - domain.clone(), MESSAGE_PROOF, router_id.clone(), )); event_exists(Event::::MessageRecoveryExecuted { - domain: domain.clone(), proof: MESSAGE_PROOF, router_id: router_id.clone(), }); @@ -2883,7 +2779,6 @@ mod execute_message_recovery { assert_ok!(LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), - domain.clone(), MESSAGE_PROOF, router_id.clone() )); @@ -2900,7 +2795,6 @@ mod execute_message_recovery { ); event_exists(Event::::MessageRecoveryExecuted { - domain: domain.clone(), proof: MESSAGE_PROOF, router_id, }); @@ -2910,17 +2804,13 @@ mod execute_message_recovery { #[test] fn inbound_domain_session_not_found() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let router_id = ROUTER_ID_1; - assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), - domain.clone(), MESSAGE_PROOF, - router_id + ROUTER_ID_1, ), - Error::::InboundDomainSessionNotFound + Error::::SessionIdNotFound ); }); } @@ -2928,18 +2818,13 @@ mod execute_message_recovery { #[test] fn routers_not_found() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let router_id = ROUTER_ID_1; - let session_id = 1; - - InboundMessageSessions::::insert(domain.clone(), session_id); + SessionIdStore::::set(Some(1)); assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), - domain.clone(), MESSAGE_PROOF, - router_id + ROUTER_ID_1, ), Error::::RoutersNotFound ); @@ -2949,23 +2834,14 @@ mod execute_message_recovery { #[test] fn unknown_inbound_message_router() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let router_id_1 = ROUTER_ID_1; - let router_id_2 = ROUTER_ID_2; - let session_id = 1; - - Routers::::insert( - domain.clone(), - BoundedVec::try_from(vec![router_id_1]).unwrap(), - ); - InboundMessageSessions::::insert(domain.clone(), session_id); + Routers::::set(Some(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap())); + SessionIdStore::::set(Some(1)); assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), - domain.clone(), MESSAGE_PROOF, - router_id_2 + ROUTER_ID_2 ), Error::::UnknownRouter ); @@ -2975,15 +2851,11 @@ mod execute_message_recovery { #[test] fn proof_count_overflow() { new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); let router_id = ROUTER_ID_1; let session_id = 1; - Routers::::insert( - domain.clone(), - BoundedVec::try_from(vec![router_id.clone()]).unwrap(), - ); - InboundMessageSessions::::insert(domain.clone(), session_id); + Routers::::set(Some(BoundedVec::try_from(vec![router_id.clone()]).unwrap())); + SessionIdStore::::set(Some(session_id)); PendingInboundEntries::::insert( session_id, (MESSAGE_PROOF, router_id.clone()), @@ -2995,7 +2867,6 @@ mod execute_message_recovery { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), - domain.clone(), MESSAGE_PROOF, router_id ), @@ -3011,11 +2882,8 @@ mod execute_message_recovery { let router_id = ROUTER_ID_1; let session_id = 1; - Routers::::insert( - domain_address.domain(), - BoundedVec::try_from(vec![router_id.clone()]).unwrap(), - ); - InboundMessageSessions::::insert(domain_address.domain(), session_id); + Routers::::set(Some(BoundedVec::try_from(vec![router_id.clone()]).unwrap())); + SessionIdStore::::set(Some(session_id)); PendingInboundEntries::::insert( session_id, (MESSAGE_PROOF, router_id.clone()), @@ -3029,7 +2897,6 @@ mod execute_message_recovery { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), - domain_address.domain(), MESSAGE_PROOF, router_id ), From 5a10a02847af491d6f81859a1b283a7b135591cc Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:01:51 +0300 Subject: [PATCH 17/38] lp-gateway: Rename RouterSupport to RouterProvider, add separate entity that implements it --- libs/primitives/src/lib.rs | 3 +++ libs/traits/src/liquidity_pools.rs | 7 +++++-- pallets/liquidity-pools-gateway/src/lib.rs | 7 +++++-- .../src/message_processing.rs | 4 ++-- pallets/liquidity-pools-gateway/src/mock.rs | 11 ++++++++--- pallets/liquidity-pools-gateway/src/tests.rs | 5 +---- runtime/altair/src/lib.rs | 10 +++++++--- runtime/centrifuge/src/lib.rs | 10 +++++++--- runtime/common/src/routing.rs | 11 ++++++++--- runtime/development/src/lib.rs | 12 ++++++++---- 10 files changed, 54 insertions(+), 26 deletions(-) diff --git a/libs/primitives/src/lib.rs b/libs/primitives/src/lib.rs index d7200cfa29..323cf554f6 100644 --- a/libs/primitives/src/lib.rs +++ b/libs/primitives/src/lib.rs @@ -161,6 +161,9 @@ pub mod types { /// The type for LP gateway message nonces. pub type LPGatewayQueueMessageNonce = u64; + + /// The type for LP gateway session IDs. + pub type LPGatewaySessionId = u64; } /// Common constants for all runtimes diff --git a/libs/traits/src/liquidity_pools.rs b/libs/traits/src/liquidity_pools.rs index a28f29a5b3..1eefd5510f 100644 --- a/libs/traits/src/liquidity_pools.rs +++ b/libs/traits/src/liquidity_pools.rs @@ -41,9 +41,12 @@ pub trait LPEncoding: Sized { fn to_message_proof(&self) -> Self; } -pub trait RouterSupport: Sized { +pub trait RouterProvider: Sized { + /// The router identifier. + type RouterId; + /// Returns a list of routers supported for the given domain. - fn for_domain(domain: Domain) -> Vec; + fn routers_for_domain(domain: Domain) -> Vec; } /// The behavior of an entity that can send messages diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 6fc5819942..c2e53c916a 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -31,7 +31,7 @@ use core::fmt::Debug; use cfg_primitives::LP_DEFENSIVE_WEIGHT; use cfg_traits::liquidity_pools::{ InboundMessageHandler, LPEncoding, MessageProcessor, MessageQueue, MessageReceiver, - MessageSender, OutboundMessageHandler, Proof, RouterSupport, + MessageSender, OutboundMessageHandler, Proof, RouterProvider, }; use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; @@ -106,7 +106,10 @@ pub mod pallet { type MessageSender: MessageSender; /// An identification of a router - type RouterId: RouterSupport + Parameter + Default + MaxEncodedLen; + type RouterId: Parameter + Default + MaxEncodedLen; + + /// The type that provides the router available for a domain. + type RouterProvider: RouterProvider; /// The type that processes inbound messages. type InboundMessageHandler: InboundMessageHandler< diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index a999a9d015..87c23e3def 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -1,6 +1,6 @@ use cfg_primitives::LP_DEFENSIVE_WEIGHT; use cfg_traits::liquidity_pools::{ - InboundMessageHandler, LPEncoding, MessageQueue, MessageSender, Proof, RouterSupport, + InboundMessageHandler, LPEncoding, MessageQueue, MessageSender, Proof, RouterProvider, }; use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{ @@ -49,7 +49,7 @@ impl Pallet { /// Retrieves all available routers for a domain and then filters them based /// on the routers that we have in storage. fn get_router_ids_for_domain(domain: Domain) -> Result, DispatchError> { - let all_routers_for_domain = T::RouterId::for_domain(domain); + let all_routers_for_domain = T::RouterProvider::routers_for_domain(domain); let stored_routers = Routers::::get().ok_or(Error::::RoutersNotFound)?; diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index de08a1216b..a94bf1bc1c 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Formatter}; use cfg_mocks::{pallet_mock_liquidity_pools, pallet_mock_liquidity_pools_gateway_queue}; -use cfg_traits::liquidity_pools::{LPEncoding, Proof, RouterSupport}; +use cfg_traits::liquidity_pools::{LPEncoding, Proof, RouterProvider}; use cfg_types::{ domain_address::{Domain, DomainAddress}, EVMChainId, @@ -115,8 +115,12 @@ impl LPEncoding for Message { #[derive(Default, Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen, Hash)] pub struct RouterId(pub u32); -impl RouterSupport for RouterId { - fn for_domain(domain: Domain) -> Vec { +pub struct TestRouterProvider; + +impl RouterProvider for TestRouterProvider { + type RouterId = RouterId; + + fn routers_for_domain(domain: Domain) -> Vec { match domain { Domain::Centrifuge => vec![], Domain::EVM(_) => vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], @@ -173,6 +177,7 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type MessageQueue = MockLiquidityPoolsGatewayQueue; type MessageSender = MockMessageSender; type RouterId = RouterId; + type RouterProvider = TestRouterProvider; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type Sender = Sender; diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 6432962431..202d7e721a 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -3,10 +3,7 @@ use std::collections::HashMap; use cfg_primitives::LP_DEFENSIVE_WEIGHT; use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler}; use cfg_types::domain_address::*; -use frame_support::{ - assert_err, assert_noop, assert_ok, dispatch::PostDispatchInfo, pallet_prelude::Pays, - weights::Weight, -}; +use frame_support::{assert_err, assert_noop, assert_ok, weights::Weight}; use itertools::Itertools; use lazy_static::lazy_static; use parity_scale_codec::MaxEncodedLen; diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 3889aadaf9..68a80a4288 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -27,7 +27,7 @@ use cfg_primitives::{ IBalance, InvestmentId, ItemId, LoanId, Nonce, OrderId, PalletIndex, PoolEpochId, PoolFeeId, PoolId, Signature, TrancheId, TrancheWeight, }, - LPGatewayQueueMessageNonce, + LPGatewayQueueMessageNonce, LPGatewaySessionId, }; use cfg_traits::{investments::OrderManager, Millis, PoolUpdateGuard, Seconds}; use cfg_types::{ @@ -117,7 +117,7 @@ use runtime_common::{ permissions::{IsUnfrozenTrancheInvestor, PoolAdminCheck}, remarks::Remark, rewards::SingleCurrencyMovement, - routing::{EvmAccountCodeChecker, RouterDispatcher, RouterId}, + routing::{EvmAccountCodeChecker, LPGatewayRouterProvider, RouterDispatcher, RouterId}, transfer_filter::{PreLpTransfer, PreNativeTransfer}, xcm::AccountIdToLocation, xcm_transactor, AllowanceDeposit, CurrencyED, @@ -1757,8 +1757,9 @@ impl pallet_liquidity_pools::Config for Runtime { } parameter_types! { - pub const MaxIncomingMessageSize: u32 = 1024; pub Sender: DomainAddress = gateway::get_gateway_account::(); + pub const MaxIncomingMessageSize: u32 = 1024; + pub const MaxRouterCount: u32 = 8; } impl pallet_liquidity_pools_gateway::Config for Runtime { @@ -1766,13 +1767,16 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type InboundMessageHandler = LiquidityPools; type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; + type MaxRouterCount = MaxRouterCount; type Message = pallet_liquidity_pools::Message; type MessageQueue = LiquidityPoolsGatewayQueue; type MessageSender = RouterDispatcher; type RouterId = RouterId; + type RouterProvider = LPGatewayRouterProvider; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type Sender = Sender; + type SessionId = LPGatewaySessionId; type WeightInfo = (); } diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index a4e2102a18..d64630fade 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -27,7 +27,7 @@ use cfg_primitives::{ IBalance, InvestmentId, ItemId, LoanId, Nonce, OrderId, PalletIndex, PoolEpochId, PoolFeeId, PoolId, Signature, TrancheId, TrancheWeight, }, - LPGatewayQueueMessageNonce, + LPGatewayQueueMessageNonce, LPGatewaySessionId, }; use cfg_traits::{ investments::OrderManager, Millis, Permissions as PermissionsT, PoolUpdateGuard, PreConditions, @@ -117,7 +117,7 @@ use runtime_common::{ }, permissions::{IsUnfrozenTrancheInvestor, PoolAdminCheck}, rewards::SingleCurrencyMovement, - routing::{EvmAccountCodeChecker, RouterDispatcher, RouterId}, + routing::{EvmAccountCodeChecker, LPGatewayRouterProvider, RouterDispatcher, RouterId}, transfer_filter::{PreLpTransfer, PreNativeTransfer}, xcm::AccountIdToLocation, xcm_transactor, AllowanceDeposit, CurrencyED, @@ -1840,8 +1840,9 @@ impl pallet_liquidity_pools::Config for Runtime { } parameter_types! { - pub const MaxIncomingMessageSize: u32 = 1024; pub Sender: DomainAddress = gateway::get_gateway_account::(); + pub const MaxIncomingMessageSize: u32 = 1024; + pub const MaxRouterCount: u32 = 8; } parameter_types! { @@ -1865,13 +1866,16 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type InboundMessageHandler = LiquidityPools; type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; + type MaxRouterCount = MaxRouterCount; type Message = pallet_liquidity_pools::Message; type MessageQueue = LiquidityPoolsGatewayQueue; type MessageSender = RouterDispatcher; type RouterId = RouterId; + type RouterProvider = LPGatewayRouterProvider; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type Sender = Sender; + type SessionId = LPGatewaySessionId; type WeightInfo = (); } diff --git a/runtime/common/src/routing.rs b/runtime/common/src/routing.rs index 9b9e345d3e..90cc97b62f 100644 --- a/runtime/common/src/routing.rs +++ b/runtime/common/src/routing.rs @@ -1,5 +1,5 @@ use cfg_traits::{ - liquidity_pools::{MessageSender, RouterSupport}, + liquidity_pools::{MessageSender, RouterProvider}, PreConditions, }; use cfg_types::domain_address::{Domain, DomainAddress}; @@ -37,8 +37,13 @@ impl From for Domain { } } -impl RouterSupport for RouterId { - fn for_domain(domain: Domain) -> Vec { +/// Static router provider used in the LP gateway. +pub struct LPGatewayRouterProvider; + +impl RouterProvider for LPGatewayRouterProvider { + type RouterId = RouterId; + + fn routers_for_domain(domain: Domain) -> Vec { match domain { Domain::EVM(chain_id) => vec![RouterId::Axelar(AxelarId::Evm(chain_id))], Domain::Centrifuge => vec![], diff --git a/runtime/development/src/lib.rs b/runtime/development/src/lib.rs index 973921019e..5fc9aa1b0e 100644 --- a/runtime/development/src/lib.rs +++ b/runtime/development/src/lib.rs @@ -27,7 +27,7 @@ use cfg_primitives::{ IBalance, InvestmentId, ItemId, LoanId, Nonce, OrderId, PalletIndex, PoolEpochId, PoolFeeId, PoolId, Signature, TrancheId, TrancheWeight, }, - LPGatewayQueueMessageNonce, + LPGatewayQueueMessageNonce, LPGatewaySessionId, }; use cfg_traits::{ investments::OrderManager, Millis, Permissions as PermissionsT, PoolUpdateGuard, PreConditions, @@ -125,7 +125,7 @@ use runtime_common::{ permissions::{IsUnfrozenTrancheInvestor, PoolAdminCheck}, remarks::Remark, rewards::SingleCurrencyMovement, - routing::{EvmAccountCodeChecker, RouterDispatcher, RouterId}, + routing::{EvmAccountCodeChecker, LPGatewayRouterProvider, RouterDispatcher, RouterId}, transfer_filter::{PreLpTransfer, PreNativeTransfer}, xcm::AccountIdToLocation, xcm_transactor, AllowanceDeposit, CurrencyED, @@ -1862,8 +1862,9 @@ impl pallet_liquidity_pools::Config for Runtime { } parameter_types! { - pub const MaxIncomingMessageSize: u32 = 1024; pub Sender: DomainAddress = gateway::get_gateway_account::(); + pub const MaxIncomingMessageSize: u32 = 1024; + pub const MaxRouterCount: u32 = 8; } impl pallet_liquidity_pools_gateway::Config for Runtime { @@ -1871,18 +1872,21 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { type InboundMessageHandler = LiquidityPools; type LocalEVMOrigin = pallet_liquidity_pools_gateway::EnsureLocal; type MaxIncomingMessageSize = MaxIncomingMessageSize; + type MaxRouterCount = MaxRouterCount; type Message = pallet_liquidity_pools::Message; type MessageQueue = LiquidityPoolsGatewayQueue; type MessageSender = RouterDispatcher; type RouterId = RouterId; + type RouterProvider = LPGatewayRouterProvider; type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; type Sender = Sender; + type SessionId = LPGatewaySessionId; type WeightInfo = (); } impl pallet_liquidity_pools_gateway_queue::Config for Runtime { - type Message = GatewayMessage; + type Message = GatewayMessage; type MessageNonce = LPGatewayQueueMessageNonce; type MessageProcessor = LiquidityPoolsGateway; type RuntimeEvent = RuntimeEvent; From 8a1230fa9c9315d474c196b0e7fd4c6b36af2e83 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Tue, 13 Aug 2024 21:13:45 +0300 Subject: [PATCH 18/38] lp-gateway: Add more asserts in unit tests --- libs/mocks/src/router_message.rs | 6 +- pallets/liquidity-pools-gateway/src/tests.rs | 93 +++++++++----------- 2 files changed, 46 insertions(+), 53 deletions(-) diff --git a/libs/mocks/src/router_message.rs b/libs/mocks/src/router_message.rs index 4d21688a11..58e7166d38 100644 --- a/libs/mocks/src/router_message.rs +++ b/libs/mocks/src/router_message.rs @@ -2,7 +2,7 @@ pub mod pallet { use cfg_traits::liquidity_pools::{MessageReceiver, MessageSender}; use frame_support::pallet_prelude::*; - use mock_builder::{execute_call, register_call}; + use mock_builder::{execute_call, register_call, CallHandler}; #[pallet::config] pub trait Config: frame_system::Config { @@ -25,8 +25,8 @@ pub mod pallet { pub fn mock_send( f: impl Fn(T::Middleware, T::Origin, Vec) -> DispatchResult + 'static, - ) { - register_call!(move |(a, b, c)| f(a, b, c)); + ) -> CallHandler { + register_call!(move |(a, b, c)| f(a, b, c)) } } diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 202d7e721a..6600aa9a3c 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -305,7 +305,7 @@ mod receive_message_domain { router_id: router_id.clone(), }; - MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { assert_eq!(mock_message, gateway_message); Ok(()) }); @@ -315,6 +315,8 @@ mod receive_message_domain { router_id, BoundedVec::::try_from(encoded_msg).unwrap() )); + + assert_eq!(handler.times(), 1); }); } @@ -430,7 +432,7 @@ mod outbound_message_handler_impl { BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), )); - MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { match mock_msg { GatewayMessage::Inbound { .. } => { assert!(false, "expected outbound message") @@ -453,11 +455,12 @@ mod outbound_message_handler_impl { }); assert_ok!(LiquidityPoolsGateway::handle(sender, domain, msg)); + assert_eq!(handler.times(), 3); }); } #[test] - fn local_domain() { + fn domain_not_supported() { new_test_ext().execute_with(|| { let domain = Domain::Centrifuge; let sender = get_test_account_id(); @@ -471,25 +474,35 @@ mod outbound_message_handler_impl { } #[test] - fn message_queue_error() { + fn routers_not_found() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); let sender = get_test_account_id(); let msg = Message::Simple; - let router_id_1 = ROUTER_ID_1; - let router_id_2 = ROUTER_ID_2; - let router_id_3 = ROUTER_ID_3; + assert_noop!( + LiquidityPoolsGateway::handle(sender, domain, msg), + Error::::RoutersNotFound + ); + }); + } + + #[test] + fn message_queue_error() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let sender = get_test_account_id(); + let msg = Message::Simple; assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - BoundedVec::try_from(vec![router_id_1.clone(), router_id_2, router_id_3]).unwrap(), + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), )); let gateway_message = GatewayMessage::Outbound { sender: ::Sender::get(), message: msg.clone(), - router_id: router_id_1, + router_id: ROUTER_ID_1, }; let err = DispatchError::Unavailable; @@ -523,7 +536,7 @@ mod set_domain_hook { } #[test] - fn failure_bad_origin() { + fn bad_origin() { new_test_ext().execute_with(|| { let domain = Domain::EVM(0); @@ -539,7 +552,7 @@ mod set_domain_hook { } #[test] - fn failure_centrifuge_domain() { + fn domain_not_supported() { new_test_ext().execute_with(|| { let domain = Domain::Centrifuge; @@ -2422,10 +2435,8 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_id = ROUTER_ID_1; - Routers::::set(Some( - BoundedVec::try_from(vec![router_id.clone()]).unwrap(), + BoundedVec::try_from(vec![ROUTER_ID_1.clone()]).unwrap(), )); SessionIdStore::::set(Some(1)); @@ -2433,7 +2444,7 @@ mod message_processor_impl { let gateway_message = GatewayMessage::Inbound { domain_address: domain_address.clone(), message: message.clone(), - router_id, + router_id: ROUTER_ID_1, }; let err = DispatchError::Unavailable; @@ -2466,44 +2477,25 @@ mod message_processor_impl { router_id: ROUTER_ID_1, }; - MockMessageSender::mock_send(move |mock_router_id, mock_sender, mock_message| { - assert_eq!(mock_router_id, ROUTER_ID_1); - assert_eq!(mock_sender, sender); - assert_eq!(mock_message, message.serialize()); + let handler = MockMessageSender::mock_send( + move |mock_router_id, mock_sender, mock_message| { + assert_eq!(mock_router_id, ROUTER_ID_1); + assert_eq!(mock_sender, sender); + assert_eq!(mock_message, message.serialize()); - Ok(()) - }); + Ok(()) + }, + ); let (res, weight) = LiquidityPoolsGateway::process(gateway_message); assert_ok!(res); assert!(weight.eq(&LP_DEFENSIVE_WEIGHT)); + assert_eq!(handler.times(), 1); }); } - //TODO(cdamian): Fix when bi-directional routers are in. - // #[test] - // fn router_not_found() { - // new_test_ext().execute_with(|| { - // let sender = get_test_account_id(); - // let message = Message::Simple; - // - // let expected_weight = ::DbWeight::get().reads(1); - // - // let gateway_message = GatewayMessage::Outbound { - // sender, - // message, - // router_id: ROUTER_ID_1, - // }; - // - // let (res, weight) = LiquidityPoolsGateway::process(gateway_message); - // assert_noop!(res, Error::::RouterNotFound); - // assert_eq!(weight, expected_weight); - // }); - // } - #[test] - fn router_error() { + fn message_sender_error() { new_test_ext().execute_with(|| { let sender = TEST_DOMAIN_ADDRESS; let message = Message::Simple; @@ -2561,7 +2553,7 @@ mod batches { DOMAIN )); - let handle = MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); // Ok Batched assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); @@ -2586,7 +2578,7 @@ mod batches { assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); // Two non-packed messages - assert_eq!(handle.times(), 2); + assert_eq!(handler.times(), 2); assert_ok!(LiquidityPoolsGateway::end_batch_message( RuntimeOrigin::signed(USER), @@ -2594,7 +2586,7 @@ mod batches { )); // Packed message queued - assert_eq!(handle.times(), 3); + assert_eq!(handler.times(), 3); }); } @@ -2606,7 +2598,7 @@ mod batches { DOMAIN )); - MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); (0..MAX_PACKED_MESSAGES).for_each(|_| { assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); @@ -2625,6 +2617,7 @@ mod batches { RuntimeOrigin::signed(USER), DOMAIN )); + assert_eq!(handler.times(), 1); }); } @@ -2799,7 +2792,7 @@ mod execute_message_recovery { } #[test] - fn inbound_domain_session_not_found() { + fn session_id_not_found() { new_test_ext().execute_with(|| { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( @@ -2829,7 +2822,7 @@ mod execute_message_recovery { } #[test] - fn unknown_inbound_message_router() { + fn unknown_router() { new_test_ext().execute_with(|| { Routers::::set(Some(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap())); SessionIdStore::::set(Some(1)); From 58c5d9bccc8ef52d2b59d3c3352503d3ea2f88db Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Tue, 13 Aug 2024 22:56:33 +0300 Subject: [PATCH 19/38] lp-gateway: Attempt to execute message during recovery --- pallets/liquidity-pools-gateway/src/lib.rs | 31 +++-- .../src/message_processing.rs | 74 +++++------ pallets/liquidity-pools-gateway/src/tests.rs | 115 +++++++++++++----- .../liquidity-pools-gateway/src/weights.rs | 4 +- 4 files changed, 151 insertions(+), 73 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index c2e53c916a..d66f224706 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -61,6 +61,8 @@ mod tests; #[frame_support::pallet] pub mod pallet { + use frame_support::dispatch::PostDispatchInfo; + use super::*; const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -291,12 +293,15 @@ pub mod pallet { /// Not enough routers are stored for a domain. NotEnoughRoutersForDomain, + + /// First router for a domain was not found. + FirstRouterNotFound, } #[pallet::call] impl Pallet { /// Sets the router IDs used for a specific domain, - #[pallet::weight(T::WeightInfo::set_domain_routers())] + #[pallet::weight(T::WeightInfo::set_routers())] #[pallet::call_index(0)] pub fn set_routers( origin: OriginFor, @@ -451,22 +456,29 @@ pub mod pallet { #[pallet::call_index(11)] pub fn execute_message_recovery( origin: OriginFor, + domain_address: DomainAddress, proof: Proof, router_id: T::RouterId, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { T::AdminOrigin::ensure_origin(origin)?; - let session_id = SessionIdStore::::get().ok_or(Error::::SessionIdNotFound)?; + let mut weight = Weight::default(); - let routers = Routers::::get().ok_or(Error::::RoutersNotFound)?; + let inbound_processing_info = + Self::get_inbound_processing_info(domain_address, &mut weight)?; ensure!( - routers.iter().any(|x| x == &router_id), + inbound_processing_info + .router_ids + .iter() + .any(|x| x == &router_id), Error::::UnknownRouter ); + weight.saturating_accrue(T::DbWeight::get().writes(1)); + PendingInboundEntries::::try_mutate( - session_id, + inbound_processing_info.current_session_id, (proof, router_id.clone()), |storage_entry| match storage_entry { Some(entry) => match entry { @@ -485,9 +497,14 @@ pub mod pallet { }, )?; + Self::execute_if_requirements_are_met(&inbound_processing_info, proof, &mut weight)?; + Self::deposit_event(Event::::MessageRecoveryExecuted { proof, router_id }); - Ok(()) + Ok(PostDispatchInfo { + actual_weight: Some(weight), + pays_fee: Pays::Yes, + }) } } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 87c23e3def..be334410a5 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -39,16 +39,16 @@ pub enum InboundEntry { /// Type used when processing inbound messages. #[derive(Clone)] pub struct InboundProcessingInfo { - domain_address: DomainAddress, - router_ids: Vec, - current_session_id: T::SessionId, - expected_proof_count_per_message: u32, + pub domain_address: DomainAddress, + pub router_ids: Vec, + pub current_session_id: T::SessionId, + pub expected_proof_count_per_message: u32, } impl Pallet { /// Retrieves all available routers for a domain and then filters them based /// on the routers that we have in storage. - fn get_router_ids_for_domain(domain: Domain) -> Result, DispatchError> { + pub fn get_router_ids_for_domain(domain: Domain) -> Result, DispatchError> { let all_routers_for_domain = T::RouterProvider::routers_for_domain(domain); let stored_routers = Routers::::get().ok_or(Error::::RoutersNotFound)?; @@ -68,10 +68,9 @@ impl Pallet { /// Calculates and returns the proof count required for processing one /// inbound message. - fn get_expected_proof_count(domain: Domain) -> Result { - let routers_count = Self::get_router_ids_for_domain(domain)?.len(); - - let expected_proof_count = routers_count + fn get_expected_proof_count(router_ids: &Vec) -> Result { + let expected_proof_count = router_ids + .len() .ensure_sub(1) .map_err(|_| Error::::NotEnoughRoutersForDomain)?; @@ -216,12 +215,13 @@ impl Pallet { } /// Checks if the number of proofs required for executing one message - /// were received, and returns the message if so. - fn get_executable_message( + /// were received, and if so, decreases the counts accordingly and executes + /// the message. + pub(crate) fn execute_if_requirements_are_met( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, weight: &mut Weight, - ) -> Option { + ) -> DispatchResult { let mut message = None; let mut votes = 0; @@ -234,7 +234,7 @@ impl Pallet { ) { // We expected one InboundEntry for each router, if that's not the case, // we can return. - None => return None, + None => return Ok(()), Some(inbound_entry) => match inbound_entry { InboundEntry::Message { message: stored_message, @@ -249,11 +249,25 @@ impl Pallet { }; } - if votes == inbound_processing_info.expected_proof_count_per_message { - return message; + if votes < inbound_processing_info.expected_proof_count_per_message { + return Ok(()); } - None + match message { + Some(msg) => { + Self::decrease_pending_entries_counts( + &inbound_processing_info, + message_proof, + weight, + )?; + + T::InboundMessageHandler::handle( + inbound_processing_info.domain_address.clone(), + msg, + ) + } + None => Ok(()), + } } /// Decreases the counts for inbound entries and removes them if the @@ -312,7 +326,7 @@ impl Pallet { /// Retrieves the information required for processing an inbound /// message. - fn get_inbound_processing_info( + pub(crate) fn get_inbound_processing_info( domain_address: DomainAddress, weight: &mut Weight, ) -> Result, DispatchError> { @@ -324,7 +338,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads(1)); - let expected_proof_count = Self::get_expected_proof_count(domain_address.domain())?; + let expected_proof_count = Self::get_expected_proof_count(&router_ids)?; weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -373,23 +387,13 @@ impl Pallet { return (Err(e), weight); } - match Self::get_executable_message(&inbound_processing_info, message_proof, &mut weight) - { - Some(m) => { - if let Err(e) = Self::decrease_pending_entries_counts( - &inbound_processing_info, - message_proof, - &mut weight, - ) { - return (Err(e), weight.saturating_mul(count)); - } - - if let Err(e) = T::InboundMessageHandler::handle(domain_address.clone(), m) { - // We only consume the processed weight if error during the batch - return (Err(e), weight.saturating_mul(count)); - } - } - None => continue, + match Self::execute_if_requirements_are_met( + &inbound_processing_info, + message_proof, + &mut weight, + ) { + Err(e) => return (Err(e), weight.saturating_mul(count)), + Ok(_) => continue, } } diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 6600aa9a3c..5904f6c082 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -2737,86 +2737,140 @@ mod execute_message_recovery { use super::*; #[test] - fn success() { + fn success_with_execution() { new_test_ext().execute_with(|| { - let router_id = ROUTER_ID_1; let session_id = 1; - Routers::::set(Some(BoundedVec::try_from(vec![router_id.clone()]).unwrap())); + Routers::::set(Some( + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), + )); SessionIdStore::::set(Some(session_id)); + PendingInboundEntries::::insert( + session_id, + (MESSAGE_PROOF, ROUTER_ID_1), + InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }, + ); + + let handler = + MockLiquidityPools::mock_handle(move |mock_domain_address, mock_message| { + assert_eq!(mock_domain_address, TEST_DOMAIN_ADDRESS); + assert_eq!(mock_message, Message::Simple); + + Ok(()) + }); + assert_ok!(LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, - router_id.clone(), + ROUTER_ID_2, )); event_exists(Event::::MessageRecoveryExecuted { proof: MESSAGE_PROOF, - router_id: router_id.clone(), + router_id: ROUTER_ID_2, }); - let inbound_entry = PendingInboundEntries::::get( + assert_eq!(handler.times(), 1); + + assert!(PendingInboundEntries::::get( session_id, - (MESSAGE_PROOF, router_id.clone()), + (MESSAGE_PROOF, ROUTER_ID_1) ) - .expect("inbound entry is stored"); + .is_none()); - assert_eq!( - inbound_entry, - InboundEntry::::Proof { current_count: 1 } + assert!(PendingInboundEntries::::get( + session_id, + (MESSAGE_PROOF, ROUTER_ID_2) + ) + .is_none()); + }); + } + + #[test] + fn success_without_execution() { + new_test_ext().execute_with(|| { + let session_id = 1; + + Routers::::set(Some( + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), + )); + SessionIdStore::::set(Some(session_id)); + + PendingInboundEntries::::insert( + session_id, + (MESSAGE_PROOF, ROUTER_ID_1), + InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }, ); assert_ok!(LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, - router_id.clone() + ROUTER_ID_2, )); - let inbound_entry = PendingInboundEntries::::get( - session_id, - (MESSAGE_PROOF, router_id.clone()), - ) - .expect("inbound entry is stored"); - - assert_eq!( - inbound_entry, - InboundEntry::::Proof { current_count: 2 } - ); - event_exists(Event::::MessageRecoveryExecuted { proof: MESSAGE_PROOF, - router_id, + router_id: ROUTER_ID_2, }); + + assert_eq!( + PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, ROUTER_ID_1)), + Some(InboundEntry::::Message { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }) + ); + assert_eq!( + PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, ROUTER_ID_2)), + Some(InboundEntry::::Proof { current_count: 1 }) + ); + assert!( + PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, ROUTER_ID_3)) + .is_none() + ) }); } #[test] - fn session_id_not_found() { + fn routers_not_found() { new_test_ext().execute_with(|| { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, ROUTER_ID_1, ), - Error::::SessionIdNotFound + Error::::RoutersNotFound ); }); } #[test] - fn routers_not_found() { + fn session_id_not_found() { new_test_ext().execute_with(|| { - SessionIdStore::::set(Some(1)); + Routers::::set(Some(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap())); assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, ROUTER_ID_1, ), - Error::::RoutersNotFound + Error::::SessionIdNotFound ); }); } @@ -2830,6 +2884,7 @@ mod execute_message_recovery { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, ROUTER_ID_2 ), @@ -2857,6 +2912,7 @@ mod execute_message_recovery { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, router_id ), @@ -2887,6 +2943,7 @@ mod execute_message_recovery { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, router_id ), diff --git a/pallets/liquidity-pools-gateway/src/weights.rs b/pallets/liquidity-pools-gateway/src/weights.rs index aaf598ec91..b330d71ac6 100644 --- a/pallets/liquidity-pools-gateway/src/weights.rs +++ b/pallets/liquidity-pools-gateway/src/weights.rs @@ -13,7 +13,7 @@ use frame_support::weights::{constants::RocksDbWeight, Weight}; pub trait WeightInfo { - fn set_domain_routers() -> Weight; + fn set_routers() -> Weight; fn add_instance() -> Weight; fn remove_instance() -> Weight; fn add_relayer() -> Weight; @@ -31,7 +31,7 @@ pub trait WeightInfo { const N: u64 = 4; impl WeightInfo for () { - fn set_domain_routers() -> Weight { + fn set_routers() -> Weight { // TODO: BENCHMARK CORRECTLY // // NOTE: Reasonable weight taken from `PoolSystem::set_max_reserve` From 207c43fa667b0e1eee7e246514295e2f208adfac Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:29:49 +0300 Subject: [PATCH 20/38] lp-gateway: Remove extra constraints from SessionId --- pallets/liquidity-pools-gateway/src/lib.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index d66f224706..c6c5469afb 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -138,14 +138,7 @@ pub mod pallet { type MaxRouterCount: Get; /// Type for identifying sessions of inbound routers. - type SessionId: Parameter - + Member - + BaseArithmetic - + Default - + Copy - + MaybeSerializeDeserialize - + TypeInfo - + MaxEncodedLen; + type SessionId: Parameter + Member + BaseArithmetic + Default + Copy + MaxEncodedLen; } #[pallet::event] From a5e943f9f6d433e1f653dfd3097b273cfe226988 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:33:44 +0300 Subject: [PATCH 21/38] lp-gateway: Drop session ID invalidation (#1965) * lp-gateway: Drop session ID invalidation * lp-gateway: Add test for invalid router --- pallets/liquidity-pools-gateway/src/lib.rs | 92 +++--- .../src/message_processing.rs | 233 +++++++------ pallets/liquidity-pools-gateway/src/mock.rs | 1 + pallets/liquidity-pools-gateway/src/tests.rs | 306 ++++++++++-------- 4 files changed, 328 insertions(+), 304 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index c6c5469afb..124fc04aa0 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -35,12 +35,12 @@ use cfg_traits::liquidity_pools::{ }; use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; -use frame_system::pallet_prelude::{ensure_signed, BlockNumberFor, OriginFor}; +use frame_system::pallet_prelude::{ensure_signed, OriginFor}; use message::GatewayMessage; use orml_traits::GetByKey; pub use pallet::*; use parity_scale_codec::FullCodec; -use sp_arithmetic::traits::{BaseArithmetic, EnsureAdd, EnsureAddAssign, One, Zero}; +use sp_arithmetic::traits::{BaseArithmetic, EnsureAddAssign, One}; use sp_std::convert::TryInto; use crate::{message_processing::InboundEntry, weights::WeightInfo}; @@ -74,13 +74,6 @@ pub mod pallet { #[pallet::origin] pub type Origin = GatewayOrigin; - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_idle(_now: BlockNumberFor, max_weight: Weight) -> Weight { - Self::clear_invalid_session_ids(max_weight) - } - } - #[pallet::config] pub trait Config: frame_system::Config { /// The origin type. @@ -175,7 +168,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn routers)] pub type Routers = - StorageValue<_, BoundedVec, OptionQuery>; + StorageValue<_, BoundedVec, ValueQuery>; /// Storage that contains a limited number of whitelisted instances of /// deployed liquidity pools for a particular domain. @@ -208,23 +201,15 @@ pub mod pallet { pub type PendingInboundEntries = StorageDoubleMap< _, Blake2_128Concat, - T::SessionId, + Proof, Blake2_128Concat, - (Proof, T::RouterId), + T::RouterId, InboundEntry, >; /// Storage for inbound message session IDs. #[pallet::storage] - pub type SessionIdStore = StorageValue<_, T::SessionId, OptionQuery>; - - /// Storage that keeps track of invalid session IDs. - /// - /// Any `PendingInboundEntries` mapped to the invalid IDs are removed from - /// storage during `on_idle`. - #[pallet::storage] - #[pallet::getter(fn invalid_message_sessions)] - pub type InvalidMessageSessions = StorageMap<_, Blake2_128Concat, T::SessionId, ()>; + pub type SessionIdStore = StorageValue<_, T::SessionId, ValueQuery>; #[pallet::error] pub enum Error { @@ -254,11 +239,8 @@ pub mod pallet { /// was not started by `start_batch_message()`. MessagePackingNotStarted, - /// Invalid multi router. - InvalidMultiRouter, - - /// Session ID not found. - SessionIdNotFound, + /// Invalid routers. + InvalidRouters, /// Unknown router. UnknownRouter, @@ -286,9 +268,6 @@ pub mod pallet { /// Not enough routers are stored for a domain. NotEnoughRoutersForDomain, - - /// First router for a domain was not found. - FirstRouterNotFound, } #[pallet::call] @@ -302,22 +281,15 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - >::set(Some(router_ids.clone())); - - let (old_session_id, new_session_id) = - SessionIdStore::::try_mutate(|storage_entry| { - let old_session_id = storage_entry.unwrap_or(T::SessionId::zero()); - let new_session_id = old_session_id.ensure_add(One::one())?; + ensure!(router_ids.len() > 0, Error::::InvalidRouters); - *storage_entry = Some(new_session_id); + >::set(router_ids.clone()); - Ok::<(T::SessionId, T::SessionId), DispatchError>(( - old_session_id, - new_session_id, - )) - })?; + let new_session_id = SessionIdStore::::try_mutate(|n| { + n.ensure_add_assign(One::one())?; - InvalidMessageSessions::::insert(old_session_id, ()); + Ok::(*n) + })?; Self::deposit_event(Event::RoutersSet { router_ids, @@ -468,27 +440,43 @@ pub mod pallet { Error::::UnknownRouter ); + ensure!( + inbound_processing_info.router_ids.len() > 1, + Error::::NotEnoughRoutersForDomain + ); + weight.saturating_accrue(T::DbWeight::get().writes(1)); - PendingInboundEntries::::try_mutate( - inbound_processing_info.current_session_id, - (proof, router_id.clone()), - |storage_entry| match storage_entry { - Some(entry) => match entry { - InboundEntry::Proof { current_count } => { - current_count.ensure_add_assign(1).map_err(|e| e.into()) + PendingInboundEntries::::try_mutate(proof, router_id.clone(), |storage_entry| { + match storage_entry { + Some(stored_inbound_entry) => match stored_inbound_entry { + InboundEntry::Proof { + session_id, + current_count, + } => { + if *session_id != inbound_processing_info.current_session_id { + *session_id = inbound_processing_info.current_session_id; + *current_count = 1; + } else { + current_count.ensure_add_assign(1)?; + } + + Ok::<(), DispatchError>(()) } InboundEntry::Message { .. } => { Err(Error::::ExpectedMessageProofType.into()) } }, None => { - *storage_entry = Some(InboundEntry::::Proof { current_count: 1 }); + *storage_entry = Some(InboundEntry::::Proof { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }); Ok::<(), DispatchError>(()) } - }, - )?; + } + })?; Self::execute_if_requirements_are_met(&inbound_processing_info, proof, &mut weight)?; diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index be334410a5..045714316c 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -14,24 +14,21 @@ use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub}; use sp_runtime::DispatchError; use crate::{ - message::GatewayMessage, Config, Error, InvalidMessageSessions, Pallet, PendingInboundEntries, - Routers, SessionIdStore, + message::GatewayMessage, Config, Error, Pallet, PendingInboundEntries, Routers, SessionIdStore, }; -/// The limit used when clearing the `PendingInboundEntries` for invalid -/// session IDs. -const INVALID_ID_REMOVAL_LIMIT: u32 = 100; - /// Type used when storing inbound message information. #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub enum InboundEntry { Message { + session_id: T::SessionId, domain_address: DomainAddress, message: T::Message, expected_proof_count: u32, }, Proof { + session_id: T::SessionId, current_count: u32, }, } @@ -51,7 +48,7 @@ impl Pallet { pub fn get_router_ids_for_domain(domain: Domain) -> Result, DispatchError> { let all_routers_for_domain = T::RouterProvider::routers_for_domain(domain); - let stored_routers = Routers::::get().ok_or(Error::::RoutersNotFound)?; + let stored_routers = Routers::::get(); let res = all_routers_for_domain .iter() @@ -91,17 +88,20 @@ impl Pallet { /// Creates an inbound entry based on whether the inbound message is a /// proof or not. fn create_inbound_entry( - domain_address: DomainAddress, + inbound_processing_info: &InboundProcessingInfo, message: T::Message, - expected_proof_count: u32, ) -> InboundEntry { match message.get_message_proof() { None => InboundEntry::Message { - domain_address, + session_id: inbound_processing_info.current_session_id.clone(), + domain_address: inbound_processing_info.domain_address.clone(), message, - expected_proof_count, + expected_proof_count: inbound_processing_info.expected_proof_count_per_message, + }, + Some(_) => InboundEntry::Proof { + session_id: inbound_processing_info.current_session_id, + current_count: 1, }, - Some(_) => InboundEntry::Proof { current_count: 1 }, } } @@ -146,7 +146,6 @@ impl Pallet { /// Upserts an inbound entry for a particular message, increasing the /// relevant counts accordingly. fn upsert_pending_entry( - session_id: T::SessionId, message_proof: Proof, router_id: T::RouterId, inbound_entry: InboundEntry, @@ -154,10 +153,8 @@ impl Pallet { ) -> DispatchResult { weight.saturating_accrue(T::DbWeight::get().writes(1)); - PendingInboundEntries::::try_mutate( - session_id, - (message_proof, router_id), - |storage_entry| match storage_entry { + PendingInboundEntries::::try_mutate(message_proof, router_id, |storage_entry| { + match storage_entry { None => { *storage_entry = Some(inbound_entry); @@ -165,26 +162,51 @@ impl Pallet { } Some(stored_inbound_entry) => match stored_inbound_entry { InboundEntry::Message { - expected_proof_count: old, + session_id: stored_session_id, + expected_proof_count: stored_expected_proof_count, .. } => match inbound_entry { InboundEntry::Message { - expected_proof_count: new, + session_id: new_session_id, + expected_proof_count: new_expected_proof_count, .. - } => old.ensure_add_assign(new).map_err(|e| e.into()), + } => { + if *stored_session_id != new_session_id { + *stored_session_id = new_session_id; + *stored_expected_proof_count = new_expected_proof_count; + } else { + stored_expected_proof_count + .ensure_add_assign(new_expected_proof_count)?; + } + + Ok::<(), DispatchError>(()) + } InboundEntry::Proof { .. } => Err(Error::::ExpectedMessageType.into()), }, - InboundEntry::Proof { current_count: old } => match inbound_entry { - InboundEntry::Proof { current_count: new } => { - old.ensure_add_assign(new).map_err(|e| e.into()) + InboundEntry::Proof { + session_id: stored_session_id, + current_count: stored_current_count, + } => match inbound_entry { + InboundEntry::Proof { + session_id: new_session_id, + current_count: new_current_count, + } => { + if *stored_session_id != new_session_id { + *stored_session_id = new_session_id; + *stored_current_count = new_current_count; + } else { + stored_current_count.ensure_add_assign(new_current_count)?; + } + + Ok::<(), DispatchError>(()) } InboundEntry::Message { .. } => { Err(Error::::ExpectedMessageProofType.into()) } }, }, - }, - ) + } + }) } /// Creates, validates and upserts the inbound entry. @@ -195,21 +217,11 @@ impl Pallet { router_id: T::RouterId, weight: &mut Weight, ) -> DispatchResult { - let inbound_entry = Self::create_inbound_entry( - inbound_processing_info.domain_address.clone(), - message, - inbound_processing_info.expected_proof_count_per_message, - ); + let inbound_entry = Self::create_inbound_entry(inbound_processing_info, message); Self::validate_inbound_entry(&inbound_processing_info, &router_id, &inbound_entry)?; - Self::upsert_pending_entry( - inbound_processing_info.current_session_id, - message_proof, - router_id, - inbound_entry, - weight, - )?; + Self::upsert_pending_entry(message_proof, router_id, inbound_entry, weight)?; Ok(()) } @@ -228,19 +240,24 @@ impl Pallet { for router_id in &inbound_processing_info.router_ids { weight.saturating_accrue(T::DbWeight::get().reads(1)); - match PendingInboundEntries::::get( - inbound_processing_info.current_session_id, - (message_proof, router_id), - ) { + match PendingInboundEntries::::get(message_proof, router_id) { // We expected one InboundEntry for each router, if that's not the case, // we can return. None => return Ok(()), - Some(inbound_entry) => match inbound_entry { + Some(stored_inbound_entry) => match stored_inbound_entry { InboundEntry::Message { message: stored_message, .. } => message = Some(stored_message), - InboundEntry::Proof { current_count } => { + InboundEntry::Proof { + session_id, + current_count, + } => { + if session_id != inbound_processing_info.current_session_id { + // Don't count vote from invalid sessions. + continue; + } + if current_count > 0 { votes += 1; } @@ -281,39 +298,59 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().writes(1)); match PendingInboundEntries::::try_mutate( - inbound_processing_info.current_session_id, - (message_proof, router_id), + message_proof, + router_id, |storage_entry| match storage_entry { None => Err(Error::::PendingInboundEntryNotFound.into()), - Some(stored_inbound_entry) => match stored_inbound_entry { - InboundEntry::Message { - expected_proof_count, - .. - } => { - let updated_count = (*expected_proof_count).ensure_sub( - inbound_processing_info.expected_proof_count_per_message, - )?; - - if updated_count == 0 { - *storage_entry = None; - } else { - *expected_proof_count = updated_count; + Some(stored_inbound_entry) => { + match stored_inbound_entry { + InboundEntry::Message { + session_id, + expected_proof_count, + .. + } => { + if *session_id != inbound_processing_info.current_session_id { + // Remove the storage entry completely. + *storage_entry = None; + + return Ok::<(), DispatchError>(()); + } + + let updated_count = (*expected_proof_count).ensure_sub( + inbound_processing_info.expected_proof_count_per_message, + )?; + + if updated_count == 0 { + *storage_entry = None; + } else { + *expected_proof_count = updated_count; + } + + Ok::<(), DispatchError>(()) } - - Ok::<(), DispatchError>(()) - } - InboundEntry::Proof { current_count } => { - let updated_count = (*current_count).ensure_sub(1)?; - - if updated_count == 0 { - *storage_entry = None; - } else { - *current_count = updated_count; + InboundEntry::Proof { + session_id, + current_count, + } => { + if *session_id != inbound_processing_info.current_session_id { + // Remove the storage entry completely. + *storage_entry = None; + + return Ok::<(), DispatchError>(()); + } + + let updated_count = (*current_count).ensure_sub(1)?; + + if updated_count == 0 { + *storage_entry = None; + } else { + *current_count = updated_count; + } + + Ok::<(), DispatchError>(()) } - - Ok::<(), DispatchError>(()) } - }, + } }, ) { Ok(()) => {} @@ -334,7 +371,7 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().reads(1)); - let current_session_id = SessionIdStore::::get().ok_or(Error::::SessionIdNotFound)?; + let current_session_id = SessionIdStore::::get(); weight.saturating_accrue(T::DbWeight::get().reads(1)); @@ -373,7 +410,9 @@ impl Pallet { let mut count = 0; for submessage in message.submessages() { - count += 1; + if let Err(e) = count.ensure_add_assign(1) { + return (Err(e.into()), weight); + } let message_proof = Self::get_message_proof(message.clone()); @@ -447,52 +486,4 @@ impl Pallet { Ok(()) } - - /// Clears `PendingInboundEntries` mapped to invalid session IDs as long as - /// there is enough weight available for this operation. - /// - /// The invalid session IDs are removed from storage if all entries mapped - /// to them were cleared. - pub(crate) fn clear_invalid_session_ids(max_weight: Weight) -> Weight { - let invalid_session_ids = InvalidMessageSessions::::iter_keys().collect::>(); - - let mut weight = T::DbWeight::get().reads(1); - - for invalid_session_id in invalid_session_ids { - let mut cursor: Option> = None; - - loop { - let res = PendingInboundEntries::::clear_prefix( - invalid_session_id, - INVALID_ID_REMOVAL_LIMIT, - cursor.as_ref().map(|x| x.as_ref()), - ); - - weight.saturating_accrue( - T::DbWeight::get().reads_writes(res.loops.into(), res.unique.into()), - ); - - if weight.all_gte(max_weight) { - return weight; - } - - cursor = match res.maybe_cursor { - None => { - InvalidMessageSessions::::remove(invalid_session_id); - - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - if weight.all_gte(max_weight) { - return weight; - } - - break; - } - Some(c) => Some(c), - }; - } - } - - weight - } } diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index a94bf1bc1c..0187e6d8a4 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -15,6 +15,7 @@ use sp_runtime::{traits::IdentityLookup, DispatchError, DispatchResult}; use crate::{pallet as pallet_liquidity_pools_gateway, EnsureLocal, GatewayMessage}; +pub const TEST_SESSION_ID: u32 = 1; pub const TEST_EVM_CHAIN: EVMChainId = 1; pub const TEST_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(TEST_EVM_CHAIN, [1; 20]); diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 5904f6c082..89bad351cc 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -62,12 +62,8 @@ mod set_routers { router_ids.clone(), )); - assert_eq!(Routers::::get(), Some(router_ids.clone())); - assert_eq!(SessionIdStore::::get(), Some(session_id)); - assert_eq!( - InvalidMessageSessions::::get(session_id - 1), - Some(()) - ); + assert_eq!(Routers::::get(), router_ids.clone()); + assert_eq!(SessionIdStore::::get(), session_id); event_exists(Event::::RoutersSet { router_ids, @@ -83,12 +79,8 @@ mod set_routers { router_ids.clone(), )); - assert_eq!(Routers::::get(), Some(router_ids.clone())); - assert_eq!(SessionIdStore::::get(), Some(session_id)); - assert_eq!( - InvalidMessageSessions::::get(session_id - 1), - Some(()) - ); + assert_eq!(Routers::::get(), router_ids.clone()); + assert_eq!(SessionIdStore::::get(), session_id); event_exists(Event::::RoutersSet { router_ids, @@ -108,21 +100,33 @@ mod set_routers { BadOrigin ); - assert!(Routers::::get().is_none()); - assert!(SessionIdStore::::get().is_none()); - assert!(InvalidMessageSessions::::get(0).is_none()); + assert!(Routers::::get().is_empty()); + assert_eq!(SessionIdStore::::get(), 0); + }); + } + + #[test] + fn invalid_routers() { + new_test_ext().execute_with(|| { + assert_noop!( + LiquidityPoolsGateway::set_routers( + RuntimeOrigin::root(), + BoundedVec::try_from(vec![]).unwrap(), + ), + Error::::InvalidRouters + ); }); } #[test] fn session_id_overflow() { new_test_ext().execute_with(|| { - SessionIdStore::::set(Some(u32::MAX)); + SessionIdStore::::set(u32::MAX); assert_noop!( LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - BoundedVec::try_from(vec![]).unwrap(), + BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap(), ), Arithmetic(Overflow) ); @@ -482,7 +486,7 @@ mod outbound_message_handler_impl { assert_noop!( LiquidityPoolsGateway::handle(sender, domain, msg), - Error::::RoutersNotFound + Error::::NotEnoughRoutersForDomain ); }); } @@ -585,13 +589,13 @@ mod message_processor_impl { println!("Executing test for - {:?}", test.router_messages); new_test_ext().execute_with(|| { - let session_id = 1; + let session_id = TEST_SESSION_ID; Routers::::set( - Some(BoundedVec::try_from(test_routers.clone()).unwrap()), + BoundedVec::try_from(test_routers.clone()).unwrap(), ); SessionIdStore::::set( - Some(session_id), + session_id, ); let handler = MockLiquidityPools::mock_handle(move |_, _| Ok(())); @@ -620,12 +624,11 @@ mod message_processor_impl { for expected_storage_entry in test.expected_test_result.expected_storage_entries { - let expected_storage_entry_router_hash = expected_storage_entry.0; + let expected_storage_entry_router_id = expected_storage_entry.0; let expected_inbound_entry = expected_storage_entry.1; let storage_entry = PendingInboundEntries::::get( - session_id, - (MESSAGE_PROOF, expected_storage_entry_router_hash), + MESSAGE_PROOF, expected_storage_entry_router_id, ); assert_eq!(storage_entry, expected_inbound_entry, "Expected inbound entry {expected_inbound_entry:?}, found {storage_entry:?}"); } @@ -741,10 +744,10 @@ mod message_processor_impl { router_id: router_id.clone(), }; - Routers::::set(Some( + Routers::::set( BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), - )); - SessionIdStore::::set(Some(session_id)); + ); + SessionIdStore::::set(session_id); let handler = MockLiquidityPools::mock_handle( move |mock_domain_address, mock_message| { @@ -759,11 +762,9 @@ mod message_processor_impl { assert_ok!(res); assert_eq!(handler.times(), 1); - assert!(PendingInboundEntries::::get( - session_id, - (message_proof, router_id) - ) - .is_none()); + assert!( + PendingInboundEntries::::get(message_proof, router_id).is_none() + ); }); } @@ -780,28 +781,7 @@ mod message_processor_impl { }; let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::RoutersNotFound); - }); - } - - #[test] - fn inbound_domain_session_not_found() { - new_test_ext().execute_with(|| { - let message = Message::Simple; - let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_id = ROUTER_ID_1; - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_id: router_id.clone(), - }; - - Routers::::set(Some( - BoundedVec::<_, _>::try_from(vec![router_id]).unwrap(), - )); - - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::SessionIdNotFound); + assert_noop!(res, Error::::NotEnoughRoutersForDomain); }); } @@ -820,10 +800,10 @@ mod message_processor_impl { router_id: ROUTER_ID_2, }; - Routers::::set(Some( + Routers::::set( BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), - )); - SessionIdStore::::set(Some(session_id)); + ); + SessionIdStore::::set(session_id); let (res, _) = LiquidityPoolsGateway::process(gateway_message); assert_noop!(res, Error::::UnknownRouter); @@ -844,14 +824,17 @@ mod message_processor_impl { router_id: router_id.clone(), }; - Routers::::set(Some( + Routers::::set( BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), - )); - SessionIdStore::::set(Some(session_id)); + ); + SessionIdStore::::set(session_id); PendingInboundEntries::::insert( - session_id, - (message_proof, router_id), - InboundEntry::::Proof { current_count: 0 }, + message_proof, + router_id, + InboundEntry::::Proof { + session_id, + current_count: 0, + }, ); let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -893,6 +876,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -914,6 +898,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -980,6 +965,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 3, @@ -1002,6 +988,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 3, }), ), @@ -1020,6 +1007,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, @@ -1041,6 +1029,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, @@ -1063,6 +1052,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1081,6 +1071,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, @@ -1103,6 +1094,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1122,6 +1114,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1163,6 +1156,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -1186,6 +1180,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 4, }), ), @@ -1205,6 +1200,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1227,6 +1223,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1249,6 +1246,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1271,6 +1269,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1384,6 +1383,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1404,6 +1404,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1424,6 +1425,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1444,6 +1446,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1472,10 +1475,10 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - Routers::::set(Some( + Routers::::set( BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - )); - SessionIdStore::::set(Some(session_id)); + ); + SessionIdStore::::set(session_id); let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, @@ -1493,10 +1496,10 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let session_id = 1; - Routers::::set(Some( + Routers::::set( BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - )); - SessionIdStore::::set(Some(session_id)); + ); + SessionIdStore::::set(session_id); let gateway_message = GatewayMessage::Inbound { domain_address: TEST_DOMAIN_ADDRESS, @@ -1542,6 +1545,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -1564,6 +1568,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1584,6 +1589,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1602,12 +1608,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1626,12 +1634,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1649,6 +1659,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1657,6 +1668,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1675,6 +1687,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1684,6 +1697,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1701,6 +1715,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1710,6 +1725,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1727,6 +1743,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1735,6 +1752,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1753,6 +1771,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1762,6 +1781,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1802,6 +1822,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 6, @@ -1825,6 +1846,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 3, }), ), @@ -1846,6 +1868,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 3, }), ), @@ -1864,6 +1887,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -1872,6 +1896,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1891,6 +1916,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -1899,6 +1925,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -1918,6 +1945,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1926,6 +1954,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1945,6 +1974,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1954,6 +1984,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1972,6 +2003,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -1981,6 +2013,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -1999,6 +2032,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -2008,6 +2042,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -2026,6 +2061,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -2034,6 +2070,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -2053,6 +2090,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -2061,6 +2099,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -2080,6 +2119,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -2089,6 +2129,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -2107,6 +2148,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -2115,6 +2157,7 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -2134,6 +2177,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -2143,6 +2187,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -2161,6 +2206,7 @@ mod message_processor_impl { ( ROUTER_ID_1, Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, @@ -2170,6 +2216,7 @@ mod message_processor_impl { ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -2279,12 +2326,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -2304,12 +2353,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -2329,12 +2380,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -2354,12 +2407,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -2379,12 +2434,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), @@ -2404,12 +2461,14 @@ mod message_processor_impl { ( ROUTER_ID_2, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 1, }), ), ( ROUTER_ID_3, Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, current_count: 2, }), ), @@ -2435,10 +2494,8 @@ mod message_processor_impl { new_test_ext().execute_with(|| { let domain_address = DomainAddress::EVM(1, [1; 20]); - Routers::::set(Some( - BoundedVec::try_from(vec![ROUTER_ID_1.clone()]).unwrap(), - )); - SessionIdStore::::set(Some(1)); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1.clone()]).unwrap()); + SessionIdStore::::set(1); let message = Message::Simple; let gateway_message = GatewayMessage::Inbound { @@ -2558,7 +2615,7 @@ mod batches { // Ok Batched assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - Routers::::set(Some(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap())); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); // Not batched, it belongs to OTHER assert_ok!(LiquidityPoolsGateway::handle( @@ -2611,7 +2668,7 @@ mod batches { let router_id_1 = ROUTER_ID_1; - Routers::::set(Some(BoundedVec::try_from(vec![router_id_1]).unwrap())); + Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); assert_ok!(LiquidityPoolsGateway::end_batch_message( RuntimeOrigin::signed(USER), @@ -2654,8 +2711,8 @@ mod batches { let router_id_1 = ROUTER_ID_1; - Routers::::set(Some(BoundedVec::try_from(vec![router_id_1]).unwrap())); - SessionIdStore::::set(Some(1)); + Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); + SessionIdStore::::set(1); let handler = MockLiquidityPools::mock_handle(|_, _| Ok(())); @@ -2708,8 +2765,8 @@ mod batches { let router_id_1 = ROUTER_ID_1; - Routers::::set(Some(BoundedVec::try_from(vec![router_id_1]).unwrap())); - SessionIdStore::::set(Some(1)); + Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); + SessionIdStore::::set(1); let counter = Arc::new(AtomicU32::new(0)); @@ -2741,15 +2798,14 @@ mod execute_message_recovery { new_test_ext().execute_with(|| { let session_id = 1; - Routers::::set(Some( - BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - )); - SessionIdStore::::set(Some(session_id)); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap()); + SessionIdStore::::set(session_id); PendingInboundEntries::::insert( - session_id, - (MESSAGE_PROOF, ROUTER_ID_1), + MESSAGE_PROOF, + ROUTER_ID_1, InboundEntry::::Message { + session_id, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, @@ -2778,17 +2834,8 @@ mod execute_message_recovery { assert_eq!(handler.times(), 1); - assert!(PendingInboundEntries::::get( - session_id, - (MESSAGE_PROOF, ROUTER_ID_1) - ) - .is_none()); - - assert!(PendingInboundEntries::::get( - session_id, - (MESSAGE_PROOF, ROUTER_ID_2) - ) - .is_none()); + assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none()); + assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2).is_none()); }); } @@ -2797,15 +2844,16 @@ mod execute_message_recovery { new_test_ext().execute_with(|| { let session_id = 1; - Routers::::set(Some( + Routers::::set( BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), - )); - SessionIdStore::::set(Some(session_id)); + ); + SessionIdStore::::set(session_id); PendingInboundEntries::::insert( - session_id, - (MESSAGE_PROOF, ROUTER_ID_1), + MESSAGE_PROOF, + ROUTER_ID_1, InboundEntry::::Message { + session_id, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, @@ -2825,26 +2873,27 @@ mod execute_message_recovery { }); assert_eq!( - PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, ROUTER_ID_1)), + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1), Some(InboundEntry::::Message { + session_id, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, }) ); assert_eq!( - PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, ROUTER_ID_2)), - Some(InboundEntry::::Proof { current_count: 1 }) + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2), + Some(InboundEntry::::Proof { + session_id, + current_count: 1 + }) ); - assert!( - PendingInboundEntries::::get(session_id, (MESSAGE_PROOF, ROUTER_ID_3)) - .is_none() - ) + assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_3).is_none()) }); } #[test] - fn routers_not_found() { + fn not_enough_routers_for_domain() { new_test_ext().execute_with(|| { assert_noop!( LiquidityPoolsGateway::execute_message_recovery( @@ -2853,15 +2902,10 @@ mod execute_message_recovery { MESSAGE_PROOF, ROUTER_ID_1, ), - Error::::RoutersNotFound + Error::::NotEnoughRoutersForDomain ); - }); - } - #[test] - fn session_id_not_found() { - new_test_ext().execute_with(|| { - Routers::::set(Some(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap())); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); assert_noop!( LiquidityPoolsGateway::execute_message_recovery( @@ -2870,7 +2914,7 @@ mod execute_message_recovery { MESSAGE_PROOF, ROUTER_ID_1, ), - Error::::SessionIdNotFound + Error::::NotEnoughRoutersForDomain ); }); } @@ -2878,8 +2922,8 @@ mod execute_message_recovery { #[test] fn unknown_router() { new_test_ext().execute_with(|| { - Routers::::set(Some(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap())); - SessionIdStore::::set(Some(1)); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); + SessionIdStore::::set(1); assert_noop!( LiquidityPoolsGateway::execute_message_recovery( @@ -2896,15 +2940,15 @@ mod execute_message_recovery { #[test] fn proof_count_overflow() { new_test_ext().execute_with(|| { - let router_id = ROUTER_ID_1; let session_id = 1; - Routers::::set(Some(BoundedVec::try_from(vec![router_id.clone()]).unwrap())); - SessionIdStore::::set(Some(session_id)); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap()); + SessionIdStore::::set(session_id); PendingInboundEntries::::insert( - session_id, - (MESSAGE_PROOF, router_id.clone()), + MESSAGE_PROOF, + ROUTER_ID_2, InboundEntry::::Proof { + session_id, current_count: u32::MAX, }, ); @@ -2914,7 +2958,7 @@ mod execute_message_recovery { RuntimeOrigin::root(), TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, - router_id + ROUTER_ID_2 ), Arithmetic(Overflow) ); @@ -2925,15 +2969,15 @@ mod execute_message_recovery { fn expected_message_proof_type() { new_test_ext().execute_with(|| { let domain_address = TEST_DOMAIN_ADDRESS; - let router_id = ROUTER_ID_1; let session_id = 1; - Routers::::set(Some(BoundedVec::try_from(vec![router_id.clone()]).unwrap())); - SessionIdStore::::set(Some(session_id)); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap()); + SessionIdStore::::set(session_id); PendingInboundEntries::::insert( - session_id, - (MESSAGE_PROOF, router_id.clone()), + MESSAGE_PROOF, + ROUTER_ID_2, InboundEntry::::Message { + session_id, domain_address: domain_address.clone(), message: Message::Simple, expected_proof_count: 2, @@ -2945,7 +2989,7 @@ mod execute_message_recovery { RuntimeOrigin::root(), TEST_DOMAIN_ADDRESS, MESSAGE_PROOF, - router_id + ROUTER_ID_2 ), Error::::ExpectedMessageProofType ); From 877dc513031a4564835d0191495484466ffd5dc6 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:15:11 +0300 Subject: [PATCH 22/38] lp-gateway: Add more unit tests --- pallets/liquidity-pools-gateway/src/lib.rs | 21 +- .../src/message_processing.rs | 81 +- pallets/liquidity-pools-gateway/src/tests.rs | 5218 ++++++++++------- 3 files changed, 2972 insertions(+), 2348 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 124fc04aa0..bc73473195 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -61,8 +61,6 @@ mod tests; #[frame_support::pallet] pub mod pallet { - use frame_support::dispatch::PostDispatchInfo; - use super::*; const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -272,7 +270,8 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Sets the router IDs used for a specific domain, + /// Sets the IDs of the routers that are used when receiving and sending + /// messages. #[pallet::weight(T::WeightInfo::set_routers())] #[pallet::call_index(0)] pub fn set_routers( @@ -424,13 +423,10 @@ pub mod pallet { domain_address: DomainAddress, proof: Proof, router_id: T::RouterId, - ) -> DispatchResultWithPostInfo { + ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - let mut weight = Weight::default(); - - let inbound_processing_info = - Self::get_inbound_processing_info(domain_address, &mut weight)?; + let inbound_processing_info = Self::get_inbound_processing_info(domain_address)?; ensure!( inbound_processing_info @@ -445,8 +441,6 @@ pub mod pallet { Error::::NotEnoughRoutersForDomain ); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - PendingInboundEntries::::try_mutate(proof, router_id.clone(), |storage_entry| { match storage_entry { Some(stored_inbound_entry) => match stored_inbound_entry { @@ -478,14 +472,11 @@ pub mod pallet { } })?; - Self::execute_if_requirements_are_met(&inbound_processing_info, proof, &mut weight)?; + Self::execute_if_requirements_are_met(&inbound_processing_info, proof)?; Self::deposit_event(Event::::MessageRecoveryExecuted { proof, router_id }); - Ok(PostDispatchInfo { - actual_weight: Some(weight), - pays_fee: Pays::Yes, - }) + Ok(()) } } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 045714316c..3e527b6146 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -43,16 +43,22 @@ pub struct InboundProcessingInfo { } impl Pallet { - /// Retrieves all available routers for a domain and then filters them based - /// on the routers that we have in storage. - pub fn get_router_ids_for_domain(domain: Domain) -> Result, DispatchError> { - let all_routers_for_domain = T::RouterProvider::routers_for_domain(domain); - + /// Retrieves all stored routers and then filters them based + /// on the available routers for the provided domain. + pub(crate) fn get_router_ids_for_domain( + domain: Domain, + ) -> Result, DispatchError> { let stored_routers = Routers::::get(); - let res = all_routers_for_domain + let all_routers_for_domain = T::RouterProvider::routers_for_domain(domain); + + let res = stored_routers .iter() - .filter(|x| stored_routers.iter().any(|y| *x == y)) + .filter(|stored_router| { + all_routers_for_domain + .iter() + .any(|available_router| *stored_router == available_router) + }) .map(|x| x.clone()) .collect::>(); @@ -65,7 +71,9 @@ impl Pallet { /// Calculates and returns the proof count required for processing one /// inbound message. - fn get_expected_proof_count(router_ids: &Vec) -> Result { + pub(crate) fn get_expected_proof_count( + router_ids: &Vec, + ) -> Result { let expected_proof_count = router_ids .len() .ensure_sub(1) @@ -75,7 +83,7 @@ impl Pallet { } /// Gets the message proof for a message. - fn get_message_proof(message: T::Message) -> Proof { + pub(crate) fn get_message_proof(message: T::Message) -> Proof { match message.get_message_proof() { None => message .to_message_proof() @@ -87,7 +95,7 @@ impl Pallet { /// Creates an inbound entry based on whether the inbound message is a /// proof or not. - fn create_inbound_entry( + pub(crate) fn create_inbound_entry( inbound_processing_info: &InboundProcessingInfo, message: T::Message, ) -> InboundEntry { @@ -111,7 +119,7 @@ impl Pallet { /// specific domain. /// - messages are only sent by the first inbound router. /// - proofs are not sent by the first inbound router. - fn validate_inbound_entry( + pub(crate) fn validate_inbound_entry( inbound_processing_info: &InboundProcessingInfo, router_id: &T::RouterId, inbound_entry: &InboundEntry, @@ -145,14 +153,11 @@ impl Pallet { /// Upserts an inbound entry for a particular message, increasing the /// relevant counts accordingly. - fn upsert_pending_entry( + pub(crate) fn upsert_pending_entry( message_proof: Proof, router_id: T::RouterId, inbound_entry: InboundEntry, - weight: &mut Weight, ) -> DispatchResult { - weight.saturating_accrue(T::DbWeight::get().writes(1)); - PendingInboundEntries::::try_mutate(message_proof, router_id, |storage_entry| { match storage_entry { None => { @@ -215,13 +220,12 @@ impl Pallet { message: T::Message, message_proof: Proof, router_id: T::RouterId, - weight: &mut Weight, ) -> DispatchResult { let inbound_entry = Self::create_inbound_entry(inbound_processing_info, message); Self::validate_inbound_entry(&inbound_processing_info, &router_id, &inbound_entry)?; - Self::upsert_pending_entry(message_proof, router_id, inbound_entry, weight)?; + Self::upsert_pending_entry(message_proof, router_id, inbound_entry)?; Ok(()) } @@ -232,14 +236,11 @@ impl Pallet { pub(crate) fn execute_if_requirements_are_met( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, - weight: &mut Weight, ) -> DispatchResult { let mut message = None; let mut votes = 0; for router_id in &inbound_processing_info.router_ids { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - match PendingInboundEntries::::get(message_proof, router_id) { // We expected one InboundEntry for each router, if that's not the case, // we can return. @@ -259,7 +260,7 @@ impl Pallet { } if current_count > 0 { - votes += 1; + votes.ensure_add_assign(1)?; } } }, @@ -272,11 +273,7 @@ impl Pallet { match message { Some(msg) => { - Self::decrease_pending_entries_counts( - &inbound_processing_info, - message_proof, - weight, - )?; + Self::decrease_pending_entries_counts(&inbound_processing_info, message_proof)?; T::InboundMessageHandler::handle( inbound_processing_info.domain_address.clone(), @@ -289,14 +286,11 @@ impl Pallet { /// Decreases the counts for inbound entries and removes them if the /// counts reach 0. - fn decrease_pending_entries_counts( + pub(crate) fn decrease_pending_entries_counts( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, - weight: &mut Weight, ) -> DispatchResult { for router_id in &inbound_processing_info.router_ids { - weight.saturating_accrue(T::DbWeight::get().writes(1)); - match PendingInboundEntries::::try_mutate( message_proof, router_id, @@ -365,20 +359,13 @@ impl Pallet { /// message. pub(crate) fn get_inbound_processing_info( domain_address: DomainAddress, - weight: &mut Weight, ) -> Result, DispatchError> { let router_ids = Self::get_router_ids_for_domain(domain_address.domain())?; - weight.saturating_accrue(T::DbWeight::get().reads(1)); - let current_session_id = SessionIdStore::::get(); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - let expected_proof_count = Self::get_expected_proof_count(&router_ids)?; - weight.saturating_accrue(T::DbWeight::get().reads(1)); - Ok(InboundProcessingInfo { domain_address, router_ids, @@ -394,24 +381,19 @@ impl Pallet { message: T::Message, router_id: T::RouterId, ) -> (DispatchResult, Weight) { - let mut weight = Default::default(); + let weight = LP_DEFENSIVE_WEIGHT; let inbound_processing_info = - match Self::get_inbound_processing_info(domain_address.clone(), &mut weight) { + match Self::get_inbound_processing_info(domain_address.clone()) { Ok(i) => i, Err(e) => return (Err(e), weight), }; - weight.saturating_accrue( - Weight::from_parts(0, T::Message::max_encoded_len() as u64) - .saturating_add(LP_DEFENSIVE_WEIGHT), - ); - let mut count = 0; for submessage in message.submessages() { if let Err(e) = count.ensure_add_assign(1) { - return (Err(e.into()), weight); + return (Err(e.into()), weight.saturating_mul(count)); } let message_proof = Self::get_message_proof(message.clone()); @@ -421,16 +403,11 @@ impl Pallet { submessage.clone(), message_proof, router_id.clone(), - &mut weight, ) { - return (Err(e), weight); + return (Err(e), weight.saturating_mul(count)); } - match Self::execute_if_requirements_are_met( - &inbound_processing_info, - message_proof, - &mut weight, - ) { + match Self::execute_if_requirements_are_met(&inbound_processing_info, message_proof) { Err(e) => return (Err(e), weight.saturating_mul(count)), Ok(_) => continue, } diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 89bad351cc..31e16eeac9 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -3,10 +3,9 @@ use std::collections::HashMap; use cfg_primitives::LP_DEFENSIVE_WEIGHT; use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler}; use cfg_types::domain_address::*; -use frame_support::{assert_err, assert_noop, assert_ok, weights::Weight}; +use frame_support::{assert_err, assert_noop, assert_ok}; use itertools::Itertools; use lazy_static::lazy_static; -use parity_scale_codec::MaxEncodedLen; use sp_arithmetic::ArithmeticError::Overflow; use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160}; use sp_runtime::{ @@ -23,7 +22,10 @@ use super::{ origin::*, pallet::*, }; -use crate::{message_processing::InboundEntry, GatewayMessage}; +use crate::{ + message_processing::{InboundEntry, InboundProcessingInfo}, + GatewayMessage, +}; mod utils { use super::*; @@ -46,820 +48,2182 @@ mod utils { use utils::*; -mod set_routers { +mod extrinsics { use super::*; - #[test] - fn success() { - new_test_ext().execute_with(|| { - let mut session_id = 1; - - let mut router_ids = - BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(); - - assert_ok!(LiquidityPoolsGateway::set_routers( - RuntimeOrigin::root(), - router_ids.clone(), - )); - - assert_eq!(Routers::::get(), router_ids.clone()); - assert_eq!(SessionIdStore::::get(), session_id); + mod set_routers { + use super::*; - event_exists(Event::::RoutersSet { - router_ids, - session_id, - }); + #[test] + fn success() { + new_test_ext().execute_with(|| { + let mut session_id = 1; - router_ids = BoundedVec::try_from(vec![ROUTER_ID_3, ROUTER_ID_2, ROUTER_ID_1]).unwrap(); + let mut router_ids = + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(); - session_id += 1; + assert_ok!(LiquidityPoolsGateway::set_routers( + RuntimeOrigin::root(), + router_ids.clone(), + )); - assert_ok!(LiquidityPoolsGateway::set_routers( - RuntimeOrigin::root(), - router_ids.clone(), - )); + assert_eq!(Routers::::get(), router_ids.clone()); + assert_eq!(SessionIdStore::::get(), session_id); - assert_eq!(Routers::::get(), router_ids.clone()); - assert_eq!(SessionIdStore::::get(), session_id); + event_exists(Event::::RoutersSet { + router_ids, + session_id, + }); - event_exists(Event::::RoutersSet { - router_ids, - session_id, - }); - }); - } + router_ids = + BoundedVec::try_from(vec![ROUTER_ID_3, ROUTER_ID_2, ROUTER_ID_1]).unwrap(); - #[test] - fn bad_origin() { - new_test_ext().execute_with(|| { - assert_noop!( - LiquidityPoolsGateway::set_routers( - RuntimeOrigin::signed(get_test_account_id()), - BoundedVec::try_from(vec![]).unwrap(), - ), - BadOrigin - ); - - assert!(Routers::::get().is_empty()); - assert_eq!(SessionIdStore::::get(), 0); - }); - } + session_id += 1; - #[test] - fn invalid_routers() { - new_test_ext().execute_with(|| { - assert_noop!( - LiquidityPoolsGateway::set_routers( + assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), - BoundedVec::try_from(vec![]).unwrap(), - ), - Error::::InvalidRouters - ); - }); - } + router_ids.clone(), + )); - #[test] - fn session_id_overflow() { - new_test_ext().execute_with(|| { - SessionIdStore::::set(u32::MAX); + assert_eq!(Routers::::get(), router_ids.clone()); + assert_eq!(SessionIdStore::::get(), session_id); - assert_noop!( - LiquidityPoolsGateway::set_routers( - RuntimeOrigin::root(), - BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap(), - ), - Arithmetic(Overflow) - ); - }); - } -} - -mod add_instance { - use super::*; + event_exists(Event::::RoutersSet { + router_ids, + session_id, + }); + }); + } - #[test] - fn success() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); + #[test] + fn bad_origin() { + new_test_ext().execute_with(|| { + assert_noop!( + LiquidityPoolsGateway::set_routers( + RuntimeOrigin::signed(get_test_account_id()), + BoundedVec::try_from(vec![]).unwrap(), + ), + BadOrigin + ); - assert_ok!(LiquidityPoolsGateway::add_instance( - RuntimeOrigin::root(), - domain_address.clone(), - )); + assert!(Routers::::get().is_empty()); + assert_eq!(SessionIdStore::::get(), 0); + }); + } - assert!(Allowlist::::contains_key( - domain_address.domain(), - domain_address.clone() - )); + #[test] + fn invalid_routers() { + new_test_ext().execute_with(|| { + assert_noop!( + LiquidityPoolsGateway::set_routers( + RuntimeOrigin::root(), + BoundedVec::try_from(vec![]).unwrap(), + ), + Error::::InvalidRouters + ); + }); + } - event_exists(Event::::InstanceAdded { - instance: domain_address, + #[test] + fn session_id_overflow() { + new_test_ext().execute_with(|| { + SessionIdStore::::set(u32::MAX); + + assert_noop!( + LiquidityPoolsGateway::set_routers( + RuntimeOrigin::root(), + BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap(), + ), + Arithmetic(Overflow) + ); }); - }); + } } - #[test] - fn bad_origin() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); + mod add_instance { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); - assert_noop!( - LiquidityPoolsGateway::add_instance( - RuntimeOrigin::signed(get_test_account_id()), + assert_ok!(LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), domain_address.clone(), - ), - BadOrigin - ); - - assert!(!Allowlist::::contains_key( - domain_address.domain(), - domain_address.clone() - )); - }); - } + )); - #[test] - fn unsupported_domain() { - new_test_ext().execute_with(|| { - let domain_address = DomainAddress::Centrifuge(get_test_account_id().into()); - - assert_noop!( - LiquidityPoolsGateway::add_instance(RuntimeOrigin::root(), domain_address.clone()), - Error::::DomainNotSupported - ); - - assert!(!Allowlist::::contains_key( - domain_address.domain(), - domain_address.clone() - )); - }); - } + assert!(Allowlist::::contains_key( + domain_address.domain(), + domain_address.clone() + )); - #[test] - fn instance_already_added() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); - - assert_ok!(LiquidityPoolsGateway::add_instance( - RuntimeOrigin::root(), - domain_address.clone(), - )); - - assert!(Allowlist::::contains_key( - domain_address.domain(), - domain_address.clone() - )); - - assert_noop!( - LiquidityPoolsGateway::add_instance(RuntimeOrigin::root(), domain_address), - Error::::InstanceAlreadyAdded - ); - }); - } -} + event_exists(Event::::InstanceAdded { + instance: domain_address, + }); + }); + } -mod remove_instance { - use super::*; + #[test] + fn bad_origin() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); + + assert_noop!( + LiquidityPoolsGateway::add_instance( + RuntimeOrigin::signed(get_test_account_id()), + domain_address.clone(), + ), + BadOrigin + ); - #[test] - fn success() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); - - assert_ok!(LiquidityPoolsGateway::add_instance( - RuntimeOrigin::root(), - domain_address.clone(), - )); - - assert_ok!(LiquidityPoolsGateway::remove_instance( - RuntimeOrigin::root(), - domain_address.clone(), - )); - - assert!(!Allowlist::::contains_key( - domain_address.domain(), - domain_address.clone() - )); - - event_exists(Event::::InstanceRemoved { - instance: domain_address.clone(), + assert!(!Allowlist::::contains_key( + domain_address.domain(), + domain_address.clone() + )); }); - }); - } + } - #[test] - fn bad_origin() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); + #[test] + fn unsupported_domain() { + new_test_ext().execute_with(|| { + let domain_address = DomainAddress::Centrifuge(get_test_account_id().into()); + + assert_noop!( + LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), + domain_address.clone() + ), + Error::::DomainNotSupported + ); - assert_noop!( - LiquidityPoolsGateway::remove_instance( - RuntimeOrigin::signed(get_test_account_id()), - domain_address.clone(), - ), - BadOrigin - ); - }); - } + assert!(!Allowlist::::contains_key( + domain_address.domain(), + domain_address.clone() + )); + }); + } - #[test] - fn instance_not_found() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); + #[test] + fn instance_already_added() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); - assert_noop!( - LiquidityPoolsGateway::remove_instance( + assert_ok!(LiquidityPoolsGateway::add_instance( RuntimeOrigin::root(), domain_address.clone(), - ), - Error::::UnknownInstance, - ); - }); - } -} + )); -mod receive_message_domain { - use super::*; + assert!(Allowlist::::contains_key( + domain_address.domain(), + domain_address.clone() + )); + + assert_noop!( + LiquidityPoolsGateway::add_instance(RuntimeOrigin::root(), domain_address), + Error::::InstanceAlreadyAdded + ); + }); + } + } - #[test] - fn success() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); - let message = Message::Simple; + mod remove_instance { + use super::*; - let router_id = ROUTER_ID_1; + #[test] + fn success() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); - assert_ok!(LiquidityPoolsGateway::add_instance( - RuntimeOrigin::root(), - domain_address.clone(), - )); + assert_ok!(LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), + domain_address.clone(), + )); - let encoded_msg = message.serialize(); + assert_ok!(LiquidityPoolsGateway::remove_instance( + RuntimeOrigin::root(), + domain_address.clone(), + )); - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_id: router_id.clone(), - }; + assert!(!Allowlist::::contains_key( + domain_address.domain(), + domain_address.clone() + )); - let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { - assert_eq!(mock_message, gateway_message); - Ok(()) + event_exists(Event::::InstanceRemoved { + instance: domain_address.clone(), + }); }); + } - assert_ok!(LiquidityPoolsGateway::receive_message( - GatewayOrigin::Domain(domain_address).into(), - router_id, - BoundedVec::::try_from(encoded_msg).unwrap() - )); + #[test] + fn bad_origin() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); + + assert_noop!( + LiquidityPoolsGateway::remove_instance( + RuntimeOrigin::signed(get_test_account_id()), + domain_address.clone(), + ), + BadOrigin + ); + }); + } - assert_eq!(handler.times(), 1); - }); + #[test] + fn instance_not_found() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); + + assert_noop!( + LiquidityPoolsGateway::remove_instance( + RuntimeOrigin::root(), + domain_address.clone(), + ), + Error::::UnknownInstance, + ); + }); + } } - #[test] - fn bad_origin() { - new_test_ext().execute_with(|| { - let encoded_msg = Message::Simple.serialize(); + mod receive_message { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); + let message = Message::Simple; - let router_id = ROUTER_ID_1; + let router_id = ROUTER_ID_1; - assert_noop!( - LiquidityPoolsGateway::receive_message( - RuntimeOrigin::signed(AccountId32::new([0u8; 32])), - router_id, - BoundedVec::::try_from(encoded_msg).unwrap() - ), - BadOrigin, - ); - }); - } + assert_ok!(LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), + domain_address.clone(), + )); - #[test] - fn invalid_message_origin() { - new_test_ext().execute_with(|| { - let domain_address = DomainAddress::Centrifuge(get_test_account_id().into()); - let encoded_msg = Message::Simple.serialize(); - let router_id = ROUTER_ID_1; + let encoded_msg = message.serialize(); - assert_noop!( - LiquidityPoolsGateway::receive_message( - GatewayOrigin::Domain(domain_address).into(), - router_id, - BoundedVec::::try_from(encoded_msg).unwrap() - ), - Error::::InvalidMessageOrigin, - ); - }); - } + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_id: router_id.clone(), + }; - #[test] - fn unknown_instance() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); - let encoded_msg = Message::Simple.serialize(); - let router_id = ROUTER_ID_1; + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { + assert_eq!(mock_message, gateway_message); + Ok(()) + }); - assert_noop!( - LiquidityPoolsGateway::receive_message( + assert_ok!(LiquidityPoolsGateway::receive_message( GatewayOrigin::Domain(domain_address).into(), router_id, BoundedVec::::try_from(encoded_msg).unwrap() - ), - Error::::UnknownInstance, - ); - }); - } - - #[test] - fn message_queue_error() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(0, address.into()); - let message = Message::Simple; - - let router_id = ROUTER_ID_1; - - assert_ok!(LiquidityPoolsGateway::add_instance( - RuntimeOrigin::root(), - domain_address.clone(), - )); + )); - let encoded_msg = message.serialize(); + assert_eq!(handler.times(), 1); + }); + } - let err = sp_runtime::DispatchError::from("liquidity_pools error"); + #[test] + fn bad_origin() { + new_test_ext().execute_with(|| { + let encoded_msg = Message::Simple.serialize(); - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_id: router_id.clone(), - }; + let router_id = ROUTER_ID_1; - MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { - assert_eq!(mock_message, gateway_message); - Err(err) + assert_noop!( + LiquidityPoolsGateway::receive_message( + RuntimeOrigin::signed(AccountId32::new([0u8; 32])), + router_id, + BoundedVec::::try_from(encoded_msg).unwrap() + ), + BadOrigin, + ); }); + } - assert_noop!( - LiquidityPoolsGateway::receive_message( - GatewayOrigin::Domain(domain_address).into(), - router_id, - BoundedVec::::try_from(encoded_msg).unwrap() - ), - err, - ); - }); - } -} - -mod outbound_message_handler_impl { - use super::*; - - #[test] - fn success() { - new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let sender = get_test_account_id(); - let msg = Message::Simple; - let message_proof = msg.to_message_proof().get_message_proof().unwrap(); - - assert_ok!(LiquidityPoolsGateway::set_routers( - RuntimeOrigin::root(), - BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), - )); - - let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { - match mock_msg { - GatewayMessage::Inbound { .. } => { - assert!(false, "expected outbound message") - } - GatewayMessage::Outbound { - sender, message, .. - } => { - assert_eq!(sender, ::Sender::get()); - - match message { - Message::Proof(p) => { - assert_eq!(p, message_proof); - } - _ => {} - } - } - } + #[test] + fn invalid_message_origin() { + new_test_ext().execute_with(|| { + let domain_address = DomainAddress::Centrifuge(get_test_account_id().into()); + let encoded_msg = Message::Simple.serialize(); + let router_id = ROUTER_ID_1; - Ok(()) + assert_noop!( + LiquidityPoolsGateway::receive_message( + GatewayOrigin::Domain(domain_address).into(), + router_id, + BoundedVec::::try_from(encoded_msg).unwrap() + ), + Error::::InvalidMessageOrigin, + ); }); + } - assert_ok!(LiquidityPoolsGateway::handle(sender, domain, msg)); - assert_eq!(handler.times(), 3); - }); - } + #[test] + fn unknown_instance() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); + let encoded_msg = Message::Simple.serialize(); + let router_id = ROUTER_ID_1; + + assert_noop!( + LiquidityPoolsGateway::receive_message( + GatewayOrigin::Domain(domain_address).into(), + router_id, + BoundedVec::::try_from(encoded_msg).unwrap() + ), + Error::::UnknownInstance, + ); + }); + } - #[test] - fn domain_not_supported() { - new_test_ext().execute_with(|| { - let domain = Domain::Centrifuge; - let sender = get_test_account_id(); - let msg = Message::Simple; - - assert_noop!( - LiquidityPoolsGateway::handle(sender, domain, msg), - Error::::DomainNotSupported - ); - }); - } + #[test] + fn message_queue_error() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(0, address.into()); + let message = Message::Simple; - #[test] - fn routers_not_found() { - new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let sender = get_test_account_id(); - let msg = Message::Simple; - - assert_noop!( - LiquidityPoolsGateway::handle(sender, domain, msg), - Error::::NotEnoughRoutersForDomain - ); - }); - } + let router_id = ROUTER_ID_1; - #[test] - fn message_queue_error() { - new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - let sender = get_test_account_id(); - let msg = Message::Simple; + assert_ok!(LiquidityPoolsGateway::add_instance( + RuntimeOrigin::root(), + domain_address.clone(), + )); - assert_ok!(LiquidityPoolsGateway::set_routers( - RuntimeOrigin::root(), - BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), - )); + let encoded_msg = message.serialize(); - let gateway_message = GatewayMessage::Outbound { - sender: ::Sender::get(), - message: msg.clone(), - router_id: ROUTER_ID_1, - }; + let err = sp_runtime::DispatchError::from("liquidity_pools error"); - let err = DispatchError::Unavailable; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_id: router_id.clone(), + }; - let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { - assert_eq!(mock_msg, gateway_message); + MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_message| { + assert_eq!(mock_message, gateway_message); + Err(err) + }); - Err(err) + assert_noop!( + LiquidityPoolsGateway::receive_message( + GatewayOrigin::Domain(domain_address).into(), + router_id, + BoundedVec::::try_from(encoded_msg).unwrap() + ), + err, + ); }); - - assert_noop!(LiquidityPoolsGateway::handle(sender, domain, msg), err); - assert_eq!(handler.times(), 1); - }); + } } -} - -mod set_domain_hook { - use super::*; - #[test] - fn success() { - new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); - - assert_ok!(LiquidityPoolsGateway::set_domain_hook_address( - RuntimeOrigin::root(), - domain, - get_test_hook_bytes() - )); - }); - } + mod set_domain_hook { + use super::*; - #[test] - fn bad_origin() { - new_test_ext().execute_with(|| { - let domain = Domain::EVM(0); + #[test] + fn success() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); - assert_noop!( - LiquidityPoolsGateway::set_domain_hook_address( - RuntimeOrigin::signed(AccountId32::new([0u8; 32])), + assert_ok!(LiquidityPoolsGateway::set_domain_hook_address( + RuntimeOrigin::root(), domain, get_test_hook_bytes() - ), - BadOrigin - ); - }); - } + )); + }); + } - #[test] - fn domain_not_supported() { - new_test_ext().execute_with(|| { - let domain = Domain::Centrifuge; + #[test] + fn bad_origin() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + + assert_noop!( + LiquidityPoolsGateway::set_domain_hook_address( + RuntimeOrigin::signed(AccountId32::new([0u8; 32])), + domain, + get_test_hook_bytes() + ), + BadOrigin + ); + }); + } - assert_noop!( - LiquidityPoolsGateway::set_domain_hook_address( - RuntimeOrigin::root(), - domain, - get_test_hook_bytes() - ), - Error::::DomainNotSupported - ); - }); + #[test] + fn domain_not_supported() { + new_test_ext().execute_with(|| { + let domain = Domain::Centrifuge; + + assert_noop!( + LiquidityPoolsGateway::set_domain_hook_address( + RuntimeOrigin::root(), + domain, + get_test_hook_bytes() + ), + Error::::DomainNotSupported + ); + }); + } } -} -mod message_processor_impl { - use super::*; - - mod inbound { + mod batches { use super::*; - #[macro_use] - mod util { - use super::*; + const USER: AccountId32 = AccountId32::new([1; 32]); + const OTHER: AccountId32 = AccountId32::new([2; 32]); + const DOMAIN: Domain = Domain::EVM(TEST_EVM_CHAIN); - pub fn run_inbound_message_test_suite(suite: InboundMessageTestSuite) { - let test_routers = suite.routers; + #[test] + fn pack_empty() { + new_test_ext().execute_with(|| { + assert_ok!(LiquidityPoolsGateway::start_batch_message( + RuntimeOrigin::signed(USER), + DOMAIN + )); + assert_ok!(LiquidityPoolsGateway::end_batch_message( + RuntimeOrigin::signed(USER), + DOMAIN + )); + }); + } - for test in suite.tests { - println!("Executing test for - {:?}", test.router_messages); + #[test] + fn pack_several() { + new_test_ext().execute_with(|| { + assert_ok!(LiquidityPoolsGateway::start_batch_message( + RuntimeOrigin::signed(USER), + DOMAIN + )); - new_test_ext().execute_with(|| { - let session_id = TEST_SESSION_ID; + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); - Routers::::set( - BoundedVec::try_from(test_routers.clone()).unwrap(), - ); - SessionIdStore::::set( - session_id, - ); + // Ok Batched + assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - let handler = MockLiquidityPools::mock_handle(move |_, _| Ok(())); + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); - for router_message in test.router_messages { - let gateway_message = GatewayMessage::Inbound { - domain_address: TEST_DOMAIN_ADDRESS, - message: router_message.1, - router_id: router_message.0, - }; + // Not batched, it belongs to OTHER + assert_ok!(LiquidityPoolsGateway::handle( + OTHER, + DOMAIN, + Message::Simple + )); - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_ok!(res); - } + // Not batched, it belongs to EVM 2 + assert_ok!(LiquidityPoolsGateway::handle( + USER, + Domain::EVM(2), + Message::Simple + )); - let expected_message_submitted_times = - test.expected_test_result.message_submitted_times; - let message_submitted_times = handler.times(); + // Ok Batched + assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - assert_eq!( - message_submitted_times, - expected_message_submitted_times, - "Expected message to be submitted {expected_message_submitted_times} times, was {message_submitted_times}" - ); + // Two non-packed messages + assert_eq!(handler.times(), 2); - for expected_storage_entry in - test.expected_test_result.expected_storage_entries - { - let expected_storage_entry_router_id = expected_storage_entry.0; - let expected_inbound_entry = expected_storage_entry.1; + assert_ok!(LiquidityPoolsGateway::end_batch_message( + RuntimeOrigin::signed(USER), + DOMAIN + )); - let storage_entry = PendingInboundEntries::::get( - MESSAGE_PROOF, expected_storage_entry_router_id, - ); - assert_eq!(storage_entry, expected_inbound_entry, "Expected inbound entry {expected_inbound_entry:?}, found {storage_entry:?}"); - } - }); - } - } + // Packed message queued + assert_eq!(handler.times(), 3); + }); + } - /// Used for generating all `RouterMessage` combinations like: - /// - /// vec![ - /// (ROUTER_ID_1, Message::Simple), - /// (ROUTER_ID_1, Message::Simple), - /// ] - /// vec![ - /// (ROUTER_ID_1, Message::Simple), - /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - /// ] - /// vec![ - /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - /// (ROUTER_ID_1, Message::Simple), - /// ] - /// vec![ - /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - /// ] - pub fn generate_test_combinations( - t: T, - count: usize, - ) -> Vec::Item>> - where - T: IntoIterator + Clone, - T::IntoIter: Clone, - T::Item: Clone, - { - std::iter::repeat(t.clone().into_iter()) - .take(count) - .multi_cartesian_product() - .collect::>() - } + #[test] + fn pack_over_limit() { + new_test_ext().execute_with(|| { + assert_ok!(LiquidityPoolsGateway::start_batch_message( + RuntimeOrigin::signed(USER), + DOMAIN + )); - /// Type used for mapping a message to a router hash. - pub type RouterMessage = (RouterId, Message); + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); - /// Type used for aggregating tests for inbound messages. - pub struct InboundMessageTestSuite { - pub routers: Vec, - pub tests: Vec, - } + (0..MAX_PACKED_MESSAGES).for_each(|_| { + assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); + }); - /// Type used for defining a test which contains a set of - /// `RouterMessage` combinations and the expected test result. - pub struct InboundMessageTest { - pub router_messages: Vec, - pub expected_test_result: ExpectedTestResult, - } + assert_err!( + LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple), + DispatchError::Other(MAX_PACKED_MESSAGES_ERR) + ); - /// Type used for defining the number of expected inbound message - /// submission and the exected storage state. - #[derive(Clone, Debug)] - pub struct ExpectedTestResult { - pub message_submitted_times: u32, - pub expected_storage_entries: Vec<(RouterId, Option>)>, - } + let router_id_1 = ROUTER_ID_1; - /// Generates the combinations of `RouterMessage` used when testing, - /// maps the `ExpectedTestResult` for each and creates the - /// `InboundMessageTestSuite`. - pub fn generate_test_suite( - routers: Vec, - test_data: Vec, - expected_results: HashMap, ExpectedTestResult>, - message_count: usize, - ) -> InboundMessageTestSuite { - let tests = generate_test_combinations(test_data, message_count); - - let tests = tests - .into_iter() - .map(|router_messages| { - let expected_test_result = expected_results - .get(&router_messages) - .expect( - format!("test for {router_messages:?} should be covered").as_str(), - ) - .clone(); - - InboundMessageTest { - router_messages, - expected_test_result, - } - }) - .collect::>(); + Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); - InboundMessageTestSuite { routers, tests } - } + assert_ok!(LiquidityPoolsGateway::end_batch_message( + RuntimeOrigin::signed(USER), + DOMAIN + )); + assert_eq!(handler.times(), 1); + }); } - use util::*; + #[test] + fn end_before_start() { + new_test_ext().execute_with(|| { + assert_err!( + LiquidityPoolsGateway::end_batch_message(RuntimeOrigin::signed(USER), DOMAIN), + Error::::MessagePackingNotStarted + ); + }); + } - mod one_router { - use super::*; + #[test] + fn start_before_end() { + new_test_ext().execute_with(|| { + assert_ok!(LiquidityPoolsGateway::start_batch_message( + RuntimeOrigin::signed(USER), + DOMAIN + )); + + assert_err!( + LiquidityPoolsGateway::start_batch_message(RuntimeOrigin::signed(USER), DOMAIN), + Error::::MessagePackingAlreadyStarted + ); + }); + } - #[test] - fn success() { - new_test_ext().execute_with(|| { - let message = Message::Simple; - let message_proof = message.to_message_proof().get_message_proof().unwrap(); - let session_id = 1; - let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_id = ROUTER_ID_1; - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_id: router_id.clone(), - }; + #[test] + fn process_inbound() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(TEST_EVM_CHAIN, address.into()); - Routers::::set( - BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), - ); - SessionIdStore::::set(session_id); + let router_id_1 = ROUTER_ID_1; - let handler = MockLiquidityPools::mock_handle( - move |mock_domain_address, mock_message| { - assert_eq!(mock_domain_address, domain_address); - assert_eq!(mock_message, message); + Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); + SessionIdStore::::set(1); - Ok(()) - }, - ); + let handler = MockLiquidityPools::mock_handle(|_, _| Ok(())); - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_ok!(res); - assert_eq!(handler.times(), 1); + let submessage_count = 5; - assert!( - PendingInboundEntries::::get(message_proof, router_id).is_none() - ); + let (result, weight) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { + domain_address, + message: Message::deserialize(&(1..=submessage_count).collect::>()) + .unwrap(), + router_id: ROUTER_ID_1, }); - } - #[test] - fn multi_router_not_found() { - new_test_ext().execute_with(|| { - let message = Message::Simple; - let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_hash = ROUTER_ID_1; - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_id: router_hash, - }; + let expected_weight = LP_DEFENSIVE_WEIGHT.saturating_mul(submessage_count.into()); - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::NotEnoughRoutersForDomain); + assert_ok!(result); + assert_eq!(weight, expected_weight); + assert_eq!(handler.times(), submessage_count as u32); + }); + } + + #[test] + fn process_inbound_with_errors() { + new_test_ext().execute_with(|| { + let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); + let domain_address = DomainAddress::EVM(1, address.into()); + + let router_id_1 = ROUTER_ID_1; + + Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); + SessionIdStore::::set(1); + + let counter = Arc::new(AtomicU32::new(0)); + + let handler = MockLiquidityPools::mock_handle(move |_, _| { + match counter.fetch_add(1, Ordering::Relaxed) { + 2 => Err(DispatchError::Unavailable), + _ => Ok(()), + } }); - } - #[test] - fn unknown_inbound_message_router() { - new_test_ext().execute_with(|| { - let message = Message::Simple; - let session_id = 1; - let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_hash = ROUTER_ID_1; - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - // The router stored has a different hash, this should trigger the expected - // error. - router_id: ROUTER_ID_2, - }; + let (result, _) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { + domain_address, + message: Message::deserialize(&(1..=5).collect::>()).unwrap(), + router_id: ROUTER_ID_1, + }); - Routers::::set( - BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), - ); - SessionIdStore::::set(session_id); + assert_err!(result, DispatchError::Unavailable); + // 2 correct messages and 1 failed message processed. + assert_eq!(handler.times(), 3); + }); + } + } - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::UnknownRouter); + mod execute_message_recovery { + use super::*; + + #[test] + fn success_with_execution() { + new_test_ext().execute_with(|| { + let session_id = 1; + + Routers::::set( + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), + ); + SessionIdStore::::set(session_id); + + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + InboundEntry::::Message { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }, + ); + + let handler = + MockLiquidityPools::mock_handle(move |mock_domain_address, mock_message| { + assert_eq!(mock_domain_address, TEST_DOMAIN_ADDRESS); + assert_eq!(mock_message, Message::Simple); + + Ok(()) + }); + + assert_ok!(LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, + MESSAGE_PROOF, + ROUTER_ID_2, + )); + + event_exists(Event::::MessageRecoveryExecuted { + proof: MESSAGE_PROOF, + router_id: ROUTER_ID_2, }); - } - #[test] - fn expected_message_proof_type() { - new_test_ext().execute_with(|| { - let message = Message::Simple; - let message_proof = message.to_message_proof().get_message_proof().unwrap(); - let session_id = 1; - let domain_address = DomainAddress::EVM(1, [1; 20]); - let router_id = ROUTER_ID_1; - let gateway_message = GatewayMessage::Inbound { + assert_eq!(handler.times(), 1); + + assert!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none() + ); + assert!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2).is_none() + ); + }); + } + + #[test] + fn success_without_execution() { + new_test_ext().execute_with(|| { + let session_id = 1; + + Routers::::set( + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), + ); + SessionIdStore::::set(session_id); + + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + InboundEntry::::Message { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }, + ); + + assert_ok!(LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, + MESSAGE_PROOF, + ROUTER_ID_2, + )); + + event_exists(Event::::MessageRecoveryExecuted { + proof: MESSAGE_PROOF, + router_id: ROUTER_ID_2, + }); + + assert_eq!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1), + Some(InboundEntry::::Message { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }) + ); + assert_eq!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2), + Some(InboundEntry::::Proof { + session_id, + current_count: 1 + }) + ); + assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_3).is_none()) + }); + } + + #[test] + fn not_enough_routers_for_domain() { + new_test_ext().execute_with(|| { + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, + MESSAGE_PROOF, + ROUTER_ID_1, + ), + Error::::NotEnoughRoutersForDomain + ); + + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, + MESSAGE_PROOF, + ROUTER_ID_1, + ), + Error::::NotEnoughRoutersForDomain + ); + }); + } + + #[test] + fn unknown_router() { + new_test_ext().execute_with(|| { + Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); + SessionIdStore::::set(1); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, + MESSAGE_PROOF, + ROUTER_ID_2 + ), + Error::::UnknownRouter + ); + }); + } + + #[test] + fn proof_count_overflow() { + new_test_ext().execute_with(|| { + let session_id = 1; + + Routers::::set( + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), + ); + SessionIdStore::::set(session_id); + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_2, + InboundEntry::::Proof { + session_id, + current_count: u32::MAX, + }, + ); + + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, + MESSAGE_PROOF, + ROUTER_ID_2 + ), + Arithmetic(Overflow) + ); + }); + } + + #[test] + fn expected_message_proof_type() { + new_test_ext().execute_with(|| { + let domain_address = TEST_DOMAIN_ADDRESS; + let session_id = 1; + + Routers::::set( + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), + ); + SessionIdStore::::set(session_id); + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_2, + InboundEntry::::Message { + session_id, domain_address: domain_address.clone(), - message: message.clone(), - router_id: router_id.clone(), - }; + message: Message::Simple, + expected_proof_count: 2, + }, + ); - Routers::::set( - BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), - ); - SessionIdStore::::set(session_id); - PendingInboundEntries::::insert( - message_proof, - router_id, - InboundEntry::::Proof { - session_id, - current_count: 0, - }, - ); + assert_noop!( + LiquidityPoolsGateway::execute_message_recovery( + RuntimeOrigin::root(), + TEST_DOMAIN_ADDRESS, + MESSAGE_PROOF, + ROUTER_ID_2 + ), + Error::::ExpectedMessageProofType + ); + }); + } + } +} - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::ExpectedMessageProofType); +mod implementations { + use super::*; + + mod outbound_message_handler { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let sender = get_test_account_id(); + let msg = Message::Simple; + let message_proof = msg.to_message_proof().get_message_proof().unwrap(); + + assert_ok!(LiquidityPoolsGateway::set_routers( + RuntimeOrigin::root(), + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), + )); + + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { + match mock_msg { + GatewayMessage::Inbound { .. } => { + assert!(false, "expected outbound message") + } + GatewayMessage::Outbound { + sender, message, .. + } => { + assert_eq!(sender, ::Sender::get()); + + match message { + Message::Proof(p) => { + assert_eq!(p, message_proof); + } + _ => {} + } + } + } + + Ok(()) }); - } + + assert_ok!(LiquidityPoolsGateway::handle(sender, domain, msg)); + assert_eq!(handler.times(), 3); + }); + } + + #[test] + fn domain_not_supported() { + new_test_ext().execute_with(|| { + let domain = Domain::Centrifuge; + let sender = get_test_account_id(); + let msg = Message::Simple; + + assert_noop!( + LiquidityPoolsGateway::handle(sender, domain, msg), + Error::::DomainNotSupported + ); + }); + } + + #[test] + fn routers_not_found() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let sender = get_test_account_id(); + let msg = Message::Simple; + + assert_noop!( + LiquidityPoolsGateway::handle(sender, domain, msg), + Error::::NotEnoughRoutersForDomain + ); + }); + } + + #[test] + fn message_queue_error() { + new_test_ext().execute_with(|| { + let domain = Domain::EVM(0); + let sender = get_test_account_id(); + let msg = Message::Simple; + + assert_ok!(LiquidityPoolsGateway::set_routers( + RuntimeOrigin::root(), + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), + )); + + let gateway_message = GatewayMessage::Outbound { + sender: ::Sender::get(), + message: msg.clone(), + router_id: ROUTER_ID_1, + }; + + let err = DispatchError::Unavailable; + + let handler = MockLiquidityPoolsGatewayQueue::mock_submit(move |mock_msg| { + assert_eq!(mock_msg, gateway_message); + + Err(err) + }); + + assert_noop!(LiquidityPoolsGateway::handle(sender, domain, msg), err); + assert_eq!(handler.times(), 1); + }); } + } + + mod message_processor { + use super::*; - mod two_routers { + mod inbound { use super::*; - mod success { - use super::*; + #[macro_use] + mod util { + use super::*; + + pub fn run_inbound_message_test_suite(suite: InboundMessageTestSuite) { + let test_routers = suite.routers; + + for test in suite.tests { + println!("Executing test for - {:?}", test.router_messages); + + new_test_ext().execute_with(|| { + let session_id = TEST_SESSION_ID; + + Routers::::set( + BoundedVec::try_from(test_routers.clone()).unwrap(), + ); + SessionIdStore::::set( + session_id, + ); + + let handler = MockLiquidityPools::mock_handle(move |_, _| Ok(())); + + for router_message in test.router_messages { + let gateway_message = GatewayMessage::Inbound { + domain_address: TEST_DOMAIN_ADDRESS, + message: router_message.1, + router_id: router_message.0, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_ok!(res); + } + + let expected_message_submitted_times = + test.expected_test_result.message_submitted_times; + let message_submitted_times = handler.times(); + + assert_eq!( + message_submitted_times, + expected_message_submitted_times, + "Expected message to be submitted {expected_message_submitted_times} times, was {message_submitted_times}" + ); + + for expected_storage_entry in + test.expected_test_result.expected_storage_entries + { + let expected_storage_entry_router_id = expected_storage_entry.0; + let expected_inbound_entry = expected_storage_entry.1; + + let storage_entry = PendingInboundEntries::::get( + MESSAGE_PROOF, expected_storage_entry_router_id, + ); + assert_eq!(storage_entry, expected_inbound_entry, "Expected inbound entry {expected_inbound_entry:?}, found {storage_entry:?}"); + } + }); + } + } + + /// Used for generating all `RouterMessage` combinations like: + /// + /// vec![ + /// (ROUTER_ID_1, Message::Simple), + /// (ROUTER_ID_1, Message::Simple), + /// ] + /// vec![ + /// (ROUTER_ID_1, Message::Simple), + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + /// ] + /// vec![ + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + /// (ROUTER_ID_1, Message::Simple), + /// ] + /// vec![ + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + /// (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + /// ] + pub fn generate_test_combinations( + t: T, + count: usize, + ) -> Vec::Item>> + where + T: IntoIterator + Clone, + T::IntoIter: Clone, + T::Item: Clone, + { + std::iter::repeat(t.clone().into_iter()) + .take(count) + .multi_cartesian_product() + .collect::>() + } + + /// Type used for mapping a message to a router hash. + pub type RouterMessage = (RouterId, Message); + + /// Type used for aggregating tests for inbound messages. + pub struct InboundMessageTestSuite { + pub routers: Vec, + pub tests: Vec, + } + + /// Type used for defining a test which contains a set of + /// `RouterMessage` combinations and the expected test result. + pub struct InboundMessageTest { + pub router_messages: Vec, + pub expected_test_result: ExpectedTestResult, + } + + /// Type used for defining the number of expected inbound + /// message submission and the exected storage state. + #[derive(Clone, Debug)] + pub struct ExpectedTestResult { + pub message_submitted_times: u32, + pub expected_storage_entries: Vec<(RouterId, Option>)>, + } + + /// Generates the combinations of `RouterMessage` used when + /// testing, maps the `ExpectedTestResult` for each and + /// creates the `InboundMessageTestSuite`. + pub fn generate_test_suite( + routers: Vec, + test_data: Vec, + expected_results: HashMap, ExpectedTestResult>, + message_count: usize, + ) -> InboundMessageTestSuite { + let tests = generate_test_combinations(test_data, message_count); + + let tests = tests + .into_iter() + .map(|router_messages| { + let expected_test_result = expected_results + .get(&router_messages) + .expect( + format!("test for {router_messages:?} should be covered") + .as_str(), + ) + .clone(); + + InboundMessageTest { + router_messages, + expected_test_result, + } + }) + .collect::>(); + + InboundMessageTestSuite { routers, tests } + } + } + + use util::*; + + mod one_router { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let message_proof = message.to_message_proof().get_message_proof().unwrap(); + let session_id = 1; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_id = ROUTER_ID_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_id: router_id.clone(), + }; + + Routers::::set( + BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), + ); + SessionIdStore::::set(session_id); + + let handler = MockLiquidityPools::mock_handle( + move |mock_domain_address, mock_message| { + assert_eq!(mock_domain_address, domain_address); + assert_eq!(mock_message, message); + + Ok(()) + }, + ); + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_ok!(res); + assert_eq!(handler.times(), 1); + + assert!( + PendingInboundEntries::::get(message_proof, router_id) + .is_none() + ); + }); + } + + #[test] + fn multi_router_not_found() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_hash = ROUTER_ID_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_id: router_hash, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::NotEnoughRoutersForDomain); + }); + } + + #[test] + fn unknown_inbound_message_router() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let session_id = 1; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_hash = ROUTER_ID_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + // The router stored has a different hash, this should trigger the + // expected error. + router_id: ROUTER_ID_2, + }; + + Routers::::set( + BoundedVec::<_, _>::try_from(vec![router_hash]).unwrap(), + ); + SessionIdStore::::set(session_id); + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::UnknownRouter); + }); + } + + #[test] + fn expected_message_proof_type() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + let message_proof = message.to_message_proof().get_message_proof().unwrap(); + let session_id = 1; + let domain_address = DomainAddress::EVM(1, [1; 20]); + let router_id = ROUTER_ID_1; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_id: router_id.clone(), + }; + + Routers::::set( + BoundedVec::<_, _>::try_from(vec![router_id.clone()]).unwrap(), + ); + SessionIdStore::::set(session_id); + PendingInboundEntries::::insert( + message_proof, + router_id, + InboundEntry::::Proof { + session_id, + current_count: 0, + }, + ); + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::ExpectedMessageProofType); + }); + } + } + + mod two_routers { + use super::*; + + mod success { + use super::*; + + lazy_static! { + static ref TEST_DATA: Vec = vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ]; + } + + mod two_messages { + use super::*; + + const MESSAGE_COUNT: usize = 2; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![ROUTER_ID_1, ROUTER_ID_2], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + + mod three_messages { + use super::*; + + const MESSAGE_COUNT: usize = 3; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 3, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 3, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![ROUTER_ID_1, ROUTER_ID_2], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + + mod four_messages { + use super::*; + + const MESSAGE_COUNT: usize = 4; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 4, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 2, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![ROUTER_ID_1, ROUTER_ID_2], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); + + run_inbound_message_test_suite(suite); + } + } + } + + mod failure { + use super::*; + + #[test] + fn message_expected_from_first_router() { + new_test_ext().execute_with(|| { + let session_id = 1; + + Routers::::set( + BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]) + .unwrap(), + ); + SessionIdStore::::set(session_id); + + let gateway_message = GatewayMessage::Inbound { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + router_id: ROUTER_ID_2, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::MessageExpectedFromFirstRouter); + }); + } + + #[test] + fn proof_not_expected_from_first_router() { + new_test_ext().execute_with(|| { + let session_id = 1; + + Routers::::set( + BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]) + .unwrap(), + ); + SessionIdStore::::set(session_id); + + let gateway_message = GatewayMessage::Inbound { + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Proof(MESSAGE_PROOF), + router_id: ROUTER_ID_1, + }; + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, Error::::ProofNotExpectedFromFirstRouter); + }); + } + } + } + + mod three_routers { + use super::*; + + lazy_static! { + static ref TEST_DATA: Vec = vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + ]; + } + + mod two_messages { + use super::*; + + const MESSAGE_COUNT: usize = 2; + + #[test] + fn success() { + let expected_results: HashMap, ExpectedTestResult> = + HashMap::from([ + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + (ROUTER_ID_2, None), + (ROUTER_ID_3, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + (ROUTER_ID_3, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + (ROUTER_ID_3, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ( + vec![ + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + (ROUTER_ID_3, None), + ], + }, + ), + ( + vec![ + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + ], + ExpectedTestResult { + message_submitted_times: 0, + expected_storage_entries: vec![ + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), + (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ], + }, + ), + ]); + + let suite = generate_test_suite( + vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + TEST_DATA.clone(), + expected_results, + MESSAGE_COUNT, + ); - lazy_static! { - static ref TEST_DATA: Vec = vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ]; + run_inbound_message_test_suite(suite); + } } - mod two_messages { + mod three_messages { use super::*; - const MESSAGE_COUNT: usize = 2; + const MESSAGE_COUNT: usize = 3; #[test] fn success() { @@ -869,6 +2233,7 @@ mod message_processor_impl { vec![ (ROUTER_ID_1, Message::Simple), (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, @@ -879,10 +2244,11 @@ mod message_processor_impl { session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - expected_proof_count: 2, + expected_proof_count: 6, }), ), (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), @@ -890,6 +2256,7 @@ mod message_processor_impl { vec![ (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, @@ -899,64 +2266,67 @@ mod message_processor_impl { ROUTER_ID_2, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, - current_count: 2, + current_count: 3, }), ), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ (ROUTER_ID_1, None), (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 3, + }), + ), ], }, ), ( vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + (ROUTER_ID_3, None), ], }, ), - ]); - - let suite = generate_test_suite( - vec![ROUTER_ID_1, ROUTER_ID_2], - TEST_DATA.clone(), - expected_results, - MESSAGE_COUNT, - ); - - run_inbound_message_test_suite(suite); - } - } - - mod three_messages { - use super::*; - - const MESSAGE_COUNT: usize = 3; - - #[test] - fn success() { - let expected_results: HashMap, ExpectedTestResult> = - HashMap::from([ ( vec![ (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { @@ -968,41 +2338,57 @@ mod message_processor_impl { session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - expected_proof_count: 3, + expected_proof_count: 4, }), ), - (ROUTER_ID_2, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (ROUTER_ID_1, None), + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), ( ROUTER_ID_2, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, - current_count: 3, + current_count: 2, }), ), + (ROUTER_ID_3, None), ], }, ), ( vec![ (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ ( ROUTER_ID_1, @@ -1010,21 +2396,28 @@ mod message_processor_impl { session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - expected_proof_count: 1, + expected_proof_count: 2, }), ), (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), ], }, ), ( vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ ( ROUTER_ID_1, @@ -1032,28 +2425,15 @@ mod message_processor_impl { session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - expected_proof_count: 1, + expected_proof_count: 2, }), ), (ROUTER_ID_2, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), ( - ROUTER_ID_2, + ROUTER_ID_3, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, - current_count: 1, + current_count: 2, }), ), ], @@ -1061,12 +2441,12 @@ mod message_processor_impl { ), ( vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ ( ROUTER_ID_1, @@ -1074,10 +2454,17 @@ mod message_processor_impl { session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - expected_proof_count: 1, + expected_proof_count: 2, }), ), (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), ], }, ), @@ -1088,16 +2475,25 @@ mod message_processor_impl { (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ - (ROUTER_ID_1, None), + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), ( ROUTER_ID_2, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, - current_count: 1, + current_count: 2, }), ), + (ROUTER_ID_3, None), ], }, ), @@ -1108,47 +2504,33 @@ mod message_processor_impl { (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ - (ROUTER_ID_1, None), + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }), + ), ( ROUTER_ID_2, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, - current_count: 1, + current_count: 2, }), ), + (ROUTER_ID_3, None), ], }, ), - ]); - - let suite = generate_test_suite( - vec![ROUTER_ID_1, ROUTER_ID_2], - TEST_DATA.clone(), - expected_results, - MESSAGE_COUNT, - ); - - run_inbound_message_test_suite(suite); - } - } - - mod four_messages { - use super::*; - - const MESSAGE_COUNT: usize = 4; - - #[test] - fn success() { - let expected_results: HashMap, ExpectedTestResult> = - HashMap::from([ ( vec![ (ROUTER_ID_1, Message::Simple), (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { message_submitted_times: 0, @@ -1163,39 +2545,53 @@ mod message_processor_impl { }), ), (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), ], }, ), ( vec![ (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 0, expected_storage_entries: vec![ - (ROUTER_ID_1, None), + ( + ROUTER_ID_1, + Some(InboundEntry::::Message { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }), + ), ( ROUTER_ID_2, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, - current_count: 4, + current_count: 1, }), ), + (ROUTER_ID_3, None), ], }, ), ( vec![ (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ ( ROUTER_ID_1, @@ -1203,22 +2599,28 @@ mod message_processor_impl { session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - expected_proof_count: 2, + expected_proof_count: 4, }), ), (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), ], }, ), ( vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ ( ROUTER_ID_1, @@ -1226,10 +2628,17 @@ mod message_processor_impl { session_id: TEST_SESSION_ID, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, - expected_proof_count: 2, + expected_proof_count: 4, }), ), (ROUTER_ID_2, None), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), ], }, ), @@ -1237,60 +2646,44 @@ mod message_processor_impl { vec![ (ROUTER_ID_1, Message::Simple), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), + message_submitted_times: 1, + expected_storage_entries: vec![ + (ROUTER_ID_1, None), (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { message_submitted_times: 1, expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), + (ROUTER_ID_1, None), (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 2, + message_submitted_times: 1, expected_storage_entries: vec![ (ROUTER_ID_1, None), (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), @@ -1298,90 +2691,120 @@ mod message_processor_impl { vec![ (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 2, + message_submitted_times: 1, expected_storage_entries: vec![ (ROUTER_ID_1, None), (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { - message_submitted_times: 2, + message_submitted_times: 1, expected_storage_entries: vec![ (ROUTER_ID_1, None), (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_1, Message::Simple), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 2, + message_submitted_times: 1, expected_storage_entries: vec![ (ROUTER_ID_1, None), (ROUTER_ID_2, None), + (ROUTER_ID_3, None), ], }, ), ( vec![ - (ROUTER_ID_1, Message::Simple), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 2, + message_submitted_times: 0, expected_storage_entries: vec![ (ROUTER_ID_1, None), - (ROUTER_ID_2, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), ], }, ), ( vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), ], ExpectedTestResult { - message_submitted_times: 2, + message_submitted_times: 0, expected_storage_entries: vec![ (ROUTER_ID_1, None), - (ROUTER_ID_2, None), + ( + ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 2, + }), + ), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), ], }, ), ( vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ (ROUTER_ID_1, None), ( ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ( + ROUTER_ID_3, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, current_count: 2, @@ -1392,17 +2815,23 @@ mod message_processor_impl { ), ( vec![ + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ (ROUTER_ID_1, None), ( ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ( + ROUTER_ID_3, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, current_count: 2, @@ -1414,12 +2843,11 @@ mod message_processor_impl { ( vec![ (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ (ROUTER_ID_1, None), ( @@ -1429,22 +2857,35 @@ mod message_processor_impl { current_count: 2, }), ), + ( + ROUTER_ID_3, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), ], }, ), ( vec![ (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), + (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), ], ExpectedTestResult { - message_submitted_times: 1, + message_submitted_times: 0, expected_storage_entries: vec![ (ROUTER_ID_1, None), ( ROUTER_ID_2, + Some(InboundEntry::::Proof { + session_id: TEST_SESSION_ID, + current_count: 1, + }), + ), + ( + ROUTER_ID_3, Some(InboundEntry::::Proof { session_id: TEST_SESSION_ID, current_count: 2, @@ -1456,7 +2897,7 @@ mod message_processor_impl { ]); let suite = generate_test_suite( - vec![ROUTER_ID_1, ROUTER_ID_2], + vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], TEST_DATA.clone(), expected_results, MESSAGE_COUNT, @@ -1467,1532 +2908,747 @@ mod message_processor_impl { } } - mod failure { - use super::*; - - #[test] - fn message_expected_from_first_router() { - new_test_ext().execute_with(|| { - let session_id = 1; - - Routers::::set( - BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - ); - SessionIdStore::::set(session_id); - - let gateway_message = GatewayMessage::Inbound { - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - router_id: ROUTER_ID_2, - }; + #[test] + fn inbound_message_handler_error() { + new_test_ext().execute_with(|| { + let domain_address = DomainAddress::EVM(1, [1; 20]); - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::MessageExpectedFromFirstRouter); - }); - } + Routers::::set( + BoundedVec::try_from(vec![ROUTER_ID_1.clone()]).unwrap(), + ); + SessionIdStore::::set(1); - #[test] - fn proof_not_expected_from_first_router() { - new_test_ext().execute_with(|| { - let session_id = 1; + let message = Message::Simple; + let gateway_message = GatewayMessage::Inbound { + domain_address: domain_address.clone(), + message: message.clone(), + router_id: ROUTER_ID_1, + }; - Routers::::set( - BoundedVec::<_, _>::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - ); - SessionIdStore::::set(session_id); + let err = DispatchError::Unavailable; - let gateway_message = GatewayMessage::Inbound { - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Proof(MESSAGE_PROOF), - router_id: ROUTER_ID_1, - }; + MockLiquidityPools::mock_handle(move |mock_domain_address, mock_mesage| { + assert_eq!(mock_domain_address, domain_address); + assert_eq!(mock_mesage, message); - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, Error::::ProofNotExpectedFromFirstRouter); + Err(err) }); - } + + let (res, _) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, err); + }); } } - mod three_routers { + mod outbound { use super::*; - lazy_static! { - static ref TEST_DATA: Vec = vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ]; - } - - mod two_messages { - use super::*; + #[test] + fn success() { + new_test_ext().execute_with(|| { + let sender = TEST_DOMAIN_ADDRESS; + let message = Message::Simple; - const MESSAGE_COUNT: usize = 2; + let gateway_message = GatewayMessage::Outbound { + sender: sender.clone(), + message: message.clone(), + router_id: ROUTER_ID_1, + }; - #[test] - fn success() { - let expected_results: HashMap, ExpectedTestResult> = - HashMap::from([ - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), - ), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ]); + let handler = MockMessageSender::mock_send( + move |mock_router_id, mock_sender, mock_message| { + assert_eq!(mock_router_id, ROUTER_ID_1); + assert_eq!(mock_sender, sender); + assert_eq!(mock_message, message.serialize()); - let suite = generate_test_suite( - vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - TEST_DATA.clone(), - expected_results, - MESSAGE_COUNT, + Ok(()) + }, ); - run_inbound_message_test_suite(suite); - } + let (res, weight) = LiquidityPoolsGateway::process(gateway_message); + assert_ok!(res); + assert!(weight.eq(&LP_DEFENSIVE_WEIGHT)); + assert_eq!(handler.times(), 1); + }); } - mod three_messages { - use super::*; + #[test] + fn message_sender_error() { + new_test_ext().execute_with(|| { + let sender = TEST_DOMAIN_ADDRESS; + let message = Message::Simple; - const MESSAGE_COUNT: usize = 3; + let gateway_message = GatewayMessage::Outbound { + sender: sender.clone(), + message: message.clone(), + router_id: ROUTER_ID_1, + }; - #[test] - fn success() { - let expected_results: HashMap, ExpectedTestResult> = - HashMap::from([ - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 6, - }), - ), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 3, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 3, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), - ), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - ( - ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), - ), - (ROUTER_ID_2, None), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - ], - ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_1, Message::Simple), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 1, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - (ROUTER_ID_2, None), - (ROUTER_ID_3, None), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ], - }, - ), - ( - vec![ - (ROUTER_ID_2, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - (ROUTER_ID_3, Message::Proof(MESSAGE_PROOF)), - ], - ExpectedTestResult { - message_submitted_times: 0, - expected_storage_entries: vec![ - (ROUTER_ID_1, None), - ( - ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), - ), - ( - ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], - }, - ), - ]); + let router_err = DispatchError::Unavailable; - let suite = generate_test_suite( - vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - TEST_DATA.clone(), - expected_results, - MESSAGE_COUNT, + MockMessageSender::mock_send( + move |mock_router_id, mock_sender, mock_message| { + assert_eq!(mock_router_id, ROUTER_ID_1); + assert_eq!(mock_sender, sender); + assert_eq!(mock_message, message.serialize()); + + Err(router_err) + }, ); - run_inbound_message_test_suite(suite); - } + let (res, weight) = LiquidityPoolsGateway::process(gateway_message); + assert_noop!(res, router_err); + assert!(weight.eq(&LP_DEFENSIVE_WEIGHT)); + }); } } + } - #[test] - fn inbound_message_handler_error() { - new_test_ext().execute_with(|| { - let domain_address = DomainAddress::EVM(1, [1; 20]); - - Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1.clone()]).unwrap()); - SessionIdStore::::set(1); + mod pallet { + use super::*; - let message = Message::Simple; - let gateway_message = GatewayMessage::Inbound { - domain_address: domain_address.clone(), - message: message.clone(), - router_id: ROUTER_ID_1, - }; + mod get_router_ids_for_domain { + use super::*; - let err = DispatchError::Unavailable; + #[test] + fn success() { + new_test_ext().execute_with(|| { + let domain = TEST_DOMAIN_ADDRESS.domain(); + let test_routers = vec![ROUTER_ID_1]; - MockLiquidityPools::mock_handle(move |mock_domain_address, mock_mesage| { - assert_eq!(mock_domain_address, domain_address); - assert_eq!(mock_mesage, message); + Routers::::set(BoundedVec::try_from(test_routers.clone()).unwrap()); - Err(err) + let res = LiquidityPoolsGateway::get_router_ids_for_domain(domain).unwrap(); + assert_eq!(res, test_routers); }); + } - let (res, _) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, err); - }); + #[test] + fn not_enough_routers_for_domain() { + new_test_ext().execute_with(|| { + let domain = TEST_DOMAIN_ADDRESS.domain(); + + let res = LiquidityPoolsGateway::get_router_ids_for_domain(domain.clone()); + + assert_eq!( + res.err().unwrap(), + Error::::NotEnoughRoutersForDomain.into() + ); + + let test_routers = vec![RouterId(4)]; + + Routers::::set(BoundedVec::try_from(test_routers.clone()).unwrap()); + + let res = LiquidityPoolsGateway::get_router_ids_for_domain(domain); + + assert_eq!( + res.err().unwrap(), + Error::::NotEnoughRoutersForDomain.into() + ); + }); + } } - } - mod outbound { - use super::*; + mod get_expected_proof_count { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let tests = vec![ + vec![ROUTER_ID_1], + vec![ROUTER_ID_1, ROUTER_ID_2], + vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + ]; + + for test in tests { + let res = LiquidityPoolsGateway::get_expected_proof_count(&test).unwrap(); + + assert_eq!(res, (test.len() - 1) as u32); + } + }); + } - #[test] - fn success() { - new_test_ext().execute_with(|| { - let sender = TEST_DOMAIN_ADDRESS; - let message = Message::Simple; + #[test] + fn not_enough_routers_for_domain() { + new_test_ext().execute_with(|| { + let res = LiquidityPoolsGateway::get_expected_proof_count(&vec![]); - let gateway_message = GatewayMessage::Outbound { - sender: sender.clone(), - message: message.clone(), - router_id: ROUTER_ID_1, - }; + assert_eq!( + res.err().unwrap(), + Error::::NotEnoughRoutersForDomain.into() + ); + }); + } + } - let handler = MockMessageSender::mock_send( - move |mock_router_id, mock_sender, mock_message| { - assert_eq!(mock_router_id, ROUTER_ID_1); - assert_eq!(mock_sender, sender); - assert_eq!(mock_message, message.serialize()); + mod get_message_proof { + use super::*; - Ok(()) - }, - ); + #[test] + fn get_message_proof() { + new_test_ext().execute_with(|| { + let test_messages = vec![ + Message::Simple, + Message::Proof(MESSAGE_PROOF), + Message::Pack(vec![Message::Simple]), + ]; - let (res, weight) = LiquidityPoolsGateway::process(gateway_message); - assert_ok!(res); - assert!(weight.eq(&LP_DEFENSIVE_WEIGHT)); - assert_eq!(handler.times(), 1); - }); + for test_message in test_messages { + assert_eq!( + LiquidityPoolsGateway::get_message_proof(test_message), + MESSAGE_PROOF + ); + } + }); + } } - #[test] - fn message_sender_error() { - new_test_ext().execute_with(|| { - let sender = TEST_DOMAIN_ADDRESS; - let message = Message::Simple; + mod create_inbound_entry { + use super::*; - let gateway_message = GatewayMessage::Outbound { - sender: sender.clone(), - message: message.clone(), - router_id: ROUTER_ID_1, - }; + #[test] + fn create_inbound_entry() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; - let router_err = DispatchError::Unavailable; + let tests = vec![ + ( + Message::Simple, + InboundEntry::::Message { + session_id: inbound_processing_info.current_session_id, + domain_address: inbound_processing_info.domain_address.clone(), + message: Message::Simple, + expected_proof_count: inbound_processing_info + .expected_proof_count_per_message, + }, + ), + ( + Message::Proof(MESSAGE_PROOF), + InboundEntry::::Proof { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }, + ), + ]; - MockMessageSender::mock_send(move |mock_router_id, mock_sender, mock_message| { - assert_eq!(mock_router_id, ROUTER_ID_1); - assert_eq!(mock_sender, sender); - assert_eq!(mock_message, message.serialize()); + for (test_message, expected_inbound_entry) in tests { + let res = LiquidityPoolsGateway::create_inbound_entry( + &inbound_processing_info, + test_message, + ); - Err(router_err) + assert_eq!(res, expected_inbound_entry) + } }); - - let (res, weight) = LiquidityPoolsGateway::process(gateway_message); - assert_noop!(res, router_err); - assert!(weight.eq(&LP_DEFENSIVE_WEIGHT)); - }); + } } - } -} -mod batches { - use super::*; + mod validate_inbound_entry { + use super::*; - const USER: AccountId32 = AccountId32::new([1; 32]); - const OTHER: AccountId32 = AccountId32::new([2; 32]); - const DOMAIN: Domain = Domain::EVM(TEST_EVM_CHAIN); - - #[test] - fn pack_empty() { - new_test_ext().execute_with(|| { - assert_ok!(LiquidityPoolsGateway::start_batch_message( - RuntimeOrigin::signed(USER), - DOMAIN - )); - assert_ok!(LiquidityPoolsGateway::end_batch_message( - RuntimeOrigin::signed(USER), - DOMAIN - )); - }); - } + #[test] + fn success() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; - #[test] - fn pack_several() { - new_test_ext().execute_with(|| { - assert_ok!(LiquidityPoolsGateway::start_batch_message( - RuntimeOrigin::signed(USER), - DOMAIN - )); - - let handler = MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); - - // Ok Batched - assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - - Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); - - // Not batched, it belongs to OTHER - assert_ok!(LiquidityPoolsGateway::handle( - OTHER, - DOMAIN, - Message::Simple - )); - - // Not batched, it belongs to EVM 2 - assert_ok!(LiquidityPoolsGateway::handle( - USER, - Domain::EVM(2), - Message::Simple - )); - - // Ok Batched - assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - - // Two non-packed messages - assert_eq!(handler.times(), 2); - - assert_ok!(LiquidityPoolsGateway::end_batch_message( - RuntimeOrigin::signed(USER), - DOMAIN - )); - - // Packed message queued - assert_eq!(handler.times(), 3); - }); - } + let inbound_entry = InboundEntry::::Message { + session_id: inbound_processing_info.current_session_id, + domain_address: inbound_processing_info.domain_address.clone(), + message: Message::Simple, + expected_proof_count: inbound_processing_info + .expected_proof_count_per_message, + }; - #[test] - fn pack_over_limit() { - new_test_ext().execute_with(|| { - assert_ok!(LiquidityPoolsGateway::start_batch_message( - RuntimeOrigin::signed(USER), - DOMAIN - )); + assert_ok!(LiquidityPoolsGateway::validate_inbound_entry( + &inbound_processing_info, + &ROUTER_ID_1, + &inbound_entry + )); - let handler = MockLiquidityPoolsGatewayQueue::mock_submit(|_| Ok(())); + let inbound_entry = InboundEntry::::Proof { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }; - (0..MAX_PACKED_MESSAGES).for_each(|_| { - assert_ok!(LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple)); - }); + assert_ok!(LiquidityPoolsGateway::validate_inbound_entry( + &inbound_processing_info, + &ROUTER_ID_2, + &inbound_entry + )); + }); + } - assert_err!( - LiquidityPoolsGateway::handle(USER, DOMAIN, Message::Simple), - DispatchError::Other(MAX_PACKED_MESSAGES_ERR) - ); + #[test] + fn unknown_router() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; - let router_id_1 = ROUTER_ID_1; + let inbound_entry = InboundEntry::::Proof { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }; - Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); + assert_noop!( + LiquidityPoolsGateway::validate_inbound_entry( + &inbound_processing_info, + &RouterId(4), + &inbound_entry + ), + Error::::UnknownRouter + ); + }); + } - assert_ok!(LiquidityPoolsGateway::end_batch_message( - RuntimeOrigin::signed(USER), - DOMAIN - )); - assert_eq!(handler.times(), 1); - }); - } + #[test] + fn message_type_mismatch() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; - #[test] - fn end_before_start() { - new_test_ext().execute_with(|| { - assert_err!( - LiquidityPoolsGateway::end_batch_message(RuntimeOrigin::signed(USER), DOMAIN), - Error::::MessagePackingNotStarted - ); - }); - } + let inbound_entry = InboundEntry::::Message { + session_id: inbound_processing_info.current_session_id, + domain_address: inbound_processing_info.domain_address.clone(), + message: Message::Simple, + expected_proof_count: inbound_processing_info + .expected_proof_count_per_message, + }; - #[test] - fn start_before_end() { - new_test_ext().execute_with(|| { - assert_ok!(LiquidityPoolsGateway::start_batch_message( - RuntimeOrigin::signed(USER), - DOMAIN - )); - - assert_err!( - LiquidityPoolsGateway::start_batch_message(RuntimeOrigin::signed(USER), DOMAIN), - Error::::MessagePackingAlreadyStarted - ); - }); - } + assert_noop!( + LiquidityPoolsGateway::validate_inbound_entry( + &inbound_processing_info, + &ROUTER_ID_2, + &inbound_entry + ), + Error::::MessageExpectedFromFirstRouter + ); - #[test] - fn process_inbound() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(TEST_EVM_CHAIN, address.into()); + let inbound_entry = InboundEntry::::Proof { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }; - let router_id_1 = ROUTER_ID_1; + assert_noop!( + LiquidityPoolsGateway::validate_inbound_entry( + &inbound_processing_info, + &ROUTER_ID_1, + &inbound_entry + ), + Error::::ProofNotExpectedFromFirstRouter + ); + }); + } + } - Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); - SessionIdStore::::set(1); + mod upsert_pending_entry { + use super::*; - let handler = MockLiquidityPools::mock_handle(|_, _| Ok(())); + #[test] + fn no_stored_entry() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; - let submessage_count = 5; + let tests = vec![ + ( + ROUTER_ID_1, + InboundEntry::::Message { + session_id: inbound_processing_info.current_session_id, + domain_address: inbound_processing_info.domain_address.clone(), + message: Message::Simple, + expected_proof_count: inbound_processing_info + .expected_proof_count_per_message, + }, + ), + ( + ROUTER_ID_2, + InboundEntry::::Proof { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }, + ), + ]; - let (result, weight) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { - domain_address, - message: Message::deserialize(&(1..=submessage_count).collect::>()).unwrap(), - router_id: ROUTER_ID_1, - }); + for (test_router_id, test_inbound_entry) in tests { + assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( + MESSAGE_PROOF, + test_router_id.clone(), + test_inbound_entry.clone(), + )); - let expected_weight = Weight::default() - // get_inbound_processing_info - .saturating_add(::DbWeight::get().reads(3)) - // process_inbound_message - .saturating_add(Weight::from_parts(0, Message::max_encoded_len() as u64)) - .saturating_add(LP_DEFENSIVE_WEIGHT) - // upsert_pending_entry - .saturating_add( - ::DbWeight::get() - .writes(1) - .saturating_mul(submessage_count.into()), - ) - // get_executable_message - .saturating_add( - ::DbWeight::get() - .reads(1) - .saturating_mul(submessage_count.into()), - ) - // decrease_pending_entries_counts - .saturating_add( - ::DbWeight::get() - .writes(1) - .saturating_mul(submessage_count.into()), - ) - // process_inbound_message - .saturating_mul(submessage_count.into()); - - assert_ok!(result); - assert_eq!(weight, expected_weight); - assert_eq!(handler.times(), submessage_count as u32); - }); - } + let res = + PendingInboundEntries::::get(MESSAGE_PROOF, test_router_id) + .unwrap(); - #[test] - fn process_inbound_with_errors() { - new_test_ext().execute_with(|| { - let address = H160::from_slice(&get_test_account_id().as_slice()[..20]); - let domain_address = DomainAddress::EVM(1, address.into()); + assert_eq!(res, test_inbound_entry); + } + }); + } - let router_id_1 = ROUTER_ID_1; + #[test] + fn message_entry_same_session() { + new_test_ext().execute_with(|| { + let inbound_entry = InboundEntry::::Message { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }; - Routers::::set(BoundedVec::try_from(vec![router_id_1]).unwrap()); - SessionIdStore::::set(1); + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + inbound_entry.clone(), + ); - let counter = Arc::new(AtomicU32::new(0)); + assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( + MESSAGE_PROOF, + ROUTER_ID_1.clone(), + inbound_entry, + )); + + let res = + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); + assert_eq!( + res, + InboundEntry::::Message { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + ); + }); + } - let handler = MockLiquidityPools::mock_handle(move |_, _| { - match counter.fetch_add(1, Ordering::Relaxed) { - 2 => Err(DispatchError::Unavailable), - _ => Ok(()), - } - }); + #[test] + fn message_entry_new_session() { + new_test_ext().execute_with(|| { + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + InboundEntry::::Message { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }, + ); - let (result, _) = LiquidityPoolsGateway::process(GatewayMessage::Inbound { - domain_address, - message: Message::deserialize(&(1..=5).collect::>()).unwrap(), - router_id: ROUTER_ID_1, - }); + assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( + MESSAGE_PROOF, + ROUTER_ID_1.clone(), + InboundEntry::::Message { + session_id: 2, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }, + )); + + let res = + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); + assert_eq!( + res, + InboundEntry::::Message { + session_id: 2, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + ); + }); + } - assert_err!(result, DispatchError::Unavailable); - // 2 correct messages and 1 failed message processed. - assert_eq!(handler.times(), 3); - }); - } -} + #[test] + fn expected_message_type() { + new_test_ext().execute_with(|| { + let inbound_entry = InboundEntry::::Message { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }; -mod execute_message_recovery { - use super::*; + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + inbound_entry.clone(), + ); - #[test] - fn success_with_execution() { - new_test_ext().execute_with(|| { - let session_id = 1; + assert_noop!( + LiquidityPoolsGateway::upsert_pending_entry( + MESSAGE_PROOF, + ROUTER_ID_1.clone(), + InboundEntry::Proof { + session_id: 1, + current_count: 1 + }, + ), + Error::::ExpectedMessageType + ); + }); + } - Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap()); - SessionIdStore::::set(session_id); + #[test] + fn proof_entry_same_session() { + new_test_ext().execute_with(|| { + let inbound_entry = InboundEntry::::Proof { + session_id: 1, + current_count: 1, + }; - PendingInboundEntries::::insert( - MESSAGE_PROOF, - ROUTER_ID_1, - InboundEntry::::Message { - session_id, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 1, - }, - ); + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + inbound_entry.clone(), + ); - let handler = - MockLiquidityPools::mock_handle(move |mock_domain_address, mock_message| { - assert_eq!(mock_domain_address, TEST_DOMAIN_ADDRESS); - assert_eq!(mock_message, Message::Simple); + assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( + MESSAGE_PROOF, + ROUTER_ID_1.clone(), + inbound_entry, + )); - Ok(()) + let res = + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); + assert_eq!( + res, + InboundEntry::::Proof { + session_id: 1, + current_count: 2, + } + ); }); + } - assert_ok!(LiquidityPoolsGateway::execute_message_recovery( - RuntimeOrigin::root(), - TEST_DOMAIN_ADDRESS, - MESSAGE_PROOF, - ROUTER_ID_2, - )); + #[test] + fn proof_entry_new_session() { + new_test_ext().execute_with(|| { + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + InboundEntry::::Proof { + session_id: 1, + current_count: 2, + }, + ); - event_exists(Event::::MessageRecoveryExecuted { - proof: MESSAGE_PROOF, - router_id: ROUTER_ID_2, - }); + assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( + MESSAGE_PROOF, + ROUTER_ID_1.clone(), + InboundEntry::::Proof { + session_id: 2, + current_count: 1, + }, + )); - assert_eq!(handler.times(), 1); + let res = + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); + assert_eq!( + res, + InboundEntry::::Proof { + session_id: 2, + current_count: 1, + } + ); + }); + } - assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none()); - assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2).is_none()); - }); - } + #[test] + fn expected_message_proof_type() { + new_test_ext().execute_with(|| { + let inbound_entry = InboundEntry::::Proof { + session_id: 1, + current_count: 1, + }; - #[test] - fn success_without_execution() { - new_test_ext().execute_with(|| { - let session_id = 1; + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + inbound_entry.clone(), + ); - Routers::::set( - BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]).unwrap(), - ); - SessionIdStore::::set(session_id); + assert_noop!( + LiquidityPoolsGateway::upsert_pending_entry( + MESSAGE_PROOF, + ROUTER_ID_1.clone(), + InboundEntry::Message { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }, + ), + Error::::ExpectedMessageProofType + ); + }); + } + } - PendingInboundEntries::::insert( - MESSAGE_PROOF, - ROUTER_ID_1, - InboundEntry::::Message { - session_id, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }, - ); - - assert_ok!(LiquidityPoolsGateway::execute_message_recovery( - RuntimeOrigin::root(), - TEST_DOMAIN_ADDRESS, - MESSAGE_PROOF, - ROUTER_ID_2, - )); - - event_exists(Event::::MessageRecoveryExecuted { - proof: MESSAGE_PROOF, - router_id: ROUTER_ID_2, - }); + mod execute_if_requirements_are_met { + use super::*; - assert_eq!( - PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1), - Some(InboundEntry::::Message { - session_id, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }) - ); - assert_eq!( - PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2), - Some(InboundEntry::::Proof { - session_id, - current_count: 1 - }) - ); - assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_3).is_none()) - }); - } + #[test] + fn entries_with_invalid_session_are_ignored() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; - #[test] - fn not_enough_routers_for_domain() { - new_test_ext().execute_with(|| { - assert_noop!( - LiquidityPoolsGateway::execute_message_recovery( - RuntimeOrigin::root(), - TEST_DOMAIN_ADDRESS, - MESSAGE_PROOF, - ROUTER_ID_1, - ), - Error::::NotEnoughRoutersForDomain - ); + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + InboundEntry::Message { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }, + ); + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_2, + InboundEntry::Proof { + session_id: 2, + current_count: 1, + }, + ); + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_3, + InboundEntry::Proof { + session_id: 3, + current_count: 1, + }, + ); - Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); + assert_ok!(LiquidityPoolsGateway::execute_if_requirements_are_met( + &inbound_processing_info, + MESSAGE_PROOF + )); + assert!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_some() + ); + assert!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2).is_some() + ); + assert!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_3).is_some() + ); + }); + } + } - assert_noop!( - LiquidityPoolsGateway::execute_message_recovery( - RuntimeOrigin::root(), - TEST_DOMAIN_ADDRESS, - MESSAGE_PROOF, - ROUTER_ID_1, - ), - Error::::NotEnoughRoutersForDomain - ); - }); - } + mod decrease_pending_entries_counts { + use super::*; - #[test] - fn unknown_router() { - new_test_ext().execute_with(|| { - Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1]).unwrap()); - SessionIdStore::::set(1); + #[test] + fn pending_inbound_entry_not_found() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; - assert_noop!( - LiquidityPoolsGateway::execute_message_recovery( - RuntimeOrigin::root(), - TEST_DOMAIN_ADDRESS, - MESSAGE_PROOF, - ROUTER_ID_2 - ), - Error::::UnknownRouter - ); - }); - } + assert_noop!( + LiquidityPoolsGateway::decrease_pending_entries_counts( + &inbound_processing_info, + MESSAGE_PROOF + ), + Error::::PendingInboundEntryNotFound + ); + }); + } - #[test] - fn proof_count_overflow() { - new_test_ext().execute_with(|| { - let session_id = 1; - - Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap()); - SessionIdStore::::set(session_id); - PendingInboundEntries::::insert( - MESSAGE_PROOF, - ROUTER_ID_2, - InboundEntry::::Proof { - session_id, - current_count: u32::MAX, - }, - ); + #[test] + fn message_entry_new_session() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1], + current_session_id: 2, + expected_proof_count_per_message: 2, + }; - assert_noop!( - LiquidityPoolsGateway::execute_message_recovery( - RuntimeOrigin::root(), - TEST_DOMAIN_ADDRESS, - MESSAGE_PROOF, - ROUTER_ID_2 - ), - Arithmetic(Overflow) - ); - }); - } + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + InboundEntry::Message { + session_id: 1, + domain_address: inbound_processing_info.domain_address.clone(), + message: Message::Simple, + expected_proof_count: inbound_processing_info + .expected_proof_count_per_message, + }, + ); - #[test] - fn expected_message_proof_type() { - new_test_ext().execute_with(|| { - let domain_address = TEST_DOMAIN_ADDRESS; - let session_id = 1; - - Routers::::set(BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap()); - SessionIdStore::::set(session_id); - PendingInboundEntries::::insert( - MESSAGE_PROOF, - ROUTER_ID_2, - InboundEntry::::Message { - session_id, - domain_address: domain_address.clone(), - message: Message::Simple, - expected_proof_count: 2, - }, - ); + assert_ok!(LiquidityPoolsGateway::decrease_pending_entries_counts( + &inbound_processing_info, + MESSAGE_PROOF + )); + assert!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none() + ); + }); + } - assert_noop!( - LiquidityPoolsGateway::execute_message_recovery( - RuntimeOrigin::root(), - TEST_DOMAIN_ADDRESS, - MESSAGE_PROOF, - ROUTER_ID_2 - ), - Error::::ExpectedMessageProofType - ); - }); + #[test] + fn proof_entry_new_session() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1], + current_session_id: 2, + expected_proof_count_per_message: 2, + }; + + PendingInboundEntries::::insert( + MESSAGE_PROOF, + ROUTER_ID_1, + InboundEntry::Proof { + session_id: 1, + current_count: 1, + }, + ); + + assert_ok!(LiquidityPoolsGateway::decrease_pending_entries_counts( + &inbound_processing_info, + MESSAGE_PROOF + )); + assert!( + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none() + ); + }); + } + } } } From 5739aef40409652d2b6db4c61515bf3d78bbdfc8 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Wed, 14 Aug 2024 21:28:35 +0300 Subject: [PATCH 23/38] lp-gateway: Move InboundEntry logic to implementation --- pallets/liquidity-pools-gateway/src/lib.rs | 47 +- .../src/message_processing.rs | 502 ++++++++++-------- pallets/liquidity-pools-gateway/src/tests.rs | 6 +- 3 files changed, 314 insertions(+), 241 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index bc73473195..f8e3d4e124 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -43,7 +43,10 @@ use parity_scale_codec::FullCodec; use sp_arithmetic::traits::{BaseArithmetic, EnsureAddAssign, One}; use sp_std::convert::TryInto; -use crate::{message_processing::InboundEntry, weights::WeightInfo}; +use crate::{ + message_processing::{InboundEntry, InboundProcessingInfo}, + weights::WeightInfo, +}; mod origin; pub use origin::*; @@ -62,6 +65,7 @@ mod tests; #[frame_support::pallet] pub mod pallet { use super::*; + use crate::message_processing::ProofEntry; const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); @@ -93,7 +97,14 @@ pub mod pallet { type AdminOrigin: EnsureOrigin<::RuntimeOrigin>; /// The Liquidity Pools message type. - type Message: LPEncoding + Clone + Debug + PartialEq + MaxEncodedLen + TypeInfo + FullCodec; + type Message: LPEncoding + + Clone + + Debug + + PartialEq + + Eq + + MaxEncodedLen + + TypeInfo + + FullCodec; /// The target of the messages coming from this chain type MessageSender: MessageSender; @@ -266,6 +277,12 @@ pub mod pallet { /// Not enough routers are stored for a domain. NotEnoughRoutersForDomain, + + /// The messages of 2 inbound entries do not match. + InboundEntryMessageMismatch, + + /// The domain addresses of 2 inbound entries do not match. + InboundEntryDomainAddressMismatch, } #[pallet::call] @@ -426,7 +443,7 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - let inbound_processing_info = Self::get_inbound_processing_info(domain_address)?; + let inbound_processing_info: InboundProcessingInfo = domain_address.try_into()?; ensure!( inbound_processing_info @@ -443,29 +460,13 @@ pub mod pallet { PendingInboundEntries::::try_mutate(proof, router_id.clone(), |storage_entry| { match storage_entry { - Some(stored_inbound_entry) => match stored_inbound_entry { - InboundEntry::Proof { - session_id, - current_count, - } => { - if *session_id != inbound_processing_info.current_session_id { - *session_id = inbound_processing_info.current_session_id; - *current_count = 1; - } else { - current_count.ensure_add_assign(1)?; - } - - Ok::<(), DispatchError>(()) - } - InboundEntry::Message { .. } => { - Err(Error::::ExpectedMessageProofType.into()) - } - }, + Some(stored_inbound_entry) => stored_inbound_entry + .increment_proof_count(inbound_processing_info.current_session_id), None => { - *storage_entry = Some(InboundEntry::::Proof { + *storage_entry = Some(InboundEntry::::Proof(ProofEntry { session_id: inbound_processing_info.current_session_id, current_count: 1, - }); + })); Ok::<(), DispatchError>(()) } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 3e527b6146..bac20f3e1c 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -17,23 +17,247 @@ use crate::{ message::GatewayMessage, Config, Error, Pallet, PendingInboundEntries, Routers, SessionIdStore, }; +/// Type that holds the information needed for inbound message entries. +#[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct MessageEntry { + /// The session ID for this entry. + pub session_id: T::SessionId, + + /// The sender of the inbound message. + pub domain_address: DomainAddress, + + /// The LP message. + pub message: T::Message, + + /// The expected proof count for processing one or more of the provided + /// message. + /// + /// NOTE - this gets increased by the `expected_proof_count` for a set of + /// routers (see `get_expected_proof_count`) every time a new identical message is submitted. + pub expected_proof_count: u32, +} + +/// Type that holds the information needed for inbound proof entries. +#[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct ProofEntry { + /// The session ID for this entry. + pub session_id: T::SessionId, + + /// The number of proofs received for a particular message. + /// + /// NOTE - this gets increased by 1 every time a new identical message is + /// submitted. + pub current_count: u32, +} + +impl ProofEntry { + /// Returns `true` if all the following conditions are true: + /// - the session IDs match + /// - the `current_count` is greater than 0 + pub fn has_valid_vote_for_session(&self, session_id: T::SessionId) -> bool { + self.session_id == session_id && self.current_count > 0 + } +} + /// Type used when storing inbound message information. #[derive(Debug, Encode, Decode, Clone, Eq, MaxEncodedLen, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub enum InboundEntry { - Message { - session_id: T::SessionId, - domain_address: DomainAddress, - message: T::Message, - expected_proof_count: u32, - }, - Proof { - session_id: T::SessionId, - current_count: u32, - }, + Message(MessageEntry), + Proof(ProofEntry), +} + +impl From<(&InboundProcessingInfo, T::Message)> for InboundEntry { + fn from((inbound_processing_info, message): (&InboundProcessingInfo, T::Message)) -> Self { + match message.get_message_proof() { + None => InboundEntry::Message(MessageEntry { + session_id: inbound_processing_info.current_session_id.clone(), + domain_address: inbound_processing_info.domain_address.clone(), + message, + expected_proof_count: inbound_processing_info.expected_proof_count_per_message, + }), + Some(_) => InboundEntry::Proof(ProofEntry { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }), + } + } +} + +impl From> for InboundEntry { + fn from(message_entry: MessageEntry) -> Self { + Self::Message(message_entry) + } +} + +impl From> for InboundEntry { + fn from(proof_entry: ProofEntry) -> Self { + Self::Proof(proof_entry) + } +} + +impl InboundEntry { + /// Creates a new `InboundEntry` based on the information provided. + /// + /// If a session change is detected or if the updated counts reach 0, it + /// means that a new entry is no longer required, otherwise, the counts are + /// decreased accordingly, based on the entry type. + pub fn create_post_voting_entry( + inbound_entry: &InboundEntry, + inbound_processing_info: &InboundProcessingInfo, + ) -> Result, DispatchError> { + match inbound_entry { + InboundEntry::Message(message_entry) => { + if message_entry.session_id != inbound_processing_info.current_session_id { + return Ok(None); + } + + let updated_count = message_entry + .expected_proof_count + .ensure_sub(inbound_processing_info.expected_proof_count_per_message)?; + + if updated_count == 0 { + return Ok(None); + } + + Ok(Some( + MessageEntry { + expected_proof_count: updated_count, + ..message_entry.clone() + } + .into(), + )) + } + InboundEntry::Proof(proof_entry) => { + if proof_entry.session_id != inbound_processing_info.current_session_id { + return Ok(None); + } + + let updated_count = proof_entry.current_count.ensure_sub(1)?; + + if updated_count == 0 { + return Ok(None); + } + + Ok(Some( + ProofEntry { + current_count: updated_count, + ..proof_entry.clone() + } + .into(), + )) + } + } + } + + /// Validation ensures that: + /// + /// - the router that sent the inbound message is a valid router for the + /// specific domain. + /// - messages are only sent by the first inbound router. + /// - proofs are not sent by the first inbound router. + pub fn validate( + &self, + inbound_processing_info: &InboundProcessingInfo, + router_id: &T::RouterId, + ) -> DispatchResult { + let router_ids = inbound_processing_info.router_ids.clone(); + + ensure!( + router_ids.iter().any(|x| x == router_id), + Error::::UnknownRouter + ); + + match self { + InboundEntry::Message { .. } => { + ensure!( + router_ids.get(0) == Some(&router_id), + Error::::MessageExpectedFromFirstRouter + ); + + Ok(()) + } + InboundEntry::Proof { .. } => { + ensure!( + router_ids.get(0) != Some(&router_id), + Error::::ProofNotExpectedFromFirstRouter + ); + + Ok(()) + } + } + } + + /// Checks if the entry type is a proof and increments the count by 1 + /// or sets it to 1 if the session is changed. + pub fn increment_proof_count(&mut self, session_id: T::SessionId) -> DispatchResult { + match self { + InboundEntry::Proof(proof_entry) => { + if proof_entry.session_id != session_id { + proof_entry.session_id = session_id; + proof_entry.current_count = 1; + } else { + proof_entry.current_count.ensure_add_assign(1)?; + } + + Ok::<(), DispatchError>(()) + } + InboundEntry::Message(_) => Err(Error::::ExpectedMessageProofType.into()), + } + } + + /// A pre-dispatch update involves increasing the `expected_proof_count` or + /// `current_count` of `self` with the one of `other`. + /// + /// If a session ID change is detected, `self` is replaced completely by + /// `other`. + pub fn pre_dispatch_update(&mut self, other: Self) -> DispatchResult { + match (&mut *self, &other) { + // Message entries + ( + InboundEntry::Message(self_message_entry), + InboundEntry::Message(other_message_entry), + ) => { + if self_message_entry.session_id != other_message_entry.session_id { + *self = other; + + return Ok(()); + } + + self_message_entry + .expected_proof_count + .ensure_add_assign(other_message_entry.expected_proof_count)?; + + Ok(()) + } + // Proof entries + (InboundEntry::Proof(self_proof_entry), InboundEntry::Proof(other_proof_entry)) => { + if self_proof_entry.session_id != other_proof_entry.session_id { + *self = other; + + return Ok(()); + } + + self_proof_entry + .current_count + .ensure_add_assign(other_proof_entry.current_count)?; + + Ok(()) + } + // Mismatches + (InboundEntry::Message(_), InboundEntry::Proof(_)) => { + Err(Error::::ExpectedMessageType.into()) + } + (InboundEntry::Proof(_), InboundEntry::Message(_)) => { + Err(Error::::ExpectedMessageProofType.into()) + } + } + } } -/// Type used when processing inbound messages. +/// Type that holds information used when processing inbound messages. #[derive(Clone)] pub struct InboundProcessingInfo { pub domain_address: DomainAddress, @@ -42,6 +266,25 @@ pub struct InboundProcessingInfo { pub expected_proof_count_per_message: u32, } +impl TryFrom for InboundProcessingInfo { + type Error = DispatchError; + + fn try_from(domain_address: DomainAddress) -> Result { + let router_ids = Pallet::::get_router_ids_for_domain(domain_address.domain())?; + + let current_session_id = SessionIdStore::::get(); + + let expected_proof_count = Pallet::::get_expected_proof_count(&router_ids)?; + + Ok(InboundProcessingInfo { + domain_address, + router_ids, + current_session_id, + expected_proof_count_per_message: expected_proof_count, + }) + } +} + impl Pallet { /// Retrieves all stored routers and then filters them based /// on the available routers for the provided domain. @@ -93,123 +336,23 @@ impl Pallet { } } - /// Creates an inbound entry based on whether the inbound message is a - /// proof or not. - pub(crate) fn create_inbound_entry( - inbound_processing_info: &InboundProcessingInfo, - message: T::Message, - ) -> InboundEntry { - match message.get_message_proof() { - None => InboundEntry::Message { - session_id: inbound_processing_info.current_session_id.clone(), - domain_address: inbound_processing_info.domain_address.clone(), - message, - expected_proof_count: inbound_processing_info.expected_proof_count_per_message, - }, - Some(_) => InboundEntry::Proof { - session_id: inbound_processing_info.current_session_id, - current_count: 1, - }, - } - } - - /// Validation ensures that: - /// - /// - the router that sent the inbound message is a valid router for the - /// specific domain. - /// - messages are only sent by the first inbound router. - /// - proofs are not sent by the first inbound router. - pub(crate) fn validate_inbound_entry( - inbound_processing_info: &InboundProcessingInfo, - router_id: &T::RouterId, - inbound_entry: &InboundEntry, - ) -> DispatchResult { - let router_ids = inbound_processing_info.router_ids.clone(); - - ensure!( - router_ids.iter().any(|x| x == router_id), - Error::::UnknownRouter - ); - - match inbound_entry { - InboundEntry::Message { .. } => { - ensure!( - router_ids.get(0) == Some(&router_id), - Error::::MessageExpectedFromFirstRouter - ); - - Ok(()) - } - InboundEntry::Proof { .. } => { - ensure!( - router_ids.get(0) != Some(&router_id), - Error::::ProofNotExpectedFromFirstRouter - ); - - Ok(()) - } - } - } - /// Upserts an inbound entry for a particular message, increasing the /// relevant counts accordingly. pub(crate) fn upsert_pending_entry( message_proof: Proof, router_id: T::RouterId, - inbound_entry: InboundEntry, + new_inbound_entry: InboundEntry, ) -> DispatchResult { PendingInboundEntries::::try_mutate(message_proof, router_id, |storage_entry| { match storage_entry { None => { - *storage_entry = Some(inbound_entry); + *storage_entry = Some(new_inbound_entry); Ok::<(), DispatchError>(()) } - Some(stored_inbound_entry) => match stored_inbound_entry { - InboundEntry::Message { - session_id: stored_session_id, - expected_proof_count: stored_expected_proof_count, - .. - } => match inbound_entry { - InboundEntry::Message { - session_id: new_session_id, - expected_proof_count: new_expected_proof_count, - .. - } => { - if *stored_session_id != new_session_id { - *stored_session_id = new_session_id; - *stored_expected_proof_count = new_expected_proof_count; - } else { - stored_expected_proof_count - .ensure_add_assign(new_expected_proof_count)?; - } - - Ok::<(), DispatchError>(()) - } - InboundEntry::Proof { .. } => Err(Error::::ExpectedMessageType.into()), - }, - InboundEntry::Proof { - session_id: stored_session_id, - current_count: stored_current_count, - } => match inbound_entry { - InboundEntry::Proof { - session_id: new_session_id, - current_count: new_current_count, - } => { - if *stored_session_id != new_session_id { - *stored_session_id = new_session_id; - *stored_current_count = new_current_count; - } else { - stored_current_count.ensure_add_assign(new_current_count)?; - } - - Ok::<(), DispatchError>(()) - } - InboundEntry::Message { .. } => { - Err(Error::::ExpectedMessageProofType.into()) - } - }, - }, + Some(stored_inbound_entry) => { + stored_inbound_entry.pre_dispatch_update(new_inbound_entry) + } } }) } @@ -221,9 +364,9 @@ impl Pallet { message_proof: Proof, router_id: T::RouterId, ) -> DispatchResult { - let inbound_entry = Self::create_inbound_entry(inbound_processing_info, message); + let inbound_entry: InboundEntry = (inbound_processing_info, message).into(); - Self::validate_inbound_entry(&inbound_processing_info, &router_id, &inbound_entry)?; + inbound_entry.validate(&inbound_processing_info, &router_id)?; Self::upsert_pending_entry(message_proof, router_id, inbound_entry)?; @@ -246,20 +389,11 @@ impl Pallet { // we can return. None => return Ok(()), Some(stored_inbound_entry) => match stored_inbound_entry { - InboundEntry::Message { - message: stored_message, - .. - } => message = Some(stored_message), - InboundEntry::Proof { - session_id, - current_count, - } => { - if session_id != inbound_processing_info.current_session_id { - // Don't count vote from invalid sessions. - continue; - } - - if current_count > 0 { + InboundEntry::Message(message_entry) => message = Some(message_entry.message), + InboundEntry::Proof(proof_entry) => { + if proof_entry + .has_valid_vote_for_session(inbound_processing_info.current_session_id) + { votes.ensure_add_assign(1)?; } } @@ -273,7 +407,7 @@ impl Pallet { match message { Some(msg) => { - Self::decrease_pending_entries_counts(&inbound_processing_info, message_proof)?; + Self::execute_post_voting_dispatch(&inbound_processing_info, message_proof)?; T::InboundMessageHandler::handle( inbound_processing_info.domain_address.clone(), @@ -286,94 +420,33 @@ impl Pallet { /// Decreases the counts for inbound entries and removes them if the /// counts reach 0. - pub(crate) fn decrease_pending_entries_counts( + pub(crate) fn execute_post_voting_dispatch( inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, ) -> DispatchResult { for router_id in &inbound_processing_info.router_ids { - match PendingInboundEntries::::try_mutate( - message_proof, - router_id, - |storage_entry| match storage_entry { - None => Err(Error::::PendingInboundEntryNotFound.into()), + PendingInboundEntries::::try_mutate(message_proof, router_id, |storage_entry| { + match storage_entry { + None => { + Err::<(), DispatchError>(Error::::PendingInboundEntryNotFound.into()) + } Some(stored_inbound_entry) => { - match stored_inbound_entry { - InboundEntry::Message { - session_id, - expected_proof_count, - .. - } => { - if *session_id != inbound_processing_info.current_session_id { - // Remove the storage entry completely. - *storage_entry = None; - - return Ok::<(), DispatchError>(()); - } - - let updated_count = (*expected_proof_count).ensure_sub( - inbound_processing_info.expected_proof_count_per_message, - )?; - - if updated_count == 0 { - *storage_entry = None; - } else { - *expected_proof_count = updated_count; - } - - Ok::<(), DispatchError>(()) - } - InboundEntry::Proof { - session_id, - current_count, - } => { - if *session_id != inbound_processing_info.current_session_id { - // Remove the storage entry completely. - *storage_entry = None; - - return Ok::<(), DispatchError>(()); - } - - let updated_count = (*current_count).ensure_sub(1)?; - - if updated_count == 0 { - *storage_entry = None; - } else { - *current_count = updated_count; - } - - Ok::<(), DispatchError>(()) - } - } + let post_dispatch_entry = InboundEntry::create_post_voting_entry( + &stored_inbound_entry, + &inbound_processing_info, + )?; + + *storage_entry = post_dispatch_entry; + + Ok(()) } - }, - ) { - Ok(()) => {} - Err(e) => return Err(e), - } + } + })?; } Ok(()) } - /// Retrieves the information required for processing an inbound - /// message. - pub(crate) fn get_inbound_processing_info( - domain_address: DomainAddress, - ) -> Result, DispatchError> { - let router_ids = Self::get_router_ids_for_domain(domain_address.domain())?; - - let current_session_id = SessionIdStore::::get(); - - let expected_proof_count = Self::get_expected_proof_count(&router_ids)?; - - Ok(InboundProcessingInfo { - domain_address, - router_ids, - current_session_id, - expected_proof_count_per_message: expected_proof_count, - }) - } - /// Iterates over a batch of messages and checks if the requirements for /// processing each message are met. pub(crate) fn process_inbound_message( @@ -383,11 +456,10 @@ impl Pallet { ) -> (DispatchResult, Weight) { let weight = LP_DEFENSIVE_WEIGHT; - let inbound_processing_info = - match Self::get_inbound_processing_info(domain_address.clone()) { - Ok(i) => i, - Err(e) => return (Err(e), weight), - }; + let inbound_processing_info = match domain_address.clone().try_into() { + Ok(i) => i, + Err(e) => return (Err(e), weight), + }; let mut count = 0; diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 31e16eeac9..4f8fd21b17 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -3580,7 +3580,7 @@ mod implementations { }; assert_noop!( - LiquidityPoolsGateway::decrease_pending_entries_counts( + LiquidityPoolsGateway::execute_post_voting_dispatch( &inbound_processing_info, MESSAGE_PROOF ), @@ -3611,7 +3611,7 @@ mod implementations { }, ); - assert_ok!(LiquidityPoolsGateway::decrease_pending_entries_counts( + assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( &inbound_processing_info, MESSAGE_PROOF )); @@ -3640,7 +3640,7 @@ mod implementations { }, ); - assert_ok!(LiquidityPoolsGateway::decrease_pending_entries_counts( + assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( &inbound_processing_info, MESSAGE_PROOF )); From 5d21ccb35d1ad0f3761b5f48db009d7720814f9d Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Wed, 14 Aug 2024 21:33:48 +0300 Subject: [PATCH 24/38] lp-gateway: Use safe math --- pallets/liquidity-pools-gateway/src/lib.rs | 3 ++- pallets/liquidity-pools-gateway/src/message_processing.rs | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index f8e3d4e124..2f8fdfe8f9 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -41,6 +41,7 @@ use orml_traits::GetByKey; pub use pallet::*; use parity_scale_codec::FullCodec; use sp_arithmetic::traits::{BaseArithmetic, EnsureAddAssign, One}; +use sp_runtime::SaturatedConversion; use sp_std::convert::TryInto; use crate::{ @@ -532,7 +533,7 @@ pub mod pallet { fn max_processing_weight(msg: &Self::Message) -> Weight { match msg { GatewayMessage::Inbound { message, .. } => { - LP_DEFENSIVE_WEIGHT.saturating_mul(message.submessages().len() as u64) + LP_DEFENSIVE_WEIGHT.saturating_mul(message.submessages().len().saturated_into()) } GatewayMessage::Outbound { .. } => LP_DEFENSIVE_WEIGHT, } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index bac20f3e1c..f2e86e6e78 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -10,7 +10,7 @@ use frame_support::{ weights::Weight, }; use parity_scale_codec::MaxEncodedLen; -use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub}; +use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub, SaturatedConversion}; use sp_runtime::DispatchError; use crate::{ @@ -34,7 +34,8 @@ pub struct MessageEntry { /// message. /// /// NOTE - this gets increased by the `expected_proof_count` for a set of - /// routers (see `get_expected_proof_count`) every time a new identical message is submitted. + /// routers (see `get_expected_proof_count`) every time a new identical + /// message is submitted. pub expected_proof_count: u32, } @@ -322,7 +323,7 @@ impl Pallet { .ensure_sub(1) .map_err(|_| Error::::NotEnoughRoutersForDomain)?; - Ok(expected_proof_count as u32) + Ok(expected_proof_count.saturated_into()) } /// Gets the message proof for a message. From ab2806702b387f216524bb4617b1ecb90acbc52e Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Wed, 14 Aug 2024 23:06:25 +0300 Subject: [PATCH 25/38] lp-gateway: Add more unit tests --- pallets/liquidity-pools-gateway/src/tests.rs | 1834 ++++++++++++------ 1 file changed, 1289 insertions(+), 545 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 4f8fd21b17..dafcaf4936 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -1,12 +1,14 @@ use std::collections::HashMap; use cfg_primitives::LP_DEFENSIVE_WEIGHT; -use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler}; +use cfg_traits::liquidity_pools::{ + LPEncoding, MessageProcessor, MessageReceiver, OutboundMessageHandler, +}; use cfg_types::domain_address::*; use frame_support::{assert_err, assert_noop, assert_ok}; use itertools::Itertools; use lazy_static::lazy_static; -use sp_arithmetic::ArithmeticError::Overflow; +use sp_arithmetic::ArithmeticError::{Overflow, Underflow}; use sp_core::{bounded::BoundedVec, crypto::AccountId32, ByteArray, H160}; use sp_runtime::{ DispatchError, @@ -23,7 +25,7 @@ use super::{ pallet::*, }; use crate::{ - message_processing::{InboundEntry, InboundProcessingInfo}, + message_processing::{InboundEntry, InboundProcessingInfo, MessageEntry, ProofEntry}, GatewayMessage, }; @@ -679,12 +681,12 @@ mod extrinsics { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, - InboundEntry::::Message { + InboundEntry::Message(MessageEntry { session_id, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, - }, + }), ); let handler = @@ -731,12 +733,12 @@ mod extrinsics { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, - InboundEntry::::Message { + InboundEntry::Message(MessageEntry { session_id, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, - }, + }), ); assert_ok!(LiquidityPoolsGateway::execute_message_recovery( @@ -753,19 +755,25 @@ mod extrinsics { assert_eq!( PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1), - Some(InboundEntry::::Message { - session_id, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }) + Some( + MessageEntry { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into() + ) ); assert_eq!( PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_2), - Some(InboundEntry::::Proof { - session_id, - current_count: 1 - }) + Some( + ProofEntry { + session_id, + current_count: 1 + } + .into() + ) ); assert!(PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_3).is_none()) }); @@ -828,10 +836,10 @@ mod extrinsics { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_2, - InboundEntry::::Proof { + InboundEntry::Proof(ProofEntry { session_id, current_count: u32::MAX, - }, + }), ); assert_noop!( @@ -859,12 +867,12 @@ mod extrinsics { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_2, - InboundEntry::::Message { + InboundEntry::Message(MessageEntry { session_id, domain_address: domain_address.clone(), message: Message::Simple, expected_proof_count: 2, - }, + }), ); assert_noop!( @@ -1248,10 +1256,10 @@ mod implementations { PendingInboundEntries::::insert( message_proof, router_id, - InboundEntry::::Proof { + InboundEntry::Proof(ProofEntry { session_id, current_count: 0, - }, + }), ); let (res, _) = LiquidityPoolsGateway::process(gateway_message); @@ -1292,12 +1300,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1314,10 +1325,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -1381,12 +1395,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 3, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 3, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1404,10 +1421,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 3, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 3, + } + .into(), + ), ), ], }, @@ -1423,12 +1443,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 1, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1445,12 +1468,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 1, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1468,10 +1494,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -1487,12 +1516,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 1, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1510,10 +1542,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -1530,10 +1565,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -1572,12 +1610,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1596,10 +1637,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 4, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 4, + } + .into(), + ), ), ], }, @@ -1616,12 +1660,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1639,12 +1686,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1662,12 +1712,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1685,12 +1738,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ], @@ -1799,10 +1855,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -1820,10 +1879,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -1841,10 +1903,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -1862,10 +1927,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -1963,12 +2031,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), (ROUTER_ID_2, None), (ROUTER_ID_3, None), @@ -1986,10 +2057,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2007,10 +2081,13 @@ mod implementations { (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -2026,17 +2103,23 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2052,17 +2135,23 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2077,19 +2166,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2105,20 +2200,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2133,20 +2234,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2161,19 +2268,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2189,20 +2302,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2240,12 +2359,15 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 6, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 6, + } + .into(), + ), ), (ROUTER_ID_2, None), (ROUTER_ID_3, None), @@ -2264,10 +2386,13 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 3, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 3, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2286,10 +2411,13 @@ mod implementations { (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 3, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 3, + } + .into(), + ), ), ], }, @@ -2305,19 +2433,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2334,19 +2468,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2363,19 +2503,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2392,20 +2538,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -2421,20 +2573,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -2450,20 +2608,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -2479,19 +2643,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2508,19 +2678,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 2, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2537,20 +2713,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2566,19 +2748,25 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), (ROUTER_ID_3, None), ], @@ -2595,20 +2783,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2624,20 +2818,26 @@ mod implementations { expected_storage_entries: vec![ ( ROUTER_ID_1, - Some(InboundEntry::::Message { - session_id: TEST_SESSION_ID, - domain_address: TEST_DOMAIN_ADDRESS, - message: Message::Simple, - expected_proof_count: 4, - }), + Some( + MessageEntry { + session_id: TEST_SESSION_ID, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + } + .into(), + ), ), (ROUTER_ID_2, None), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2744,17 +2944,23 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2771,17 +2977,23 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2798,19 +3010,25 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), - ), - ], + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), + ), + ], }, ), ( @@ -2825,17 +3043,23 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -2852,17 +3076,23 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ], }, @@ -2879,17 +3109,23 @@ mod implementations { (ROUTER_ID_1, None), ( ROUTER_ID_2, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 1, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 1, + } + .into(), + ), ), ( ROUTER_ID_3, - Some(InboundEntry::::Proof { - session_id: TEST_SESSION_ID, - current_count: 2, - }), + Some( + ProofEntry { + session_id: TEST_SESSION_ID, + current_count: 2, + } + .into(), + ), ), ], }, @@ -2908,6 +3144,57 @@ mod implementations { } } + #[test] + fn same_message_multiple_domain_addresses() { + new_test_ext().execute_with(|| { + let message = Message::Simple; + + let first_message = GatewayMessage::Inbound { + domain_address: DomainAddress::EVM(1, [1; 20]), + message: message.clone(), + router_id: ROUTER_ID_1, + }; + + let second_message = GatewayMessage::Inbound { + domain_address: DomainAddress::EVM(2, [2; 20]), + message, + router_id: ROUTER_ID_1, + }; + + Routers::::set( + BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), + ); + + let (res, _) = LiquidityPoolsGateway::process(first_message); + assert_ok!(res); + + let expected_inbound_entry = InboundEntry::Message(MessageEntry { + session_id: 0, + domain_address: DomainAddress::EVM(1, [1; 20]), + message: Message::Simple, + expected_proof_count: 1, + }); + + let stored_inbound_entry = + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); + assert_eq!(stored_inbound_entry, expected_inbound_entry); + + let (res, _) = LiquidityPoolsGateway::process(second_message); + assert_ok!(res); + + let expected_inbound_entry = InboundEntry::Message(MessageEntry { + session_id: 0, + domain_address: DomainAddress::EVM(1, [1; 20]), + message: Message::Simple, + expected_proof_count: 2, + }); + + let stored_inbound_entry = + PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); + assert_eq!(stored_inbound_entry, expected_inbound_entry); + }); + } + #[test] fn inbound_message_handler_error() { new_test_ext().execute_with(|| { @@ -3117,31 +3404,31 @@ mod implementations { expected_proof_count_per_message: 2, }; - let tests = vec![ + let tests: Vec<(Message, InboundEntry)> = vec![ ( Message::Simple, - InboundEntry::::Message { + MessageEntry { session_id: inbound_processing_info.current_session_id, domain_address: inbound_processing_info.domain_address.clone(), message: Message::Simple, expected_proof_count: inbound_processing_info .expected_proof_count_per_message, - }, + } + .into(), ), ( Message::Proof(MESSAGE_PROOF), - InboundEntry::::Proof { + ProofEntry { session_id: inbound_processing_info.current_session_id, current_count: 1, - }, + } + .into(), ), ]; for (test_message, expected_inbound_entry) in tests { - let res = LiquidityPoolsGateway::create_inbound_entry( - &inbound_processing_info, - test_message, - ); + let res: InboundEntry = + (&inbound_processing_info, test_message).into(); assert_eq!(res, expected_inbound_entry) } @@ -3149,116 +3436,6 @@ mod implementations { } } - mod validate_inbound_entry { - use super::*; - - #[test] - fn success() { - new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; - - let inbound_entry = InboundEntry::::Message { - session_id: inbound_processing_info.current_session_id, - domain_address: inbound_processing_info.domain_address.clone(), - message: Message::Simple, - expected_proof_count: inbound_processing_info - .expected_proof_count_per_message, - }; - - assert_ok!(LiquidityPoolsGateway::validate_inbound_entry( - &inbound_processing_info, - &ROUTER_ID_1, - &inbound_entry - )); - - let inbound_entry = InboundEntry::::Proof { - session_id: inbound_processing_info.current_session_id, - current_count: 1, - }; - - assert_ok!(LiquidityPoolsGateway::validate_inbound_entry( - &inbound_processing_info, - &ROUTER_ID_2, - &inbound_entry - )); - }); - } - - #[test] - fn unknown_router() { - new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; - - let inbound_entry = InboundEntry::::Proof { - session_id: inbound_processing_info.current_session_id, - current_count: 1, - }; - - assert_noop!( - LiquidityPoolsGateway::validate_inbound_entry( - &inbound_processing_info, - &RouterId(4), - &inbound_entry - ), - Error::::UnknownRouter - ); - }); - } - - #[test] - fn message_type_mismatch() { - new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; - - let inbound_entry = InboundEntry::::Message { - session_id: inbound_processing_info.current_session_id, - domain_address: inbound_processing_info.domain_address.clone(), - message: Message::Simple, - expected_proof_count: inbound_processing_info - .expected_proof_count_per_message, - }; - - assert_noop!( - LiquidityPoolsGateway::validate_inbound_entry( - &inbound_processing_info, - &ROUTER_ID_2, - &inbound_entry - ), - Error::::MessageExpectedFromFirstRouter - ); - - let inbound_entry = InboundEntry::::Proof { - session_id: inbound_processing_info.current_session_id, - current_count: 1, - }; - - assert_noop!( - LiquidityPoolsGateway::validate_inbound_entry( - &inbound_processing_info, - &ROUTER_ID_1, - &inbound_entry - ), - Error::::ProofNotExpectedFromFirstRouter - ); - }); - } - } - mod upsert_pending_entry { use super::*; @@ -3272,23 +3449,25 @@ mod implementations { expected_proof_count_per_message: 2, }; - let tests = vec![ + let tests: Vec<(RouterId, InboundEntry)> = vec![ ( ROUTER_ID_1, - InboundEntry::::Message { + MessageEntry { session_id: inbound_processing_info.current_session_id, domain_address: inbound_processing_info.domain_address.clone(), message: Message::Simple, expected_proof_count: inbound_processing_info .expected_proof_count_per_message, - }, + } + .into(), ), ( ROUTER_ID_2, - InboundEntry::::Proof { + ProofEntry { session_id: inbound_processing_info.current_session_id, current_count: 1, - }, + } + .into(), ), ]; @@ -3311,12 +3490,13 @@ mod implementations { #[test] fn message_entry_same_session() { new_test_ext().execute_with(|| { - let inbound_entry = InboundEntry::::Message { + let inbound_entry: InboundEntry = MessageEntry { session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, - }; + } + .into(); PendingInboundEntries::::insert( MESSAGE_PROOF, @@ -3334,12 +3514,13 @@ mod implementations { PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); assert_eq!( res, - InboundEntry::::Message { + MessageEntry { session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 4, } + .into() ); }); } @@ -3350,35 +3531,37 @@ mod implementations { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, - InboundEntry::::Message { + InboundEntry::Message(MessageEntry { session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, - }, + }), ); assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, ROUTER_ID_1.clone(), - InboundEntry::::Message { + MessageEntry { session_id: 2, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, - }, + } + .into(), )); let res = PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); assert_eq!( res, - InboundEntry::::Message { + MessageEntry { session_id: 2, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, } + .into() ); }); } @@ -3386,12 +3569,13 @@ mod implementations { #[test] fn expected_message_type() { new_test_ext().execute_with(|| { - let inbound_entry = InboundEntry::::Message { + let inbound_entry: InboundEntry = MessageEntry { session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, - }; + } + .into(); PendingInboundEntries::::insert( MESSAGE_PROOF, @@ -3403,10 +3587,10 @@ mod implementations { LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, ROUTER_ID_1.clone(), - InboundEntry::Proof { + InboundEntry::Proof(ProofEntry { session_id: 1, current_count: 1 - }, + }), ), Error::::ExpectedMessageType ); @@ -3416,10 +3600,11 @@ mod implementations { #[test] fn proof_entry_same_session() { new_test_ext().execute_with(|| { - let inbound_entry = InboundEntry::::Proof { + let inbound_entry: InboundEntry = ProofEntry { session_id: 1, current_count: 1, - }; + } + .into(); PendingInboundEntries::::insert( MESSAGE_PROOF, @@ -3437,10 +3622,11 @@ mod implementations { PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); assert_eq!( res, - InboundEntry::::Proof { + ProofEntry { session_id: 1, current_count: 2, } + .into() ); }); } @@ -3451,29 +3637,31 @@ mod implementations { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, - InboundEntry::::Proof { + InboundEntry::Proof(ProofEntry { session_id: 1, current_count: 2, - }, + }), ); assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, ROUTER_ID_1.clone(), - InboundEntry::::Proof { + ProofEntry { session_id: 2, current_count: 1, - }, + } + .into(), )); let res = PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); assert_eq!( res, - InboundEntry::::Proof { + ProofEntry { session_id: 2, current_count: 1, } + .into() ); }); } @@ -3481,10 +3669,11 @@ mod implementations { #[test] fn expected_message_proof_type() { new_test_ext().execute_with(|| { - let inbound_entry = InboundEntry::::Proof { + let inbound_entry: InboundEntry = ProofEntry { session_id: 1, current_count: 1, - }; + } + .into(); PendingInboundEntries::::insert( MESSAGE_PROOF, @@ -3496,12 +3685,12 @@ mod implementations { LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, ROUTER_ID_1.clone(), - InboundEntry::Message { + InboundEntry::Message(MessageEntry { session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 1, - }, + }), ), Error::::ExpectedMessageProofType ); @@ -3525,28 +3714,28 @@ mod implementations { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, - InboundEntry::Message { + InboundEntry::Message(MessageEntry { session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: Message::Simple, expected_proof_count: 2, - }, + }), ); PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_2, - InboundEntry::Proof { + InboundEntry::Proof(ProofEntry { session_id: 2, current_count: 1, - }, + }), ); PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_3, - InboundEntry::Proof { + InboundEntry::Proof(ProofEntry { session_id: 3, current_count: 1, - }, + }), ); assert_ok!(LiquidityPoolsGateway::execute_if_requirements_are_met( @@ -3602,13 +3791,13 @@ mod implementations { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, - InboundEntry::Message { + InboundEntry::Message(MessageEntry { session_id: 1, domain_address: inbound_processing_info.domain_address.clone(), message: Message::Simple, expected_proof_count: inbound_processing_info .expected_proof_count_per_message, - }, + }), ); assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( @@ -3634,10 +3823,10 @@ mod implementations { PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, - InboundEntry::Proof { + InboundEntry::Proof(ProofEntry { session_id: 1, current_count: 1, - }, + }), ); assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( @@ -3652,3 +3841,558 @@ mod implementations { } } } + +mod inbound_entry { + use super::*; + + mod create_post_voting_entry { + use super::*; + + #[test] + fn message_entry_some() { + new_test_ext().execute_with(|| { + let session_id = 1; + let message = Message::Simple; + + let inbound_entry = InboundEntry::::Message(MessageEntry { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: message.clone(), + expected_proof_count: 4, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id, + expected_proof_count_per_message: 2, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ) + .unwrap(); + + assert_eq!( + res, + Some(InboundEntry::::Message(MessageEntry { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message, + expected_proof_count: 2, + })) + ); + }); + } + + #[test] + fn message_entry_session_change() { + new_test_ext().execute_with(|| { + let session_id = 1; + let message = Message::Simple; + + let inbound_entry = InboundEntry::::Message(MessageEntry { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: message.clone(), + expected_proof_count: 4, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id + 1, + expected_proof_count_per_message: 2, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ) + .unwrap(); + assert_eq!(res, None); + }); + } + + #[test] + fn message_entry_count_underflow() { + new_test_ext().execute_with(|| { + let session_id = 1; + let message = Message::Simple; + + let inbound_entry = InboundEntry::::Message(MessageEntry { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: message.clone(), + expected_proof_count: 2, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id, + expected_proof_count_per_message: 3, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ); + + assert_noop!(res, Arithmetic(Underflow)); + }); + } + + #[test] + fn message_entry_zero_updated_count() { + new_test_ext().execute_with(|| { + let session_id = 1; + let message = Message::Simple; + + let inbound_entry = InboundEntry::::Message(MessageEntry { + session_id, + domain_address: TEST_DOMAIN_ADDRESS, + message: message.clone(), + expected_proof_count: 2, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id, + expected_proof_count_per_message: 2, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ) + .unwrap(); + + assert_eq!(res, None); + }); + } + + #[test] + fn proof_entry_some() { + new_test_ext().execute_with(|| { + let session_id = 1; + + let inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 2, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id, + expected_proof_count_per_message: 2, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ) + .unwrap(); + + assert_eq!( + res, + Some(InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 1 + })) + ); + }); + } + + #[test] + fn proof_entry_session_change() { + new_test_ext().execute_with(|| { + let session_id = 1; + + let inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 2, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id + 1, + expected_proof_count_per_message: 2, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ) + .unwrap(); + + assert_eq!(res, None); + }); + } + + #[test] + fn proof_entry_count_underflow() { + new_test_ext().execute_with(|| { + let session_id = 1; + + let inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 0, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id, + expected_proof_count_per_message: 2, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ); + + assert_noop!(res, Arithmetic(Underflow),); + }); + } + + #[test] + fn proof_entry_zero_updated_count() { + new_test_ext().execute_with(|| { + let session_id = 1; + + let inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 1, + }); + + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![], + current_session_id: session_id, + expected_proof_count_per_message: 2, + }; + + let res = InboundEntry::create_post_voting_entry( + &inbound_entry, + &inbound_processing_info, + ) + .unwrap(); + + assert_eq!(res, None,); + }); + } + } + + mod validate { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; + + let inbound_entry = InboundEntry::Message(MessageEntry { + session_id: inbound_processing_info.current_session_id, + domain_address: inbound_processing_info.domain_address.clone(), + message: Message::Simple, + expected_proof_count: inbound_processing_info.expected_proof_count_per_message, + }); + + assert_ok!(inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_1)); + + let inbound_entry = InboundEntry::Proof(ProofEntry { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }); + + assert_ok!(inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_2)); + }); + } + + #[test] + fn unknown_router() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; + + let inbound_entry = InboundEntry::Proof(ProofEntry { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }); + + assert_noop!( + inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_3), + Error::::UnknownRouter + ); + }); + } + + #[test] + fn message_type_mismatch() { + new_test_ext().execute_with(|| { + let inbound_processing_info = InboundProcessingInfo:: { + domain_address: TEST_DOMAIN_ADDRESS, + router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], + current_session_id: 1, + expected_proof_count_per_message: 2, + }; + + let inbound_entry = InboundEntry::Message(MessageEntry { + session_id: inbound_processing_info.current_session_id, + domain_address: inbound_processing_info.domain_address.clone(), + message: Message::Simple, + expected_proof_count: inbound_processing_info.expected_proof_count_per_message, + }); + + assert_noop!( + inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_2), + Error::::MessageExpectedFromFirstRouter + ); + + let inbound_entry = InboundEntry::Proof(ProofEntry { + session_id: inbound_processing_info.current_session_id, + current_count: 1, + }); + + assert_noop!( + inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_1), + Error::::ProofNotExpectedFromFirstRouter + ); + }); + } + } + + mod increment_proof_count { + use super::*; + + #[test] + fn success_same_session() { + new_test_ext().execute_with(|| { + let session_id = 1; + let mut inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 1, + }); + + assert_ok!(inbound_entry.increment_proof_count(session_id)); + assert_eq!( + inbound_entry, + InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 2, + }) + ); + }); + } + + #[test] + fn success_new_session() { + new_test_ext().execute_with(|| { + let session_id = 1; + let mut inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, + current_count: 1, + }); + + let new_session_id = session_id + 1; + + assert_ok!(inbound_entry.increment_proof_count(new_session_id)); + assert_eq!( + inbound_entry, + InboundEntry::::Proof(ProofEntry { + session_id: new_session_id, + current_count: 1, + }) + ); + }); + } + + #[test] + fn expected_message_proof_type() { + new_test_ext().execute_with(|| { + let mut inbound_entry = InboundEntry::::Message(MessageEntry { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 1, + }); + + assert_noop!( + inbound_entry.increment_proof_count(1), + Error::::ExpectedMessageProofType + ); + }); + } + } + + mod pre_dispatch_update { + use super::*; + + #[test] + fn message_success_same_session() { + new_test_ext().execute_with(|| { + let mut inbound_entry_1 = InboundEntry::::Message(MessageEntry { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }); + + let inbound_entry_2 = inbound_entry_1.clone(); + + assert_ok!(inbound_entry_1.pre_dispatch_update(inbound_entry_2)); + assert_eq!( + inbound_entry_1, + InboundEntry::::Message(MessageEntry { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 4, + }) + ) + }); + } + + #[test] + fn message_success_session_change() { + new_test_ext().execute_with(|| { + let mut inbound_entry_1 = InboundEntry::::Message(MessageEntry { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }); + + let inbound_entry_2 = InboundEntry::::Message(MessageEntry { + session_id: 2, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 5, + }); + + assert_ok!(inbound_entry_1.pre_dispatch_update(inbound_entry_2.clone())); + assert_eq!(inbound_entry_1, inbound_entry_2) + }); + } + + #[test] + fn proof_success_same_session() { + new_test_ext().execute_with(|| { + let mut inbound_entry_1 = InboundEntry::::Proof(ProofEntry { + session_id: 1, + current_count: 1, + }); + + let inbound_entry_2 = inbound_entry_1.clone(); + + assert_ok!(inbound_entry_1.pre_dispatch_update(inbound_entry_2)); + assert_eq!( + inbound_entry_1, + InboundEntry::::Proof(ProofEntry { + session_id: 1, + current_count: 2, + }) + ) + }); + } + + #[test] + fn proof_success_session_change() { + new_test_ext().execute_with(|| { + let mut inbound_entry_1 = InboundEntry::::Proof(ProofEntry { + session_id: 1, + current_count: 1, + }); + + let inbound_entry_2 = InboundEntry::::Proof(ProofEntry { + session_id: 2, + current_count: 3, + }); + + assert_ok!(inbound_entry_1.pre_dispatch_update(inbound_entry_2.clone())); + assert_eq!(inbound_entry_1, inbound_entry_2) + }); + } + + #[test] + fn mismatch_errors() { + new_test_ext().execute_with(|| { + let mut inbound_entry_1 = InboundEntry::::Message(MessageEntry { + session_id: 1, + domain_address: TEST_DOMAIN_ADDRESS, + message: Message::Simple, + expected_proof_count: 2, + }); + + let mut inbound_entry_2 = InboundEntry::::Proof(ProofEntry { + session_id: 1, + current_count: 1, + }); + + assert_noop!( + inbound_entry_1.pre_dispatch_update(inbound_entry_2.clone()), + Error::::ExpectedMessageType + ); + + assert_noop!( + inbound_entry_2.pre_dispatch_update(inbound_entry_1), + Error::::ExpectedMessageProofType + ); + }); + } + } +} + +mod inbound_processing_info { + use super::*; + + mod try_from_domain_address { + use super::*; + + #[test] + fn success() { + new_test_ext().execute_with(|| { + let router_ids = vec![ROUTER_ID_1, ROUTER_ID_2]; + let expected_proof_count = router_ids.len() - 1; + + Routers::::set(BoundedVec::try_from(router_ids.clone()).unwrap()); + + let res: InboundProcessingInfo = TEST_DOMAIN_ADDRESS.try_into().unwrap(); + assert_eq!(res.domain_address, TEST_DOMAIN_ADDRESS); + assert_eq!(res.router_ids, router_ids); + assert_eq!(res.current_session_id, 0); + assert_eq!( + res.expected_proof_count_per_message, + expected_proof_count as u32 + ); + }); + } + + #[test] + fn not_enough_routers_for_domain() { + new_test_ext().execute_with(|| { + let res: Result, DispatchError> = + TEST_DOMAIN_ADDRESS.try_into(); + + assert_eq!( + res.err().unwrap(), + Error::::NotEnoughRoutersForDomain.into() + ); + }); + } + } +} From c950614ea5809529fc7d93620c53bce0fafd1ec3 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:17:38 +0300 Subject: [PATCH 26/38] checks: Fix clippy, taplo, formatting --- pallets/axelar-router/src/lib.rs | 6 ++++++ pallets/liquidity-pools-gateway/Cargo.toml | 4 ++-- pallets/liquidity-pools-gateway/src/lib.rs | 2 +- .../src/message_processing.rs | 19 ++++++++++--------- pallets/liquidity-pools/Cargo.toml | 2 ++ pallets/liquidity-pools/src/message.rs | 5 +++-- runtime/altair/src/lib.rs | 2 +- runtime/centrifuge/src/lib.rs | 2 +- runtime/common/src/routing.rs | 6 ++++++ 9 files changed, 32 insertions(+), 16 deletions(-) diff --git a/pallets/axelar-router/src/lib.rs b/pallets/axelar-router/src/lib.rs index d18b96bd42..21abe3687f 100644 --- a/pallets/axelar-router/src/lib.rs +++ b/pallets/axelar-router/src/lib.rs @@ -62,6 +62,12 @@ pub enum AxelarId { Evm(EVMChainId), } +impl Default for AxelarId { + fn default() -> Self { + Self::Evm(1) + } +} + /// Configuration for outbound messages though axelar #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct AxelarConfig { diff --git a/pallets/liquidity-pools-gateway/Cargo.toml b/pallets/liquidity-pools-gateway/Cargo.toml index e2caa19652..ced29cdd71 100644 --- a/pallets/liquidity-pools-gateway/Cargo.toml +++ b/pallets/liquidity-pools-gateway/Cargo.toml @@ -19,10 +19,10 @@ hex = { workspace = true } orml-traits = { workspace = true } parity-scale-codec = { workspace = true } scale-info = { workspace = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } -sp-arithmetic = { workspace = true } # Benchmarking frame-benchmarking = { workspace = true, optional = true } @@ -35,10 +35,10 @@ cfg-utils = { workspace = true } [dev-dependencies] cfg-mocks = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } itertools = { workspace = true, default-features = true } lazy_static = { workspace = true, default-features = true } mock-builder = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } [features] default = ["std"] diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 2f8fdfe8f9..94899843bb 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -42,7 +42,7 @@ pub use pallet::*; use parity_scale_codec::FullCodec; use sp_arithmetic::traits::{BaseArithmetic, EnsureAddAssign, One}; use sp_runtime::SaturatedConversion; -use sp_std::convert::TryInto; +use sp_std::{convert::TryInto, vec::Vec}; use crate::{ message_processing::{InboundEntry, InboundProcessingInfo}, diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index f2e86e6e78..5ff8086e9e 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -12,6 +12,7 @@ use frame_support::{ use parity_scale_codec::MaxEncodedLen; use sp_arithmetic::traits::{EnsureAddAssign, EnsureSub, SaturatedConversion}; use sp_runtime::DispatchError; +use sp_std::vec::Vec; use crate::{ message::GatewayMessage, Config, Error, Pallet, PendingInboundEntries, Routers, SessionIdStore, @@ -74,7 +75,7 @@ impl From<(&InboundProcessingInfo, T::Message)> for InboundEntry, T::Message)) -> Self { match message.get_message_proof() { None => InboundEntry::Message(MessageEntry { - session_id: inbound_processing_info.current_session_id.clone(), + session_id: inbound_processing_info.current_session_id, domain_address: inbound_processing_info.domain_address.clone(), message, expected_proof_count: inbound_processing_info.expected_proof_count_per_message, @@ -174,7 +175,7 @@ impl InboundEntry { match self { InboundEntry::Message { .. } => { ensure!( - router_ids.get(0) == Some(&router_id), + router_ids.first() == Some(router_id), Error::::MessageExpectedFromFirstRouter ); @@ -182,7 +183,7 @@ impl InboundEntry { } InboundEntry::Proof { .. } => { ensure!( - router_ids.get(0) != Some(&router_id), + router_ids.first() != Some(router_id), Error::::ProofNotExpectedFromFirstRouter ); @@ -303,7 +304,7 @@ impl Pallet { .iter() .any(|available_router| *stored_router == available_router) }) - .map(|x| x.clone()) + .cloned() .collect::>(); if res.is_empty() { @@ -316,7 +317,7 @@ impl Pallet { /// Calculates and returns the proof count required for processing one /// inbound message. pub(crate) fn get_expected_proof_count( - router_ids: &Vec, + router_ids: &[T::RouterId], ) -> Result { let expected_proof_count = router_ids .len() @@ -367,7 +368,7 @@ impl Pallet { ) -> DispatchResult { let inbound_entry: InboundEntry = (inbound_processing_info, message).into(); - inbound_entry.validate(&inbound_processing_info, &router_id)?; + inbound_entry.validate(inbound_processing_info, &router_id)?; Self::upsert_pending_entry(message_proof, router_id, inbound_entry)?; @@ -408,7 +409,7 @@ impl Pallet { match message { Some(msg) => { - Self::execute_post_voting_dispatch(&inbound_processing_info, message_proof)?; + Self::execute_post_voting_dispatch(inbound_processing_info, message_proof)?; T::InboundMessageHandler::handle( inbound_processing_info.domain_address.clone(), @@ -433,8 +434,8 @@ impl Pallet { } Some(stored_inbound_entry) => { let post_dispatch_entry = InboundEntry::create_post_voting_entry( - &stored_inbound_entry, - &inbound_processing_info, + stored_inbound_entry, + inbound_processing_info, )?; *storage_entry = post_dispatch_entry; diff --git a/pallets/liquidity-pools/Cargo.toml b/pallets/liquidity-pools/Cargo.toml index 9b2bab88a5..62bec053f1 100644 --- a/pallets/liquidity-pools/Cargo.toml +++ b/pallets/liquidity-pools/Cargo.toml @@ -22,6 +22,7 @@ scale-info = { workspace = true } serde = { workspace = true } serde-big-array = { workspace = true } sp-core = { workspace = true } +sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } staging-xcm = { workspace = true } @@ -48,6 +49,7 @@ std = [ "frame-support/std", "frame-system/std", "sp-std/std", + "sp-io/std", "sp-runtime/std", "orml-traits/std", "staging-xcm/std", diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index fac0bed5e8..397b2da728 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -18,7 +18,8 @@ use serde::{ ser::{Error as _, SerializeTuple}, Deserialize, Serialize, Serializer, }; -use sp_core::{keccak_256, U256}; +use sp_core::U256; +use sp_io::hashing::keccak_256; use sp_runtime::{traits::ConstU32, DispatchError, DispatchResult}; use sp_std::{vec, vec::Vec}; @@ -564,7 +565,7 @@ impl LPEncoding for Message { fn get_message_proof(&self) -> Option { match self { - Message::MessageProof { hash } => Some(hash.clone()), + Message::MessageProof { hash } => Some(*hash), _ => None, } } diff --git a/runtime/altair/src/lib.rs b/runtime/altair/src/lib.rs index 68a80a4288..834333cae0 100644 --- a/runtime/altair/src/lib.rs +++ b/runtime/altair/src/lib.rs @@ -1781,7 +1781,7 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { } impl pallet_liquidity_pools_gateway_queue::Config for Runtime { - type Message = GatewayMessage; + type Message = GatewayMessage; type MessageNonce = LPGatewayQueueMessageNonce; type MessageProcessor = LiquidityPoolsGateway; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/centrifuge/src/lib.rs b/runtime/centrifuge/src/lib.rs index d64630fade..3cae0346fd 100644 --- a/runtime/centrifuge/src/lib.rs +++ b/runtime/centrifuge/src/lib.rs @@ -1880,7 +1880,7 @@ impl pallet_liquidity_pools_gateway::Config for Runtime { } impl pallet_liquidity_pools_gateway_queue::Config for Runtime { - type Message = GatewayMessage; + type Message = GatewayMessage; type MessageNonce = LPGatewayQueueMessageNonce; type MessageProcessor = LiquidityPoolsGateway; type RuntimeEvent = RuntimeEvent; diff --git a/runtime/common/src/routing.rs b/runtime/common/src/routing.rs index 90cc97b62f..ccea345f1a 100644 --- a/runtime/common/src/routing.rs +++ b/runtime/common/src/routing.rs @@ -23,6 +23,12 @@ pub enum RouterId { Axelar(AxelarId), } +impl Default for RouterId { + fn default() -> Self { + Self::Axelar(AxelarId::default()) + } +} + impl From for RouterId { fn from(axelar_id: AxelarId) -> Self { RouterId::Axelar(axelar_id) From e7674817d967d6e14f111a9c21296103100d3c25 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:04:45 +0300 Subject: [PATCH 27/38] review: Remove mock-builder dep, rename LP encoding proof methods --- Cargo.lock | 1 - libs/traits/src/liquidity_pools.rs | 6 +- pallets/liquidity-pools-gateway/Cargo.toml | 1 - .../src/message_processing.rs | 10 +-- pallets/liquidity-pools-gateway/src/mock.rs | 4 +- pallets/liquidity-pools-gateway/src/tests.rs | 61 ++----------------- pallets/liquidity-pools/src/message.rs | 4 +- 7 files changed, 16 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12681bcd7e..8f8b2d2768 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8244,7 +8244,6 @@ dependencies = [ "hex", "itertools 0.13.0", "lazy_static", - "mock-builder", "orml-traits", "parity-scale-codec", "scale-info", diff --git a/libs/traits/src/liquidity_pools.rs b/libs/traits/src/liquidity_pools.rs index 1eefd5510f..d79a1f5523 100644 --- a/libs/traits/src/liquidity_pools.rs +++ b/libs/traits/src/liquidity_pools.rs @@ -34,11 +34,11 @@ pub trait LPEncoding: Sized { /// It's the identity message for composing messages with pack_with fn empty() -> Self; - /// Retrieves the message proof, if any. - fn get_message_proof(&self) -> Option; + /// Retrieves the message proof hash, if the message is a proof type. + fn proof_hash(&self) -> Option; /// Converts the message into a message proof type. - fn to_message_proof(&self) -> Self; + fn proof_message(&self) -> Self; } pub trait RouterProvider: Sized { diff --git a/pallets/liquidity-pools-gateway/Cargo.toml b/pallets/liquidity-pools-gateway/Cargo.toml index ced29cdd71..14c3f2c8eb 100644 --- a/pallets/liquidity-pools-gateway/Cargo.toml +++ b/pallets/liquidity-pools-gateway/Cargo.toml @@ -37,7 +37,6 @@ cfg-utils = { workspace = true } cfg-mocks = { workspace = true, default-features = true } itertools = { workspace = true, default-features = true } lazy_static = { workspace = true, default-features = true } -mock-builder = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } [features] diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 5ff8086e9e..04584ac15b 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -73,7 +73,7 @@ pub enum InboundEntry { impl From<(&InboundProcessingInfo, T::Message)> for InboundEntry { fn from((inbound_processing_info, message): (&InboundProcessingInfo, T::Message)) -> Self { - match message.get_message_proof() { + match message.proof_hash() { None => InboundEntry::Message(MessageEntry { session_id: inbound_processing_info.current_session_id, domain_address: inbound_processing_info.domain_address.clone(), @@ -329,10 +329,10 @@ impl Pallet { /// Gets the message proof for a message. pub(crate) fn get_message_proof(message: T::Message) -> Proof { - match message.get_message_proof() { + match message.proof_hash() { None => message - .to_message_proof() - .get_message_proof() + .proof_message() + .proof_hash() .expect("message proof ensured by 'to_message_proof'"), Some(proof) => proof, } @@ -513,7 +513,7 @@ impl Pallet { ) -> DispatchResult { let router_ids = Self::get_router_ids_for_domain(destination)?; - let message_proof = message.to_message_proof(); + let message_proof = message.proof_message(); let mut message_opt = Some(message); for router_id in router_ids { diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 0187e6d8a4..58e7eb35f3 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -98,14 +98,14 @@ impl LPEncoding for Message { Self::Pack(vec![]) } - fn get_message_proof(&self) -> Option { + fn proof_hash(&self) -> Option { match self { Message::Proof(p) => Some(p.clone()), _ => None, } } - fn to_message_proof(&self) -> Self { + fn proof_message(&self) -> Self { match self { Message::Proof(_) => self.clone(), _ => Message::Proof(MESSAGE_PROOF), diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index dafcaf4936..68fd4d94e1 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -1,9 +1,7 @@ use std::collections::HashMap; use cfg_primitives::LP_DEFENSIVE_WEIGHT; -use cfg_traits::liquidity_pools::{ - LPEncoding, MessageProcessor, MessageReceiver, OutboundMessageHandler, -}; +use cfg_traits::liquidity_pools::{LPEncoding, MessageProcessor, OutboundMessageHandler}; use cfg_types::domain_address::*; use frame_support::{assert_err, assert_noop, assert_ok}; use itertools::Itertools; @@ -901,7 +899,7 @@ mod implementations { let domain = Domain::EVM(0); let sender = get_test_account_id(); let msg = Message::Simple; - let message_proof = msg.to_message_proof().get_message_proof().unwrap(); + let message_proof = msg.proof_message().proof_hash().unwrap(); assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), @@ -1158,7 +1156,7 @@ mod implementations { fn success() { new_test_ext().execute_with(|| { let message = Message::Simple; - let message_proof = message.to_message_proof().get_message_proof().unwrap(); + let message_proof = message.proof_message().proof_hash().unwrap(); let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); let router_id = ROUTER_ID_1; @@ -1239,7 +1237,7 @@ mod implementations { fn expected_message_proof_type() { new_test_ext().execute_with(|| { let message = Message::Simple; - let message_proof = message.to_message_proof().get_message_proof().unwrap(); + let message_proof = message.proof_message().proof_hash().unwrap(); let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); let router_id = ROUTER_ID_1; @@ -3144,57 +3142,6 @@ mod implementations { } } - #[test] - fn same_message_multiple_domain_addresses() { - new_test_ext().execute_with(|| { - let message = Message::Simple; - - let first_message = GatewayMessage::Inbound { - domain_address: DomainAddress::EVM(1, [1; 20]), - message: message.clone(), - router_id: ROUTER_ID_1, - }; - - let second_message = GatewayMessage::Inbound { - domain_address: DomainAddress::EVM(2, [2; 20]), - message, - router_id: ROUTER_ID_1, - }; - - Routers::::set( - BoundedVec::try_from(vec![ROUTER_ID_1, ROUTER_ID_2]).unwrap(), - ); - - let (res, _) = LiquidityPoolsGateway::process(first_message); - assert_ok!(res); - - let expected_inbound_entry = InboundEntry::Message(MessageEntry { - session_id: 0, - domain_address: DomainAddress::EVM(1, [1; 20]), - message: Message::Simple, - expected_proof_count: 1, - }); - - let stored_inbound_entry = - PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); - assert_eq!(stored_inbound_entry, expected_inbound_entry); - - let (res, _) = LiquidityPoolsGateway::process(second_message); - assert_ok!(res); - - let expected_inbound_entry = InboundEntry::Message(MessageEntry { - session_id: 0, - domain_address: DomainAddress::EVM(1, [1; 20]), - message: Message::Simple, - expected_proof_count: 2, - }); - - let stored_inbound_entry = - PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).unwrap(); - assert_eq!(stored_inbound_entry, expected_inbound_entry); - }); - } - #[test] fn inbound_message_handler_error() { new_test_ext().execute_with(|| { diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index 397b2da728..a68cbe72ee 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -563,14 +563,14 @@ impl LPEncoding for Message { Message::Batch(BatchMessages::default()) } - fn get_message_proof(&self) -> Option { + fn proof_hash(&self) -> Option { match self { Message::MessageProof { hash } => Some(*hash), _ => None, } } - fn to_message_proof(&self) -> Self { + fn proof_message(&self) -> Self { let hash = keccak_256(&LPEncoding::serialize(self)); Message::MessageProof { hash } From 8af5c43bdd230f9737c7d6ac602afd2781242f60 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:10:03 +0300 Subject: [PATCH 28/38] lp-gateway: Remove Default impls for RouterId and GatewayMessage --- pallets/liquidity-pools-gateway/queue/src/lib.rs | 2 +- pallets/liquidity-pools-gateway/src/lib.rs | 2 +- pallets/liquidity-pools-gateway/src/message.rs | 10 ---------- pallets/liquidity-pools-gateway/src/mock.rs | 3 +-- runtime/common/src/routing.rs | 6 ------ 5 files changed, 3 insertions(+), 20 deletions(-) diff --git a/pallets/liquidity-pools-gateway/queue/src/lib.rs b/pallets/liquidity-pools-gateway/queue/src/lib.rs index 57c5817e17..f473c20b42 100644 --- a/pallets/liquidity-pools-gateway/queue/src/lib.rs +++ b/pallets/liquidity-pools-gateway/queue/src/lib.rs @@ -38,7 +38,7 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The message type. - type Message: Clone + Debug + PartialEq + MaxEncodedLen + TypeInfo + FullCodec + Default; + type Message: Clone + Debug + PartialEq + MaxEncodedLen + TypeInfo + FullCodec; /// Type used for message identification. type MessageNonce: Parameter diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 94899843bb..9abcd04460 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -111,7 +111,7 @@ pub mod pallet { type MessageSender: MessageSender; /// An identification of a router - type RouterId: Parameter + Default + MaxEncodedLen; + type RouterId: Parameter + MaxEncodedLen; /// The type that provides the router available for a domain. type RouterProvider: RouterProvider; diff --git a/pallets/liquidity-pools-gateway/src/message.rs b/pallets/liquidity-pools-gateway/src/message.rs index 0c6707814b..1c604f5d0d 100644 --- a/pallets/liquidity-pools-gateway/src/message.rs +++ b/pallets/liquidity-pools-gateway/src/message.rs @@ -15,13 +15,3 @@ pub enum GatewayMessage { router_id: RouterId, }, } - -impl Default for GatewayMessage { - fn default() -> Self { - GatewayMessage::Inbound { - domain_address: Default::default(), - message: Default::default(), - router_id: Default::default(), - } - } -} diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 58e7eb35f3..18eca2f97e 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -30,9 +30,8 @@ pub const MAX_PACKED_MESSAGES: usize = 10; pub const MESSAGE_PROOF: [u8; 32] = [1; 32]; -#[derive(Default, Eq, PartialEq, Clone, Encode, Decode, TypeInfo, Hash)] +#[derive(Eq, PartialEq, Clone, Encode, Decode, TypeInfo, Hash)] pub enum Message { - #[default] Simple, Pack(Vec), Proof([u8; 32]), diff --git a/runtime/common/src/routing.rs b/runtime/common/src/routing.rs index ccea345f1a..90cc97b62f 100644 --- a/runtime/common/src/routing.rs +++ b/runtime/common/src/routing.rs @@ -23,12 +23,6 @@ pub enum RouterId { Axelar(AxelarId), } -impl Default for RouterId { - fn default() -> Self { - Self::Axelar(AxelarId::default()) - } -} - impl From for RouterId { fn from(axelar_id: AxelarId) -> Self { RouterId::Axelar(axelar_id) From 92933414b9893b292c31d45fd6dc1a3a42c48b20 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:26:55 +0300 Subject: [PATCH 29/38] lp-gateway: Allow empty list of routers --- pallets/liquidity-pools-gateway/src/lib.rs | 5 ----- pallets/liquidity-pools-gateway/src/tests.rs | 13 ------------- 2 files changed, 18 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 9abcd04460..73752c1810 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -249,9 +249,6 @@ pub mod pallet { /// was not started by `start_batch_message()`. MessagePackingNotStarted, - /// Invalid routers. - InvalidRouters, - /// Unknown router. UnknownRouter, @@ -298,8 +295,6 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - ensure!(router_ids.len() > 0, Error::::InvalidRouters); - >::set(router_ids.clone()); let new_session_id = SessionIdStore::::try_mutate(|n| { diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 68fd4d94e1..a618cc5331 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -111,19 +111,6 @@ mod extrinsics { }); } - #[test] - fn invalid_routers() { - new_test_ext().execute_with(|| { - assert_noop!( - LiquidityPoolsGateway::set_routers( - RuntimeOrigin::root(), - BoundedVec::try_from(vec![]).unwrap(), - ), - Error::::InvalidRouters - ); - }); - } - #[test] fn session_id_overflow() { new_test_ext().execute_with(|| { From c510b9dd306bf39ff0761979a8229df37b07f8e4 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:28:24 +0300 Subject: [PATCH 30/38] lp-gateway: Drop InboundProcessingInfo --- pallets/liquidity-pools-gateway/src/lib.rs | 37 +- .../src/message_processing.rs | 176 +++++----- pallets/liquidity-pools-gateway/src/tests.rs | 324 +++++++----------- 3 files changed, 221 insertions(+), 316 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index 73752c1810..bee1bbd624 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -44,10 +44,7 @@ use sp_arithmetic::traits::{BaseArithmetic, EnsureAddAssign, One}; use sp_runtime::SaturatedConversion; use sp_std::{convert::TryInto, vec::Vec}; -use crate::{ - message_processing::{InboundEntry, InboundProcessingInfo}, - weights::WeightInfo, -}; +use crate::{message_processing::InboundEntry, weights::WeightInfo}; mod origin; pub use origin::*; @@ -439,28 +436,26 @@ pub mod pallet { ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - let inbound_processing_info: InboundProcessingInfo = domain_address.try_into()?; + let router_ids = Self::get_router_ids_for_domain(domain_address.domain())?; ensure!( - inbound_processing_info - .router_ids - .iter() - .any(|x| x == &router_id), + router_ids.iter().any(|x| x == &router_id), Error::::UnknownRouter ); + // Message recovery shouldn't be supported for setups that have less than 1 + // router since no proofs are required in that case. + ensure!(router_ids.len() > 1, Error::::NotEnoughRoutersForDomain); - ensure!( - inbound_processing_info.router_ids.len() > 1, - Error::::NotEnoughRoutersForDomain - ); + let session_id = SessionIdStore::::get(); PendingInboundEntries::::try_mutate(proof, router_id.clone(), |storage_entry| { match storage_entry { - Some(stored_inbound_entry) => stored_inbound_entry - .increment_proof_count(inbound_processing_info.current_session_id), + Some(stored_inbound_entry) => { + stored_inbound_entry.increment_proof_count(session_id) + } None => { *storage_entry = Some(InboundEntry::::Proof(ProofEntry { - session_id: inbound_processing_info.current_session_id, + session_id, current_count: 1, })); @@ -469,7 +464,15 @@ pub mod pallet { } })?; - Self::execute_if_requirements_are_met(&inbound_processing_info, proof)?; + let expected_proof_count = Self::get_expected_proof_count(&router_ids)?; + + Self::execute_if_requirements_are_met( + proof, + &router_ids, + session_id, + expected_proof_count, + domain_address, + )?; Self::deposit_event(Event::::MessageRecoveryExecuted { proof, router_id }); diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 04584ac15b..9c806bca0e 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -71,23 +71,6 @@ pub enum InboundEntry { Proof(ProofEntry), } -impl From<(&InboundProcessingInfo, T::Message)> for InboundEntry { - fn from((inbound_processing_info, message): (&InboundProcessingInfo, T::Message)) -> Self { - match message.proof_hash() { - None => InboundEntry::Message(MessageEntry { - session_id: inbound_processing_info.current_session_id, - domain_address: inbound_processing_info.domain_address.clone(), - message, - expected_proof_count: inbound_processing_info.expected_proof_count_per_message, - }), - Some(_) => InboundEntry::Proof(ProofEntry { - session_id: inbound_processing_info.current_session_id, - current_count: 1, - }), - } - } -} - impl From> for InboundEntry { fn from(message_entry: MessageEntry) -> Self { Self::Message(message_entry) @@ -101,6 +84,27 @@ impl From> for InboundEntry { } impl InboundEntry { + /// Creates an inbound entry based on the type of message. + pub fn create( + message: T::Message, + session_id: T::SessionId, + domain_address: DomainAddress, + expected_proof_count: u32, + ) -> Self { + match message.proof_hash() { + None => InboundEntry::Message(MessageEntry { + session_id, + domain_address, + message, + expected_proof_count, + }), + Some(_) => InboundEntry::Proof(ProofEntry { + session_id, + current_count: 1, + }), + } + } + /// Creates a new `InboundEntry` based on the information provided. /// /// If a session change is detected or if the updated counts reach 0, it @@ -108,17 +112,18 @@ impl InboundEntry { /// decreased accordingly, based on the entry type. pub fn create_post_voting_entry( inbound_entry: &InboundEntry, - inbound_processing_info: &InboundProcessingInfo, + session_id: T::SessionId, + expected_proof_count: u32, ) -> Result, DispatchError> { match inbound_entry { InboundEntry::Message(message_entry) => { - if message_entry.session_id != inbound_processing_info.current_session_id { + if message_entry.session_id != session_id { return Ok(None); } let updated_count = message_entry .expected_proof_count - .ensure_sub(inbound_processing_info.expected_proof_count_per_message)?; + .ensure_sub(expected_proof_count)?; if updated_count == 0 { return Ok(None); @@ -133,7 +138,7 @@ impl InboundEntry { )) } InboundEntry::Proof(proof_entry) => { - if proof_entry.session_id != inbound_processing_info.current_session_id { + if proof_entry.session_id != session_id { return Ok(None); } @@ -160,13 +165,7 @@ impl InboundEntry { /// specific domain. /// - messages are only sent by the first inbound router. /// - proofs are not sent by the first inbound router. - pub fn validate( - &self, - inbound_processing_info: &InboundProcessingInfo, - router_id: &T::RouterId, - ) -> DispatchResult { - let router_ids = inbound_processing_info.router_ids.clone(); - + pub fn validate(&self, router_ids: &[T::RouterId], router_id: &T::RouterId) -> DispatchResult { ensure!( router_ids.iter().any(|x| x == router_id), Error::::UnknownRouter @@ -259,34 +258,6 @@ impl InboundEntry { } } -/// Type that holds information used when processing inbound messages. -#[derive(Clone)] -pub struct InboundProcessingInfo { - pub domain_address: DomainAddress, - pub router_ids: Vec, - pub current_session_id: T::SessionId, - pub expected_proof_count_per_message: u32, -} - -impl TryFrom for InboundProcessingInfo { - type Error = DispatchError; - - fn try_from(domain_address: DomainAddress) -> Result { - let router_ids = Pallet::::get_router_ids_for_domain(domain_address.domain())?; - - let current_session_id = SessionIdStore::::get(); - - let expected_proof_count = Pallet::::get_expected_proof_count(&router_ids)?; - - Ok(InboundProcessingInfo { - domain_address, - router_ids, - current_session_id, - expected_proof_count_per_message: expected_proof_count, - }) - } -} - impl Pallet { /// Retrieves all stored routers and then filters them based /// on the available routers for the provided domain. @@ -342,7 +313,7 @@ impl Pallet { /// relevant counts accordingly. pub(crate) fn upsert_pending_entry( message_proof: Proof, - router_id: T::RouterId, + router_id: &T::RouterId, new_inbound_entry: InboundEntry, ) -> DispatchResult { PendingInboundEntries::::try_mutate(message_proof, router_id, |storage_entry| { @@ -359,33 +330,20 @@ impl Pallet { }) } - /// Creates, validates and upserts the inbound entry. - fn validate_and_upsert_pending_entries( - inbound_processing_info: &InboundProcessingInfo, - message: T::Message, - message_proof: Proof, - router_id: T::RouterId, - ) -> DispatchResult { - let inbound_entry: InboundEntry = (inbound_processing_info, message).into(); - - inbound_entry.validate(inbound_processing_info, &router_id)?; - - Self::upsert_pending_entry(message_proof, router_id, inbound_entry)?; - - Ok(()) - } - /// Checks if the number of proofs required for executing one message /// were received, and if so, decreases the counts accordingly and executes /// the message. pub(crate) fn execute_if_requirements_are_met( - inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, + router_ids: &[T::RouterId], + session_id: T::SessionId, + expected_proof_count: u32, + domain_address: DomainAddress, ) -> DispatchResult { let mut message = None; let mut votes = 0; - for router_id in &inbound_processing_info.router_ids { + for router_id in router_ids { match PendingInboundEntries::::get(message_proof, router_id) { // We expected one InboundEntry for each router, if that's not the case, // we can return. @@ -393,9 +351,7 @@ impl Pallet { Some(stored_inbound_entry) => match stored_inbound_entry { InboundEntry::Message(message_entry) => message = Some(message_entry.message), InboundEntry::Proof(proof_entry) => { - if proof_entry - .has_valid_vote_for_session(inbound_processing_info.current_session_id) - { + if proof_entry.has_valid_vote_for_session(session_id) { votes.ensure_add_assign(1)?; } } @@ -403,18 +359,20 @@ impl Pallet { }; } - if votes < inbound_processing_info.expected_proof_count_per_message { + if votes < expected_proof_count { return Ok(()); } match message { Some(msg) => { - Self::execute_post_voting_dispatch(inbound_processing_info, message_proof)?; - - T::InboundMessageHandler::handle( - inbound_processing_info.domain_address.clone(), - msg, - ) + Self::execute_post_voting_dispatch( + message_proof, + router_ids, + session_id, + expected_proof_count, + )?; + + T::InboundMessageHandler::handle(domain_address, msg) } None => Ok(()), } @@ -423,10 +381,12 @@ impl Pallet { /// Decreases the counts for inbound entries and removes them if the /// counts reach 0. pub(crate) fn execute_post_voting_dispatch( - inbound_processing_info: &InboundProcessingInfo, message_proof: Proof, + router_ids: &[T::RouterId], + session_id: T::SessionId, + expected_proof_count: u32, ) -> DispatchResult { - for router_id in &inbound_processing_info.router_ids { + for router_id in router_ids { PendingInboundEntries::::try_mutate(message_proof, router_id, |storage_entry| { match storage_entry { None => { @@ -435,7 +395,8 @@ impl Pallet { Some(stored_inbound_entry) => { let post_dispatch_entry = InboundEntry::create_post_voting_entry( stored_inbound_entry, - inbound_processing_info, + session_id, + expected_proof_count, )?; *storage_entry = post_dispatch_entry; @@ -458,8 +419,15 @@ impl Pallet { ) -> (DispatchResult, Weight) { let weight = LP_DEFENSIVE_WEIGHT; - let inbound_processing_info = match domain_address.clone().try_into() { - Ok(i) => i, + let router_ids = match Self::get_router_ids_for_domain(domain_address.domain()) { + Ok(r) => r, + Err(e) => return (Err(e), weight), + }; + + let session_id = SessionIdStore::::get(); + + let expected_proof_count = match Self::get_expected_proof_count(&router_ids) { + Ok(r) => r, Err(e) => return (Err(e), weight), }; @@ -470,18 +438,30 @@ impl Pallet { return (Err(e.into()), weight.saturating_mul(count)); } - let message_proof = Self::get_message_proof(message.clone()); + let message_proof = Self::get_message_proof(submessage.clone()); - if let Err(e) = Self::validate_and_upsert_pending_entries( - &inbound_processing_info, - submessage.clone(), - message_proof, - router_id.clone(), - ) { + let inbound_entry: InboundEntry = InboundEntry::create( + submessage, + session_id, + domain_address.clone(), + expected_proof_count, + ); + + if let Err(e) = inbound_entry.validate(&router_ids, &router_id.clone()) { + return (Err(e), weight.saturating_mul(count)); + } + + if let Err(e) = Self::upsert_pending_entry(message_proof, &router_id, inbound_entry) { return (Err(e), weight.saturating_mul(count)); } - match Self::execute_if_requirements_are_met(&inbound_processing_info, message_proof) { + match Self::execute_if_requirements_are_met( + message_proof, + &router_ids, + session_id, + expected_proof_count, + domain_address.clone(), + ) { Err(e) => return (Err(e), weight.saturating_mul(count)), Ok(_) => continue, } diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index a618cc5331..0c2e66fcd3 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -23,7 +23,7 @@ use super::{ pallet::*, }; use crate::{ - message_processing::{InboundEntry, InboundProcessingInfo, MessageEntry, ProofEntry}, + message_processing::{InboundEntry, MessageEntry, ProofEntry}, GatewayMessage, }; @@ -3331,29 +3331,25 @@ mod implementations { #[test] fn create_inbound_entry() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; + let domain_address = TEST_DOMAIN_ADDRESS; + let session_id = 1; + let expected_proof_count = 2; let tests: Vec<(Message, InboundEntry)> = vec![ ( Message::Simple, MessageEntry { - session_id: inbound_processing_info.current_session_id, - domain_address: inbound_processing_info.domain_address.clone(), + session_id, + domain_address: domain_address.clone(), message: Message::Simple, - expected_proof_count: inbound_processing_info - .expected_proof_count_per_message, + expected_proof_count, } .into(), ), ( Message::Proof(MESSAGE_PROOF), ProofEntry { - session_id: inbound_processing_info.current_session_id, + session_id, current_count: 1, } .into(), @@ -3361,8 +3357,12 @@ mod implementations { ]; for (test_message, expected_inbound_entry) in tests { - let res: InboundEntry = - (&inbound_processing_info, test_message).into(); + let res = InboundEntry::create( + test_message, + session_id, + domain_address.clone(), + expected_proof_count, + ); assert_eq!(res, expected_inbound_entry) } @@ -3376,29 +3376,25 @@ mod implementations { #[test] fn no_stored_entry() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; + let domain_address = TEST_DOMAIN_ADDRESS; + let session_id = 1; + let expected_proof_count = 2; let tests: Vec<(RouterId, InboundEntry)> = vec![ ( ROUTER_ID_1, MessageEntry { - session_id: inbound_processing_info.current_session_id, - domain_address: inbound_processing_info.domain_address.clone(), + session_id, + domain_address, message: Message::Simple, - expected_proof_count: inbound_processing_info - .expected_proof_count_per_message, + expected_proof_count, } .into(), ), ( ROUTER_ID_2, ProofEntry { - session_id: inbound_processing_info.current_session_id, + session_id, current_count: 1, } .into(), @@ -3408,7 +3404,7 @@ mod implementations { for (test_router_id, test_inbound_entry) in tests { assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, - test_router_id.clone(), + &test_router_id.clone(), test_inbound_entry.clone(), )); @@ -3440,7 +3436,7 @@ mod implementations { assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, - ROUTER_ID_1.clone(), + &ROUTER_ID_1, inbound_entry, )); @@ -3475,7 +3471,7 @@ mod implementations { assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, - ROUTER_ID_1.clone(), + &ROUTER_ID_1, MessageEntry { session_id: 2, domain_address: TEST_DOMAIN_ADDRESS, @@ -3520,7 +3516,7 @@ mod implementations { assert_noop!( LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, - ROUTER_ID_1.clone(), + &ROUTER_ID_1, InboundEntry::Proof(ProofEntry { session_id: 1, current_count: 1 @@ -3548,7 +3544,7 @@ mod implementations { assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, - ROUTER_ID_1.clone(), + &ROUTER_ID_1, inbound_entry, )); @@ -3579,7 +3575,7 @@ mod implementations { assert_ok!(LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, - ROUTER_ID_1.clone(), + &ROUTER_ID_1, ProofEntry { session_id: 2, current_count: 1, @@ -3618,7 +3614,7 @@ mod implementations { assert_noop!( LiquidityPoolsGateway::upsert_pending_entry( MESSAGE_PROOF, - ROUTER_ID_1.clone(), + &ROUTER_ID_1, InboundEntry::Message(MessageEntry { session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, @@ -3638,12 +3634,10 @@ mod implementations { #[test] fn entries_with_invalid_session_are_ignored() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; + let domain_address = TEST_DOMAIN_ADDRESS; + let router_ids = vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]; + let session_id = 1; + let expected_proof_count = 2; PendingInboundEntries::::insert( MESSAGE_PROOF, @@ -3673,8 +3667,11 @@ mod implementations { ); assert_ok!(LiquidityPoolsGateway::execute_if_requirements_are_met( - &inbound_processing_info, - MESSAGE_PROOF + MESSAGE_PROOF, + &router_ids, + session_id, + expected_proof_count, + domain_address, )); assert!( PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_some() @@ -3695,17 +3692,16 @@ mod implementations { #[test] fn pending_inbound_entry_not_found() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; + let router_ids = vec![ROUTER_ID_1]; + let session_id = 1; + let expected_proof_count = 2; assert_noop!( LiquidityPoolsGateway::execute_post_voting_dispatch( - &inbound_processing_info, - MESSAGE_PROOF + MESSAGE_PROOF, + &router_ids, + session_id, + expected_proof_count, ), Error::::PendingInboundEntryNotFound ); @@ -3715,28 +3711,27 @@ mod implementations { #[test] fn message_entry_new_session() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1], - current_session_id: 2, - expected_proof_count_per_message: 2, - }; + let domain_address = TEST_DOMAIN_ADDRESS; + let router_ids = vec![ROUTER_ID_1]; + let session_id = 2; + let expected_proof_count = 2; PendingInboundEntries::::insert( MESSAGE_PROOF, ROUTER_ID_1, InboundEntry::Message(MessageEntry { session_id: 1, - domain_address: inbound_processing_info.domain_address.clone(), + domain_address, message: Message::Simple, - expected_proof_count: inbound_processing_info - .expected_proof_count_per_message, + expected_proof_count, }), ); assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( - &inbound_processing_info, - MESSAGE_PROOF + MESSAGE_PROOF, + &router_ids, + session_id, + expected_proof_count, )); assert!( PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none() @@ -3747,12 +3742,9 @@ mod implementations { #[test] fn proof_entry_new_session() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1], - current_session_id: 2, - expected_proof_count_per_message: 2, - }; + let router_ids = vec![ROUTER_ID_1]; + let session_id = 2; + let expected_proof_count = 2; PendingInboundEntries::::insert( MESSAGE_PROOF, @@ -3764,8 +3756,10 @@ mod implementations { ); assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( - &inbound_processing_info, - MESSAGE_PROOF + MESSAGE_PROOF, + &router_ids, + session_id, + expected_proof_count, )); assert!( PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none() @@ -3795,16 +3789,13 @@ mod inbound_entry { expected_proof_count: 4, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id, - expected_proof_count_per_message: 2, - }; + let session_id = session_id; + let expected_proof_count = 2; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ) .unwrap(); @@ -3833,16 +3824,13 @@ mod inbound_entry { expected_proof_count: 4, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id + 1, - expected_proof_count_per_message: 2, - }; + let session_id = session_id + 1; + let expected_proof_count = 2; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ) .unwrap(); assert_eq!(res, None); @@ -3862,16 +3850,13 @@ mod inbound_entry { expected_proof_count: 2, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id, - expected_proof_count_per_message: 3, - }; + let session_id = session_id; + let expected_proof_count = 3; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ); assert_noop!(res, Arithmetic(Underflow)); @@ -3891,16 +3876,13 @@ mod inbound_entry { expected_proof_count: 2, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id, - expected_proof_count_per_message: 2, - }; + let session_id = session_id; + let expected_proof_count = 2; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ) .unwrap(); @@ -3918,16 +3900,13 @@ mod inbound_entry { current_count: 2, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id, - expected_proof_count_per_message: 2, - }; + let session_id = session_id; + let expected_proof_count = 2; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ) .unwrap(); @@ -3951,16 +3930,13 @@ mod inbound_entry { current_count: 2, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id + 1, - expected_proof_count_per_message: 2, - }; + let session_id = session_id + 1; + let expected_proof_count = 2; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ) .unwrap(); @@ -3978,19 +3954,16 @@ mod inbound_entry { current_count: 0, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id, - expected_proof_count_per_message: 2, - }; + let session_id = session_id; + let expected_proof_count = 2; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ); - assert_noop!(res, Arithmetic(Underflow),); + assert_noop!(res, Arithmetic(Underflow)); }); } @@ -4004,16 +3977,13 @@ mod inbound_entry { current_count: 1, }); - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![], - current_session_id: session_id, - expected_proof_count_per_message: 2, - }; + let session_id = session_id; + let expected_proof_count = 2; let res = InboundEntry::create_post_voting_entry( &inbound_entry, - &inbound_processing_info, + session_id, + expected_proof_count, ) .unwrap(); @@ -4028,48 +3998,42 @@ mod inbound_entry { #[test] fn success() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; + let domain_address = TEST_DOMAIN_ADDRESS; + let router_ids = vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]; + let session_id = 1; + let expected_proof_count = 2; - let inbound_entry = InboundEntry::Message(MessageEntry { - session_id: inbound_processing_info.current_session_id, - domain_address: inbound_processing_info.domain_address.clone(), + let inbound_entry = InboundEntry::::Message(MessageEntry { + session_id, + domain_address, message: Message::Simple, - expected_proof_count: inbound_processing_info.expected_proof_count_per_message, + expected_proof_count, }); - assert_ok!(inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_1)); + assert_ok!(inbound_entry.validate(&router_ids, &ROUTER_ID_1)); - let inbound_entry = InboundEntry::Proof(ProofEntry { - session_id: inbound_processing_info.current_session_id, + let inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, current_count: 1, }); - assert_ok!(inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_2)); + assert_ok!(inbound_entry.validate(&router_ids, &ROUTER_ID_2)); }); } #[test] fn unknown_router() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; + let router_ids = vec![ROUTER_ID_1, ROUTER_ID_2]; + let session_id = 1; - let inbound_entry = InboundEntry::Proof(ProofEntry { - session_id: inbound_processing_info.current_session_id, + let inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, current_count: 1, }); assert_noop!( - inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_3), + inbound_entry.validate(&router_ids, &ROUTER_ID_3), Error::::UnknownRouter ); }); @@ -4078,32 +4042,30 @@ mod inbound_entry { #[test] fn message_type_mismatch() { new_test_ext().execute_with(|| { - let inbound_processing_info = InboundProcessingInfo:: { - domain_address: TEST_DOMAIN_ADDRESS, - router_ids: vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3], - current_session_id: 1, - expected_proof_count_per_message: 2, - }; + let domain_address = TEST_DOMAIN_ADDRESS; + let router_ids = vec![ROUTER_ID_1, ROUTER_ID_2, ROUTER_ID_3]; + let session_id = 1; + let expected_proof_count = 2; - let inbound_entry = InboundEntry::Message(MessageEntry { - session_id: inbound_processing_info.current_session_id, - domain_address: inbound_processing_info.domain_address.clone(), + let inbound_entry = InboundEntry::::Message(MessageEntry { + session_id, + domain_address, message: Message::Simple, - expected_proof_count: inbound_processing_info.expected_proof_count_per_message, + expected_proof_count, }); assert_noop!( - inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_2), + inbound_entry.validate(&router_ids, &ROUTER_ID_2), Error::::MessageExpectedFromFirstRouter ); - let inbound_entry = InboundEntry::Proof(ProofEntry { - session_id: inbound_processing_info.current_session_id, + let inbound_entry = InboundEntry::::Proof(ProofEntry { + session_id, current_count: 1, }); assert_noop!( - inbound_entry.validate(&inbound_processing_info, &ROUTER_ID_1), + inbound_entry.validate(&router_ids, &ROUTER_ID_1), Error::::ProofNotExpectedFromFirstRouter ); }); @@ -4290,43 +4252,3 @@ mod inbound_entry { } } } - -mod inbound_processing_info { - use super::*; - - mod try_from_domain_address { - use super::*; - - #[test] - fn success() { - new_test_ext().execute_with(|| { - let router_ids = vec![ROUTER_ID_1, ROUTER_ID_2]; - let expected_proof_count = router_ids.len() - 1; - - Routers::::set(BoundedVec::try_from(router_ids.clone()).unwrap()); - - let res: InboundProcessingInfo = TEST_DOMAIN_ADDRESS.try_into().unwrap(); - assert_eq!(res.domain_address, TEST_DOMAIN_ADDRESS); - assert_eq!(res.router_ids, router_ids); - assert_eq!(res.current_session_id, 0); - assert_eq!( - res.expected_proof_count_per_message, - expected_proof_count as u32 - ); - }); - } - - #[test] - fn not_enough_routers_for_domain() { - new_test_ext().execute_with(|| { - let res: Result, DispatchError> = - TEST_DOMAIN_ADDRESS.try_into(); - - assert_eq!( - res.err().unwrap(), - Error::::NotEnoughRoutersForDomain.into() - ); - }); - } - } -} From 6c45d5b1dc52b0ff75985c26b760bfba00f6d817 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:33:13 +0300 Subject: [PATCH 31/38] lp-gateway: Rename LP encoding methods to get_proof and to_proof_message --- libs/traits/src/liquidity_pools.rs | 4 ++-- .../liquidity-pools-gateway/src/message_processing.rs | 10 +++++----- pallets/liquidity-pools-gateway/src/mock.rs | 4 ++-- pallets/liquidity-pools-gateway/src/tests.rs | 6 +++--- pallets/liquidity-pools/src/message.rs | 4 ++-- runtime/integration-tests/submodules/liquidity-pools | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libs/traits/src/liquidity_pools.rs b/libs/traits/src/liquidity_pools.rs index d79a1f5523..0f80787337 100644 --- a/libs/traits/src/liquidity_pools.rs +++ b/libs/traits/src/liquidity_pools.rs @@ -35,10 +35,10 @@ pub trait LPEncoding: Sized { fn empty() -> Self; /// Retrieves the message proof hash, if the message is a proof type. - fn proof_hash(&self) -> Option; + fn get_proof(&self) -> Option; /// Converts the message into a message proof type. - fn proof_message(&self) -> Self; + fn to_proof_message(&self) -> Self; } pub trait RouterProvider: Sized { diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 9c806bca0e..51d11ea69a 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -91,7 +91,7 @@ impl InboundEntry { domain_address: DomainAddress, expected_proof_count: u32, ) -> Self { - match message.proof_hash() { + match message.get_proof() { None => InboundEntry::Message(MessageEntry { session_id, domain_address, @@ -300,10 +300,10 @@ impl Pallet { /// Gets the message proof for a message. pub(crate) fn get_message_proof(message: T::Message) -> Proof { - match message.proof_hash() { + match message.get_proof() { None => message - .proof_message() - .proof_hash() + .to_proof_message() + .get_proof() .expect("message proof ensured by 'to_message_proof'"), Some(proof) => proof, } @@ -493,7 +493,7 @@ impl Pallet { ) -> DispatchResult { let router_ids = Self::get_router_ids_for_domain(destination)?; - let message_proof = message.proof_message(); + let message_proof = message.to_proof_message(); let mut message_opt = Some(message); for router_id in router_ids { diff --git a/pallets/liquidity-pools-gateway/src/mock.rs b/pallets/liquidity-pools-gateway/src/mock.rs index 18eca2f97e..9296a0b534 100644 --- a/pallets/liquidity-pools-gateway/src/mock.rs +++ b/pallets/liquidity-pools-gateway/src/mock.rs @@ -97,14 +97,14 @@ impl LPEncoding for Message { Self::Pack(vec![]) } - fn proof_hash(&self) -> Option { + fn get_proof(&self) -> Option { match self { Message::Proof(p) => Some(p.clone()), _ => None, } } - fn proof_message(&self) -> Self { + fn to_proof_message(&self) -> Self { match self { Message::Proof(_) => self.clone(), _ => Message::Proof(MESSAGE_PROOF), diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 0c2e66fcd3..7aead56fd4 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -886,7 +886,7 @@ mod implementations { let domain = Domain::EVM(0); let sender = get_test_account_id(); let msg = Message::Simple; - let message_proof = msg.proof_message().proof_hash().unwrap(); + let message_proof = msg.to_proof_message().get_proof().unwrap(); assert_ok!(LiquidityPoolsGateway::set_routers( RuntimeOrigin::root(), @@ -1143,7 +1143,7 @@ mod implementations { fn success() { new_test_ext().execute_with(|| { let message = Message::Simple; - let message_proof = message.proof_message().proof_hash().unwrap(); + let message_proof = message.to_proof_message().get_proof().unwrap(); let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); let router_id = ROUTER_ID_1; @@ -1224,7 +1224,7 @@ mod implementations { fn expected_message_proof_type() { new_test_ext().execute_with(|| { let message = Message::Simple; - let message_proof = message.proof_message().proof_hash().unwrap(); + let message_proof = message.to_proof_message().get_proof().unwrap(); let session_id = 1; let domain_address = DomainAddress::EVM(1, [1; 20]); let router_id = ROUTER_ID_1; diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index a68cbe72ee..cb7be4c372 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -563,14 +563,14 @@ impl LPEncoding for Message { Message::Batch(BatchMessages::default()) } - fn proof_hash(&self) -> Option { + fn get_proof(&self) -> Option { match self { Message::MessageProof { hash } => Some(*hash), _ => None, } } - fn proof_message(&self) -> Self { + fn to_proof_message(&self) -> Self { let hash = keccak_256(&LPEncoding::serialize(self)); Message::MessageProof { hash } diff --git a/runtime/integration-tests/submodules/liquidity-pools b/runtime/integration-tests/submodules/liquidity-pools index 6e8f1a29df..4301885b9a 160000 --- a/runtime/integration-tests/submodules/liquidity-pools +++ b/runtime/integration-tests/submodules/liquidity-pools @@ -1 +1 @@ -Subproject commit 6e8f1a29dff0d7cf5ff74285cfffadae8a8b303f +Subproject commit 4301885b9a3b8ec36f3bda4b789daa5b115c006a From 88bdad7b58cbb3661c405711fba34a959b5589ae Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:39:11 +0300 Subject: [PATCH 32/38] lp-gateway: Move outbound processing logic back to pallet --- pallets/liquidity-pools-gateway/src/lib.rs | 9 ++++++++- .../src/message_processing.rs | 17 +---------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/lib.rs b/pallets/liquidity-pools-gateway/src/lib.rs index bee1bbd624..6e815c45b2 100644 --- a/pallets/liquidity-pools-gateway/src/lib.rs +++ b/pallets/liquidity-pools-gateway/src/lib.rs @@ -522,7 +522,14 @@ pub mod pallet { sender, message, router_id, - } => Self::process_outbound_message(sender, message, router_id), + } => { + let weight = LP_DEFENSIVE_WEIGHT; + + match T::MessageSender::send(router_id, sender, message.serialize()) { + Ok(_) => (Ok(()), weight), + Err(e) => (Err(e), weight), + } + } } } diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 51d11ea69a..1579e19192 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -1,6 +1,6 @@ use cfg_primitives::LP_DEFENSIVE_WEIGHT; use cfg_traits::liquidity_pools::{ - InboundMessageHandler, LPEncoding, MessageQueue, MessageSender, Proof, RouterProvider, + InboundMessageHandler, LPEncoding, MessageQueue, Proof, RouterProvider, }; use cfg_types::domain_address::{Domain, DomainAddress}; use frame_support::{ @@ -470,21 +470,6 @@ impl Pallet { (Ok(()), weight.saturating_mul(count)) } - /// Retrieves the stored router, sends the message, and calculates and - /// returns the router operation result and the weight used. - pub(crate) fn process_outbound_message( - sender: DomainAddress, - message: T::Message, - router_id: T::RouterId, - ) -> (DispatchResult, Weight) { - let weight = LP_DEFENSIVE_WEIGHT; - - match T::MessageSender::send(router_id, sender, message.serialize()) { - Ok(_) => (Ok(()), weight), - Err(e) => (Err(e), weight), - } - } - /// Retrieves the IDs of the routers set for a domain and queues the /// message and proofs accordingly. pub(crate) fn queue_outbound_message( From 9f6d68459da2f15d283c6226a4abcfd29a6ac1fa Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:16:20 +0300 Subject: [PATCH 33/38] review: Small fixes --- .../src/message_processing.rs | 23 +++++++++---------- pallets/liquidity-pools-gateway/src/tests.rs | 22 ------------------ 2 files changed, 11 insertions(+), 34 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 1579e19192..1d7fe0081b 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -363,19 +363,18 @@ impl Pallet { return Ok(()); } - match message { - Some(msg) => { - Self::execute_post_voting_dispatch( - message_proof, - router_ids, - session_id, - expected_proof_count, - )?; - - T::InboundMessageHandler::handle(domain_address, msg) - } - None => Ok(()), + if let Some(msg) = message { + Self::execute_post_voting_dispatch( + message_proof, + router_ids, + session_id, + expected_proof_count, + )?; + + T::InboundMessageHandler::handle(domain_address, msg)?; } + + Ok(()) } /// Decreases the counts for inbound entries and removes them if the diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 7aead56fd4..1ab66ec493 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -3303,28 +3303,6 @@ mod implementations { } } - mod get_message_proof { - use super::*; - - #[test] - fn get_message_proof() { - new_test_ext().execute_with(|| { - let test_messages = vec![ - Message::Simple, - Message::Proof(MESSAGE_PROOF), - Message::Pack(vec![Message::Simple]), - ]; - - for test_message in test_messages { - assert_eq!( - LiquidityPoolsGateway::get_message_proof(test_message), - MESSAGE_PROOF - ); - } - }); - } - } - mod create_inbound_entry { use super::*; From d990f5fe4d6d6b39359d5a2d45d118ca51b10802 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:32:51 +0300 Subject: [PATCH 34/38] lp-gateway: Add comment for post voting dispatch error case --- .../src/message_processing.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 1d7fe0081b..851273b486 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -350,11 +350,12 @@ impl Pallet { None => return Ok(()), Some(stored_inbound_entry) => match stored_inbound_entry { InboundEntry::Message(message_entry) => message = Some(message_entry.message), - InboundEntry::Proof(proof_entry) => { - if proof_entry.has_valid_vote_for_session(session_id) { - votes.ensure_add_assign(1)?; - } + InboundEntry::Proof(proof_entry) + if proof_entry.has_valid_vote_for_session(session_id) => + { + votes.ensure_add_assign(1)?; } + _ => {} }, }; } @@ -389,6 +390,9 @@ impl Pallet { PendingInboundEntries::::try_mutate(message_proof, router_id, |storage_entry| { match storage_entry { None => { + // This case cannot be reproduced in production since this function is + // called only if a message is submitted for further processing, which + // means that all the pending inbound entries are present. Err::<(), DispatchError>(Error::::PendingInboundEntryNotFound.into()) } Some(stored_inbound_entry) => { From 603e24c7defa1bbdc73fc33a79ed3c3b97aad83c Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:07:20 +0300 Subject: [PATCH 35/38] lp-gatway: Drop session ID check in create_post_voting_entry --- .../src/message_processing.rs | 27 +-- pallets/liquidity-pools-gateway/src/tests.rs | 194 +++--------------- 2 files changed, 32 insertions(+), 189 deletions(-) diff --git a/pallets/liquidity-pools-gateway/src/message_processing.rs b/pallets/liquidity-pools-gateway/src/message_processing.rs index 851273b486..1783c7e869 100644 --- a/pallets/liquidity-pools-gateway/src/message_processing.rs +++ b/pallets/liquidity-pools-gateway/src/message_processing.rs @@ -26,6 +26,9 @@ pub struct MessageEntry { pub session_id: T::SessionId, /// The sender of the inbound message. + /// + /// NOTE - the `RouterProvider` ensures that we cannot have the same message + /// entry, for the same message, for different domain addresses. pub domain_address: DomainAddress, /// The LP message. @@ -107,20 +110,15 @@ impl InboundEntry { /// Creates a new `InboundEntry` based on the information provided. /// - /// If a session change is detected or if the updated counts reach 0, it - /// means that a new entry is no longer required, otherwise, the counts are - /// decreased accordingly, based on the entry type. + /// If the updated counts reach 0, it means that a new entry is no longer + /// required, otherwise, the counts are decreased accordingly, based on the + /// entry type. pub fn create_post_voting_entry( inbound_entry: &InboundEntry, - session_id: T::SessionId, expected_proof_count: u32, ) -> Result, DispatchError> { match inbound_entry { InboundEntry::Message(message_entry) => { - if message_entry.session_id != session_id { - return Ok(None); - } - let updated_count = message_entry .expected_proof_count .ensure_sub(expected_proof_count)?; @@ -138,10 +136,6 @@ impl InboundEntry { )) } InboundEntry::Proof(proof_entry) => { - if proof_entry.session_id != session_id { - return Ok(None); - } - let updated_count = proof_entry.current_count.ensure_sub(1)?; if updated_count == 0 { @@ -365,12 +359,7 @@ impl Pallet { } if let Some(msg) = message { - Self::execute_post_voting_dispatch( - message_proof, - router_ids, - session_id, - expected_proof_count, - )?; + Self::execute_post_voting_dispatch(message_proof, router_ids, expected_proof_count)?; T::InboundMessageHandler::handle(domain_address, msg)?; } @@ -383,7 +372,6 @@ impl Pallet { pub(crate) fn execute_post_voting_dispatch( message_proof: Proof, router_ids: &[T::RouterId], - session_id: T::SessionId, expected_proof_count: u32, ) -> DispatchResult { for router_id in router_ids { @@ -398,7 +386,6 @@ impl Pallet { Some(stored_inbound_entry) => { let post_dispatch_entry = InboundEntry::create_post_voting_entry( stored_inbound_entry, - session_id, expected_proof_count, )?; diff --git a/pallets/liquidity-pools-gateway/src/tests.rs b/pallets/liquidity-pools-gateway/src/tests.rs index 1ab66ec493..d687a9cd57 100644 --- a/pallets/liquidity-pools-gateway/src/tests.rs +++ b/pallets/liquidity-pools-gateway/src/tests.rs @@ -3664,86 +3664,25 @@ mod implementations { } } - mod decrease_pending_entries_counts { + mod execute_post_voting_dispatch { use super::*; #[test] fn pending_inbound_entry_not_found() { new_test_ext().execute_with(|| { let router_ids = vec![ROUTER_ID_1]; - let session_id = 1; let expected_proof_count = 2; assert_noop!( LiquidityPoolsGateway::execute_post_voting_dispatch( MESSAGE_PROOF, &router_ids, - session_id, expected_proof_count, ), Error::::PendingInboundEntryNotFound ); }); } - - #[test] - fn message_entry_new_session() { - new_test_ext().execute_with(|| { - let domain_address = TEST_DOMAIN_ADDRESS; - let router_ids = vec![ROUTER_ID_1]; - let session_id = 2; - let expected_proof_count = 2; - - PendingInboundEntries::::insert( - MESSAGE_PROOF, - ROUTER_ID_1, - InboundEntry::Message(MessageEntry { - session_id: 1, - domain_address, - message: Message::Simple, - expected_proof_count, - }), - ); - - assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( - MESSAGE_PROOF, - &router_ids, - session_id, - expected_proof_count, - )); - assert!( - PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none() - ); - }); - } - - #[test] - fn proof_entry_new_session() { - new_test_ext().execute_with(|| { - let router_ids = vec![ROUTER_ID_1]; - let session_id = 2; - let expected_proof_count = 2; - - PendingInboundEntries::::insert( - MESSAGE_PROOF, - ROUTER_ID_1, - InboundEntry::Proof(ProofEntry { - session_id: 1, - current_count: 1, - }), - ); - - assert_ok!(LiquidityPoolsGateway::execute_post_voting_dispatch( - MESSAGE_PROOF, - &router_ids, - session_id, - expected_proof_count, - )); - assert!( - PendingInboundEntries::::get(MESSAGE_PROOF, ROUTER_ID_1).is_none() - ); - }); - } } } } @@ -3757,30 +3696,25 @@ mod inbound_entry { #[test] fn message_entry_some() { new_test_ext().execute_with(|| { - let session_id = 1; let message = Message::Simple; let inbound_entry = InboundEntry::::Message(MessageEntry { - session_id, + session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: message.clone(), expected_proof_count: 4, }); - let session_id = session_id; let expected_proof_count = 2; - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ) - .unwrap(); + let res = + InboundEntry::create_post_voting_entry(&inbound_entry, expected_proof_count) + .unwrap(); assert_eq!( res, Some(InboundEntry::::Message(MessageEntry { - session_id, + session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message, expected_proof_count: 2, @@ -3789,53 +3723,22 @@ mod inbound_entry { }); } - #[test] - fn message_entry_session_change() { - new_test_ext().execute_with(|| { - let session_id = 1; - let message = Message::Simple; - - let inbound_entry = InboundEntry::::Message(MessageEntry { - session_id, - domain_address: TEST_DOMAIN_ADDRESS, - message: message.clone(), - expected_proof_count: 4, - }); - - let session_id = session_id + 1; - let expected_proof_count = 2; - - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ) - .unwrap(); - assert_eq!(res, None); - }); - } - #[test] fn message_entry_count_underflow() { new_test_ext().execute_with(|| { - let session_id = 1; let message = Message::Simple; let inbound_entry = InboundEntry::::Message(MessageEntry { - session_id, + session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: message.clone(), expected_proof_count: 2, }); - let session_id = session_id; let expected_proof_count = 3; - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ); + let res = + InboundEntry::create_post_voting_entry(&inbound_entry, expected_proof_count); assert_noop!(res, Arithmetic(Underflow)); }); @@ -3844,25 +3747,20 @@ mod inbound_entry { #[test] fn message_entry_zero_updated_count() { new_test_ext().execute_with(|| { - let session_id = 1; let message = Message::Simple; let inbound_entry = InboundEntry::::Message(MessageEntry { - session_id, + session_id: 1, domain_address: TEST_DOMAIN_ADDRESS, message: message.clone(), expected_proof_count: 2, }); - let session_id = session_id; let expected_proof_count = 2; - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ) - .unwrap(); + let res = + InboundEntry::create_post_voting_entry(&inbound_entry, expected_proof_count) + .unwrap(); assert_eq!(res, None); }); @@ -3871,75 +3769,39 @@ mod inbound_entry { #[test] fn proof_entry_some() { new_test_ext().execute_with(|| { - let session_id = 1; - let inbound_entry = InboundEntry::::Proof(ProofEntry { - session_id, + session_id: 1, current_count: 2, }); - let session_id = session_id; let expected_proof_count = 2; - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ) - .unwrap(); + let res = + InboundEntry::create_post_voting_entry(&inbound_entry, expected_proof_count) + .unwrap(); assert_eq!( res, Some(InboundEntry::::Proof(ProofEntry { - session_id, + session_id: 1, current_count: 1 })) ); }); } - #[test] - fn proof_entry_session_change() { - new_test_ext().execute_with(|| { - let session_id = 1; - - let inbound_entry = InboundEntry::::Proof(ProofEntry { - session_id, - current_count: 2, - }); - - let session_id = session_id + 1; - let expected_proof_count = 2; - - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ) - .unwrap(); - - assert_eq!(res, None); - }); - } - #[test] fn proof_entry_count_underflow() { new_test_ext().execute_with(|| { - let session_id = 1; - let inbound_entry = InboundEntry::::Proof(ProofEntry { - session_id, + session_id: 1, current_count: 0, }); - let session_id = session_id; let expected_proof_count = 2; - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ); + let res = + InboundEntry::create_post_voting_entry(&inbound_entry, expected_proof_count); assert_noop!(res, Arithmetic(Underflow)); }); @@ -3948,22 +3810,16 @@ mod inbound_entry { #[test] fn proof_entry_zero_updated_count() { new_test_ext().execute_with(|| { - let session_id = 1; - let inbound_entry = InboundEntry::::Proof(ProofEntry { - session_id, + session_id: 1, current_count: 1, }); - let session_id = session_id; let expected_proof_count = 2; - let res = InboundEntry::create_post_voting_entry( - &inbound_entry, - session_id, - expected_proof_count, - ) - .unwrap(); + let res = + InboundEntry::create_post_voting_entry(&inbound_entry, expected_proof_count) + .unwrap(); assert_eq!(res, None,); }); From 584e7e8eb4333942a1093bc5f3bb2c9b06a5114c Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:08:57 +0300 Subject: [PATCH 36/38] lp: Remove unused import --- pallets/liquidity-pools/src/message.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/liquidity-pools/src/message.rs b/pallets/liquidity-pools/src/message.rs index cb7be4c372..f8f04014ec 100644 --- a/pallets/liquidity-pools/src/message.rs +++ b/pallets/liquidity-pools/src/message.rs @@ -18,7 +18,6 @@ use serde::{ ser::{Error as _, SerializeTuple}, Deserialize, Serialize, Serializer, }; -use sp_core::U256; use sp_io::hashing::keccak_256; use sp_runtime::{traits::ConstU32, DispatchError, DispatchResult}; use sp_std::{vec, vec::Vec}; From e59f1edef850669b6382c58ef26f15e7981e560a Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 21:14:45 +0300 Subject: [PATCH 37/38] integration-tests: Register routers during setup (#1968) --- .../src/cases/liquidity_pools.rs | 32 +++++++++++-------- .../cases/liquidity_pools_gateway_queue.rs | 23 ++++++++++--- runtime/integration-tests/src/cases/lp/mod.rs | 6 ++-- .../integration-tests/src/cases/lp/utils.rs | 8 ++--- .../integration-tests/src/cases/routers.rs | 19 +++++++++-- runtime/integration-tests/src/config.rs | 2 +- 6 files changed, 61 insertions(+), 29 deletions(-) diff --git a/runtime/integration-tests/src/cases/liquidity_pools.rs b/runtime/integration-tests/src/cases/liquidity_pools.rs index ddc227f779..a3a80d3da6 100644 --- a/runtime/integration-tests/src/cases/liquidity_pools.rs +++ b/runtime/integration-tests/src/cases/liquidity_pools.rs @@ -22,6 +22,7 @@ use frame_support::{ OriginTrait, PalletInfo, }, }; +use pallet_axelar_router::AxelarId; use pallet_foreign_investments::ForeignInvestmentInfo; use pallet_investments::CollectOutcome; use pallet_liquidity_pools::Message; @@ -30,7 +31,7 @@ use pallet_liquidity_pools_gateway_queue::MessageNonceStore; use pallet_pool_system::tranches::{TrancheInput, TrancheLoc, TrancheType}; use runtime_common::{ account_conversion::AccountConverter, foreign_investments::IdentityPoolCurrencyConverter, - xcm::general_key, + routing::RouterId, xcm::general_key, }; use sp_core::Get; use sp_runtime::{ @@ -77,6 +78,7 @@ pub const DEFAULT_DOMAIN_ADDRESS_MOONBEAM: DomainAddress = DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, DEFAULT_EVM_ADDRESS_MOONBEAM); pub const DEFAULT_OTHER_DOMAIN_ADDRESS: DomainAddress = DomainAddress::EVM(MOONBEAM_EVM_CHAIN_ID, [0; 20]); +pub const DEFAULT_ROUTER_ID: RouterId = RouterId::Axelar(AxelarId::Evm(MOONBEAM_EVM_CHAIN_ID)); pub type LiquidityPoolMessage = Message; @@ -288,6 +290,11 @@ pub mod utils { DEFAULT_BALANCE_GLMR, 0, )); + + assert_ok!(pallet_liquidity_pools_gateway::Pallet::::set_routers( + ::RuntimeOrigin::root(), + BoundedVec::try_from(vec![DEFAULT_ROUTER_ID]).unwrap(), + )); }); } @@ -1038,7 +1045,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: LiquidityPoolMessage::FulfilledDepositRequest { pool_id, tranche_id: default_tranche_id::(pool_id), @@ -1142,7 +1149,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: Message::FulfilledDepositRequest { pool_id, tranche_id: default_tranche_id::(pool_id), @@ -1235,7 +1242,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: LiquidityPoolMessage::FulfilledDepositRequest { pool_id, tranche_id: default_tranche_id::(pool_id), @@ -1270,14 +1277,11 @@ mod foreign_investments { message: GatewayMessage::Outbound { sender: event_sender, - destination: event_domain, + router_id: event_router_id, message: Message::FulfilledDepositRequest { .. }, }, .. - } => { - event_sender == sender - && event_domain == DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain() - } + } => event_sender == sender && event_router_id == DEFAULT_ROUTER_ID, _ => false, } } else { @@ -1520,7 +1524,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: LiquidityPoolMessage::FulfilledRedeemRequest { pool_id, tranche_id: default_tranche_id::(pool_id), @@ -1610,7 +1614,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: LiquidityPoolMessage::FulfilledRedeemRequest { pool_id, tranche_id: default_tranche_id::(pool_id), @@ -1965,7 +1969,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: LiquidityPoolMessage::FulfilledDepositRequest { pool_id, tranche_id: default_tranche_id::(pool_id), @@ -2117,7 +2121,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: LiquidityPoolMessage::FulfilledCancelDepositRequest { pool_id, tranche_id: default_tranche_id::(pool_id), @@ -2229,7 +2233,7 @@ mod foreign_investments { nonce, message: GatewayMessage::Outbound { sender: sender.clone(), - destination: DEFAULT_DOMAIN_ADDRESS_MOONBEAM.domain(), + router_id: DEFAULT_ROUTER_ID, message: LiquidityPoolMessage::FulfilledCancelDepositRequest { pool_id, tranche_id: default_tranche_id::(pool_id), diff --git a/runtime/integration-tests/src/cases/liquidity_pools_gateway_queue.rs b/runtime/integration-tests/src/cases/liquidity_pools_gateway_queue.rs index 7034f18ecb..95f6ce9442 100644 --- a/runtime/integration-tests/src/cases/liquidity_pools_gateway_queue.rs +++ b/runtime/integration-tests/src/cases/liquidity_pools_gateway_queue.rs @@ -1,15 +1,17 @@ use cfg_traits::liquidity_pools::MessageQueue; -use cfg_types::domain_address::{Domain, DomainAddress}; -use frame_support::assert_ok; +use cfg_types::domain_address::DomainAddress; +use frame_support::{assert_ok, traits::OriginTrait}; use pallet_liquidity_pools::Message; use pallet_liquidity_pools_gateway::message::GatewayMessage; -use sp_runtime::traits::One; +use sp_runtime::{traits::One, BoundedVec}; use crate::{ + cases::liquidity_pools::{DEFAULT_DOMAIN_ADDRESS_MOONBEAM, DEFAULT_ROUTER_ID}, config::Runtime, env::{Blocks, Env}, envs::fudge_env::{FudgeEnv, FudgeSupport}, }; + /// NOTE - we're using fudge here because in a non-fudge environment, the event /// can only be read before block finalization. The LP gateway queue is /// processing messages during the `on_idle` hook, just before the block is @@ -23,9 +25,15 @@ fn inbound() { let mut env = FudgeEnv::::default(); let expected_event = env.parachain_state_mut(|| { + assert_ok!(pallet_liquidity_pools_gateway::Pallet::::set_routers( + ::RuntimeOrigin::root(), + BoundedVec::try_from(vec![DEFAULT_ROUTER_ID]).unwrap(), + )); + let nonce = ::MessageNonce::one(); let message = GatewayMessage::Inbound { - domain_address: DomainAddress::EVM(1, [2; 20]), + domain_address: DEFAULT_DOMAIN_ADDRESS_MOONBEAM, + router_id: DEFAULT_ROUTER_ID, message: Message::Invalid, }; @@ -53,10 +61,15 @@ fn outbound() { let mut env = FudgeEnv::::default(); let expected_event = env.parachain_state_mut(|| { + assert_ok!(pallet_liquidity_pools_gateway::Pallet::::set_routers( + ::RuntimeOrigin::root(), + BoundedVec::try_from(vec![DEFAULT_ROUTER_ID]).unwrap(), + )); + let nonce = ::MessageNonce::one(); let message = GatewayMessage::Outbound { sender: DomainAddress::Centrifuge([1; 32]), - destination: Domain::EVM(1), + router_id: DEFAULT_ROUTER_ID, message: Message::Invalid, }; diff --git a/runtime/integration-tests/src/cases/lp/mod.rs b/runtime/integration-tests/src/cases/lp/mod.rs index 1c6896a9bf..5ff21520b0 100644 --- a/runtime/integration-tests/src/cases/lp/mod.rs +++ b/runtime/integration-tests/src/cases/lp/mod.rs @@ -24,9 +24,9 @@ use ethabi::{ use frame_support::{assert_ok, dispatch::RawOrigin, traits::OriginTrait}; use frame_system::pallet_prelude::OriginFor; use hex_literal::hex; -use pallet_axelar_router::{AxelarConfig, DomainConfig, EvmConfig, FeeValues}; +use pallet_axelar_router::{AxelarConfig, AxelarId, DomainConfig, EvmConfig, FeeValues}; use pallet_evm::FeeCalculator; -use runtime_common::account_conversion::AccountConverter; +use runtime_common::{account_conversion::AccountConverter, routing::RouterId}; pub use setup_lp::*; use sp_core::Get; use sp_runtime::traits::{BlakeTwo256, Hash}; @@ -88,6 +88,8 @@ pub const EVM_DOMAIN_CHAIN_ID: u64 = 1; pub const EVM_DOMAIN: Domain = Domain::EVM(EVM_DOMAIN_CHAIN_ID); +pub const EVM_ROUTER_ID: RouterId = RouterId::Axelar(AxelarId::Evm(EVM_DOMAIN_CHAIN_ID)); + /// Represents Solidity enum Domain.Centrifuge pub const DOMAIN_CENTRIFUGE: u8 = 0; diff --git a/runtime/integration-tests/src/cases/lp/utils.rs b/runtime/integration-tests/src/cases/lp/utils.rs index e8229d5c17..fe5e570088 100644 --- a/runtime/integration-tests/src/cases/lp/utils.rs +++ b/runtime/integration-tests/src/cases/lp/utils.rs @@ -13,7 +13,7 @@ use std::{cmp::min, fmt::Debug}; use cfg_primitives::{Balance, TrancheId}; -use cfg_types::domain_address::{Domain, DomainAddress}; +use cfg_types::domain_address::DomainAddress; use ethabi::ethereum_types::{H160, H256, U256}; use fp_evm::CallInfo; use frame_support::traits::{OriginTrait, PalletInfo}; @@ -34,7 +34,7 @@ use staging_xcm::{ }; use crate::{ - cases::lp::{EVM_DOMAIN_CHAIN_ID, POOL_A, POOL_B, POOL_C}, + cases::lp::{EVM_DOMAIN_CHAIN_ID, EVM_ROUTER_ID, POOL_A, POOL_B, POOL_C}, config::Runtime, utils::{accounts::Keyring, evm::receipt_ok, last_event, pool::get_tranche_ids}, }; @@ -149,14 +149,14 @@ pub fn process_gateway_message( GatewayMessage::Inbound { message, .. } => verifier(message), GatewayMessage::Outbound { sender, - destination, + router_id, message, } => { assert_eq!( sender, ::Sender::get() ); - assert_eq!(destination, Domain::EVM(EVM_DOMAIN_CHAIN_ID)); + assert_eq!(router_id, EVM_ROUTER_ID); verifier(message) } } diff --git a/runtime/integration-tests/src/cases/routers.rs b/runtime/integration-tests/src/cases/routers.rs index e4c13f0d55..0eaf6065fc 100644 --- a/runtime/integration-tests/src/cases/routers.rs +++ b/runtime/integration-tests/src/cases/routers.rs @@ -7,12 +7,12 @@ use cfg_types::{ use ethabi::{Function, Param, ParamType, Token}; use frame_support::{assert_ok, dispatch::RawOrigin}; use orml_traits::MultiCurrency; -use pallet_axelar_router::{AxelarConfig, DomainConfig, EvmConfig, FeeValues}; +use pallet_axelar_router::{AxelarConfig, AxelarId, DomainConfig, EvmConfig, FeeValues}; use pallet_liquidity_pools::Message; use pallet_liquidity_pools_gateway::message::GatewayMessage; use runtime_common::{ account_conversion::AccountConverter, evm::precompile::LP_AXELAR_GATEWAY, - gateway::get_gateway_h160_account, + gateway::get_gateway_h160_account, routing::RouterId, }; use sp_core::{Get, H160, H256, U256}; use sp_runtime::traits::{BlakeTwo256, Hash}; @@ -30,12 +30,15 @@ use crate::{ }; mod axelar_evm { + use frame_support::BoundedVec; + use super::*; const CHAIN_NAME: &str = "Ethereum"; const INITIAL: Balance = 100; const CHAIN_ID: EVMChainId = 1; const TEST_DOMAIN: Domain = Domain::EVM(CHAIN_ID); + const TEST_ROUTER_ID: RouterId = RouterId::Axelar(AxelarId::Evm(CHAIN_ID)); const AXELAR_CONTRACT_CODE: &[u8] = &[0, 0, 0]; const AXELAR_CONTRACT_ADDRESS: H160 = H160::repeat_byte(1); const LP_CONTRACT_ADDRESS: H160 = H160::repeat_byte(2); @@ -130,9 +133,14 @@ mod axelar_evm { Box::new(base_config::()), )); + assert_ok!(pallet_liquidity_pools_gateway::Pallet::::set_routers( + RawOrigin::Root.into(), + BoundedVec::try_from(vec![TEST_ROUTER_ID]).unwrap(), + )); + let gateway_message = GatewayMessage::Outbound { sender: T::Sender::get(), - destination: TEST_DOMAIN, + router_id: TEST_ROUTER_ID, message: Message::Invalid, }; @@ -162,6 +170,11 @@ mod axelar_evm { Box::new(base_config::()), )); + assert_ok!(pallet_liquidity_pools_gateway::Pallet::::set_routers( + RawOrigin::Root.into(), + BoundedVec::try_from(vec![TEST_ROUTER_ID]).unwrap(), + )); + let message = Message::TransferAssets { currency: pallet_liquidity_pools::Pallet::::try_get_general_index(Usd18.id()) .unwrap(), diff --git a/runtime/integration-tests/src/config.rs b/runtime/integration-tests/src/config.rs index 6873cbcbc8..8671a58c54 100644 --- a/runtime/integration-tests/src/config.rs +++ b/runtime/integration-tests/src/config.rs @@ -137,7 +137,7 @@ pub trait Runtime: TrancheId = TrancheId, BalanceRatio = Ratio, > + pallet_liquidity_pools_gateway::Config - + pallet_liquidity_pools_gateway_queue::Config> + + pallet_liquidity_pools_gateway_queue::Config> + pallet_xcm_transactor::Config + pallet_ethereum::Config + pallet_ethereum_transaction::Config From 89ffd0e80becaa51f28d40cc28d3b7d60b475ae6 Mon Sep 17 00:00:00 2001 From: Cosmin Damian <17934949+cdamian@users.noreply.github.com> Date: Thu, 15 Aug 2024 23:13:39 +0300 Subject: [PATCH 38/38] integration-tests: Set routers in all setup funcs and tests --- runtime/integration-tests/src/cases/lp/setup_lp.rs | 7 +++++++ .../src/cases/restricted_transfers.rs | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/runtime/integration-tests/src/cases/lp/setup_lp.rs b/runtime/integration-tests/src/cases/lp/setup_lp.rs index efc3ad0299..e5cab8f68a 100644 --- a/runtime/integration-tests/src/cases/lp/setup_lp.rs +++ b/runtime/integration-tests/src/cases/lp/setup_lp.rs @@ -10,6 +10,8 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +use sp_core::bounded_vec::BoundedVec; + use super::*; use crate::cases::lp::utils::pool_c_tranche_1_id; @@ -91,6 +93,11 @@ pub fn setup as EnvEvmExtension>::E DomainAddress::evm(EVM_DOMAIN_CHAIN_ID, EVM_LP_INSTANCE) )); + assert_ok!(pallet_liquidity_pools_gateway::Pallet::::set_routers( + RawOrigin::Root.into(), + BoundedVec::try_from(vec![EVM_ROUTER_ID]).unwrap(), + )); + assert_ok!( pallet_liquidity_pools_gateway::Pallet::::set_domain_hook_address( RawOrigin::Root.into(), diff --git a/runtime/integration-tests/src/cases/restricted_transfers.rs b/runtime/integration-tests/src/cases/restricted_transfers.rs index bb1cfe7466..5269cc1b3f 100644 --- a/runtime/integration-tests/src/cases/restricted_transfers.rs +++ b/runtime/integration-tests/src/cases/restricted_transfers.rs @@ -21,8 +21,9 @@ use cfg_types::{ }; use cumulus_primitives_core::WeightLimit; use frame_support::{assert_noop, assert_ok, dispatch::RawOrigin, traits::PalletInfo}; -use runtime_common::remarks::Remark; -use sp_runtime::traits::Zero; +use pallet_axelar_router::AxelarId; +use runtime_common::{remarks::Remark, routing::RouterId}; +use sp_runtime::{traits::Zero, BoundedVec}; use staging_xcm::{ v4::{Junction::*, Location, NetworkId}, VersionedLocation, @@ -361,6 +362,7 @@ mod eth_address { const TRANSFER: u32 = 10; const CHAIN_ID: u64 = 1; const CONTRACT_ACCOUNT: [u8; 20] = [1; 20]; + const ROUTER_ID: RouterId = RouterId::Axelar(AxelarId::Evm(CHAIN_ID)); #[test_runtimes(all)] fn restrict_lp_eth_transfer() { @@ -399,6 +401,11 @@ mod eth_address { env.parachain_state_mut(|| { let curr_contract = DomainAddress::EVM(CHAIN_ID, CONTRACT_ACCOUNT); + assert_ok!(pallet_liquidity_pools_gateway::Pallet::::set_routers( + RawOrigin::Root.into(), + BoundedVec::try_from(vec![ROUTER_ID]).unwrap(), + )); + assert_ok!( pallet_transfer_allowlist::Pallet::::add_transfer_allowance( RawOrigin::Signed(Keyring::Alice.into()).into(),