Split payload types (#383)

* split payloads (inbound/outbound/opaque/dispatch) + fees (inbound/outbound)

* added tests

Co-authored-by: Hernando Castano <castano.ha@gmail.com>
This commit is contained in:
Svyatoslav Nikolsky
2020-09-28 23:48:58 +03:00
committed by Bastian Köcher
parent be050bda84
commit 7f7d62d813
6 changed files with 178 additions and 85 deletions
@@ -17,13 +17,12 @@
//! Everything about incoming messages receival. //! Everything about incoming messages receival.
use bp_message_lane::{ use bp_message_lane::{
target_chain::MessageDispatch, InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
InboundLaneData, LaneId, MessageKey, MessageNonce,
}; };
/// Inbound lane storage. /// Inbound lane storage.
pub trait InboundLaneStorage { pub trait InboundLaneStorage {
/// Message payload.
type Payload;
/// Delivery and dispatch fee type on source chain. /// Delivery and dispatch fee type on source chain.
type MessageFee; type MessageFee;
@@ -47,10 +46,10 @@ impl<S: InboundLaneStorage> InboundLane<S> {
} }
/// Receive new message. /// Receive new message.
pub fn receive_message<P: MessageDispatch<S::Payload, S::MessageFee>>( pub fn receive_message<P: MessageDispatch<S::MessageFee>>(
&mut self, &mut self,
nonce: MessageNonce, nonce: MessageNonce,
message_data: MessageData<S::Payload, S::MessageFee>, message_data: DispatchMessageData<P::DispatchPayload, S::MessageFee>,
) -> bool { ) -> bool {
let mut data = self.storage.data(); let mut data = self.storage.data();
let is_correct_message = nonce == data.latest_received_nonce + 1; let is_correct_message = nonce == data.latest_received_nonce + 1;
@@ -61,7 +60,7 @@ impl<S: InboundLaneStorage> InboundLane<S> {
data.latest_received_nonce = nonce; data.latest_received_nonce = nonce;
self.storage.set_data(data); self.storage.set_data(data);
P::dispatch(Message { P::dispatch(DispatchMessage {
key: MessageKey { key: MessageKey {
lane_id: self.storage.id(), lane_id: self.storage.id(),
nonce, nonce,
@@ -85,7 +84,7 @@ mod tests {
fn fails_to_receive_message_with_incorrect_nonce() { fn fails_to_receive_message_with_incorrect_nonce() {
run_test(|| { run_test(|| {
let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID); let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID);
assert!(!lane.receive_message::<TestMessageDispatch>(10, message_data(REGULAR_PAYLOAD))); assert!(!lane.receive_message::<TestMessageDispatch>(10, message_data(REGULAR_PAYLOAD).into()));
assert_eq!(lane.storage.data().latest_received_nonce, 0); assert_eq!(lane.storage.data().latest_received_nonce, 0);
}); });
} }
@@ -94,7 +93,7 @@ mod tests {
fn correct_message_is_processed_instantly() { fn correct_message_is_processed_instantly() {
run_test(|| { run_test(|| {
let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID); let mut lane = inbound_lane::<TestRuntime, _>(TEST_LANE_ID);
assert!(lane.receive_message::<TestMessageDispatch>(1, message_data(REGULAR_PAYLOAD))); assert!(lane.receive_message::<TestMessageDispatch>(1, message_data(REGULAR_PAYLOAD).into()));
assert_eq!(lane.storage.data().latest_received_nonce, 1); assert_eq!(lane.storage.data().latest_received_nonce, 1);
}); });
} }
+75 -46
View File
@@ -37,6 +37,7 @@ use bp_message_lane::{
target_chain::{MessageDispatch, SourceHeaderChain}, target_chain::{MessageDispatch, SourceHeaderChain},
InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, OutboundLaneData, InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, OutboundLaneData,
}; };
use codec::{Decode, Encode};
use frame_support::{ use frame_support::{
decl_error, decl_event, decl_module, decl_storage, sp_runtime::DispatchResult, traits::Get, weights::Weight, decl_error, decl_event, decl_module, decl_storage, sp_runtime::DispatchResult, traits::Get, weights::Weight,
Parameter, StorageMap, Parameter, StorageMap,
@@ -60,41 +61,45 @@ pub trait Trait<I = DefaultInstance>: frame_system::Trait {
/// They overarching event type. /// They overarching event type.
type Event: From<Event<Self, I>> + Into<<Self as frame_system::Trait>::Event>; type Event: From<Event<Self, I>> + Into<<Self as frame_system::Trait>::Event>;
/// Message payload.
type Payload: Parameter;
/// Maximal number of messages that may be pruned during maintenance. Maintenance occurs /// Maximal number of messages that may be pruned during maintenance. Maintenance occurs
/// whenever outbound lane is updated - i.e. when new message is sent, or receival is /// whenever outbound lane is updated - i.e. when new message is sent, or receival is
/// confirmed. The reason is that if you want to use lane, you should be ready to pay /// confirmed. The reason is that if you want to use lane, you should be ready to pay
/// for it. /// for it.
type MaxMessagesToPruneAtOnce: Get<MessageNonce>; type MaxMessagesToPruneAtOnce: Get<MessageNonce>;
/// Payload type of outbound messages. This payload is dispatched on the bridged chain.
type OutboundPayload: Parameter;
/// Message fee type of outbound messages. This fee is paid on this chain.
type OutboundMessageFee: Parameter;
/// Payload type of inbound messages. This payload is dispatched on this chain.
type InboundPayload: Decode;
/// Message fee type of inbound messages. This fee is paid on the bridged chain.
type InboundMessageFee: Decode;
// Types that are used by outbound_lane (on source chain). // Types that are used by outbound_lane (on source chain).
/// Type of delivery_and_dispatch_fee on source chain.
type MessageFee: Parameter;
/// Target header chain. /// Target header chain.
type TargetHeaderChain: TargetHeaderChain<Self::Payload>; type TargetHeaderChain: TargetHeaderChain<Self::OutboundPayload>;
/// Message payload verifier. /// Message payload verifier.
type LaneMessageVerifier: LaneMessageVerifier<Self::AccountId, Self::Payload, Self::MessageFee>; type LaneMessageVerifier: LaneMessageVerifier<Self::AccountId, Self::OutboundPayload, Self::OutboundMessageFee>;
/// Message delivery payment. /// Message delivery payment.
type MessageDeliveryAndDispatchPayment: MessageDeliveryAndDispatchPayment<Self::AccountId, Self::MessageFee>; type MessageDeliveryAndDispatchPayment: MessageDeliveryAndDispatchPayment<Self::AccountId, Self::OutboundMessageFee>;
// Types that are used by inbound_lane (on target chain). // Types that are used by inbound_lane (on target chain).
/// Source header chain, as it is represented on target chain. /// Source header chain, as it is represented on target chain.
type SourceHeaderChain: SourceHeaderChain<Self::Payload, Self::MessageFee>; type SourceHeaderChain: SourceHeaderChain<Self::InboundMessageFee>;
/// Message dispatch. /// Message dispatch.
type MessageDispatch: MessageDispatch<Self::Payload, Self::MessageFee>; type MessageDispatch: MessageDispatch<Self::InboundMessageFee, DispatchPayload = Self::InboundPayload>;
} }
/// Shortcut to messages proof type for Trait. /// Shortcut to messages proof type for Trait.
type MessagesProofOf<T, I> = <<T as Trait<I>>::SourceHeaderChain as SourceHeaderChain< type MessagesProofOf<T, I> =
<T as Trait<I>>::Payload, <<T as Trait<I>>::SourceHeaderChain as SourceHeaderChain<<T as Trait<I>>::InboundMessageFee>>::MessagesProof;
<T as Trait<I>>::MessageFee,
>>::MessagesProof;
/// Shortcut to messages delivery proof type for Trait. /// Shortcut to messages delivery proof type for Trait.
type MessagesDeliveryProofOf<T, I> = type MessagesDeliveryProofOf<T, I> =
<<T as Trait<I>>::TargetHeaderChain as TargetHeaderChain<<T as Trait<I>>::Payload>>::MessagesDeliveryProof; <<T as Trait<I>>::TargetHeaderChain as TargetHeaderChain<<T as Trait<I>>::OutboundPayload>>::MessagesDeliveryProof;
decl_error! { decl_error! {
pub enum Error for Module<T: Trait<I>, I: Instance> { pub enum Error for Module<T: Trait<I>, I: Instance> {
@@ -120,7 +125,7 @@ decl_storage! {
/// Map of lane id => outbound lane data. /// Map of lane id => outbound lane data.
OutboundLanes: map hasher(blake2_128_concat) LaneId => OutboundLaneData; OutboundLanes: map hasher(blake2_128_concat) LaneId => OutboundLaneData;
/// All queued outbound messages. /// All queued outbound messages.
OutboundMessages: map hasher(blake2_128_concat) MessageKey => Option<MessageData<T::Payload, T::MessageFee>>; OutboundMessages: map hasher(blake2_128_concat) MessageKey => Option<MessageData<T::OutboundMessageFee>>;
} }
} }
@@ -147,8 +152,8 @@ decl_module! {
pub fn send_message( pub fn send_message(
origin, origin,
lane_id: LaneId, lane_id: LaneId,
payload: T::Payload, payload: T::OutboundPayload,
delivery_and_dispatch_fee: T::MessageFee, delivery_and_dispatch_fee: T::OutboundMessageFee,
) -> DispatchResult { ) -> DispatchResult {
let submitter = ensure_signed(origin)?; let submitter = ensure_signed(origin)?;
@@ -201,7 +206,7 @@ decl_module! {
// finally, save message in outbound storage and emit event // finally, save message in outbound storage and emit event
let mut lane = outbound_lane::<T, I>(lane_id); let mut lane = outbound_lane::<T, I>(lane_id);
let nonce = lane.send_message(MessageData { let nonce = lane.send_message(MessageData {
payload, payload: payload.encode(),
fee: delivery_and_dispatch_fee, fee: delivery_and_dispatch_fee,
}); });
lane.prune_messages(T::MaxMessagesToPruneAtOnce::get()); lane.prune_messages(T::MaxMessagesToPruneAtOnce::get());
@@ -238,6 +243,9 @@ decl_module! {
Error::<T, I>::InvalidMessagesProof Error::<T, I>::InvalidMessagesProof
})?; })?;
// try to decode message payloads
let messages: Vec<_> = messages.into_iter().map(Into::into).collect();
// verify that relayer is paying actual dispatch weight // verify that relayer is paying actual dispatch weight
let actual_dispatch_weight: Weight = messages let actual_dispatch_weight: Weight = messages
.iter() .iter()
@@ -329,8 +337,7 @@ struct RuntimeInboundLaneStorage<T, I = DefaultInstance> {
} }
impl<T: Trait<I>, I: Instance> InboundLaneStorage for RuntimeInboundLaneStorage<T, I> { impl<T: Trait<I>, I: Instance> InboundLaneStorage for RuntimeInboundLaneStorage<T, I> {
type Payload = T::Payload; type MessageFee = T::InboundMessageFee;
type MessageFee = T::MessageFee;
fn id(&self) -> LaneId { fn id(&self) -> LaneId {
self.lane_id self.lane_id
@@ -352,8 +359,7 @@ struct RuntimeOutboundLaneStorage<T, I = DefaultInstance> {
} }
impl<T: Trait<I>, I: Instance> OutboundLaneStorage for RuntimeOutboundLaneStorage<T, I> { impl<T: Trait<I>, I: Instance> OutboundLaneStorage for RuntimeOutboundLaneStorage<T, I> {
type Payload = T::Payload; type MessageFee = T::OutboundMessageFee;
type MessageFee = T::MessageFee;
fn id(&self) -> LaneId { fn id(&self) -> LaneId {
self.lane_id self.lane_id
@@ -368,14 +374,14 @@ impl<T: Trait<I>, I: Instance> OutboundLaneStorage for RuntimeOutboundLaneStorag
} }
#[cfg(test)] #[cfg(test)]
fn message(&self, nonce: &MessageNonce) -> Option<MessageData<T::Payload, T::MessageFee>> { fn message(&self, nonce: &MessageNonce) -> Option<MessageData<T::OutboundMessageFee>> {
OutboundMessages::<T, I>::get(MessageKey { OutboundMessages::<T, I>::get(MessageKey {
lane_id: self.lane_id, lane_id: self.lane_id,
nonce: *nonce, nonce: *nonce,
}) })
} }
fn save_message(&mut self, nonce: MessageNonce, mesage_data: MessageData<T::Payload, T::MessageFee>) { fn save_message(&mut self, nonce: MessageNonce, mesage_data: MessageData<T::OutboundMessageFee>) {
OutboundMessages::<T, I>::insert( OutboundMessages::<T, I>::insert(
MessageKey { MessageKey {
lane_id: self.lane_id, lane_id: self.lane_id,
@@ -397,10 +403,9 @@ impl<T: Trait<I>, I: Instance> OutboundLaneStorage for RuntimeOutboundLaneStorag
mod tests { mod tests {
use super::*; use super::*;
use crate::mock::{ use crate::mock::{
run_test, Origin, TestEvent, TestMessageDeliveryAndDispatchPayment, TestRuntime, message, run_test, Origin, TestEvent, TestMessageDeliveryAndDispatchPayment, TestRuntime,
PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID,
}; };
use bp_message_lane::Message;
use frame_support::{assert_noop, assert_ok}; use frame_support::{assert_noop, assert_ok};
use frame_system::{EventRecord, Module as System, Phase}; use frame_system::{EventRecord, Module as System, Phase};
@@ -503,16 +508,7 @@ mod tests {
run_test(|| { run_test(|| {
assert_ok!(Module::<TestRuntime>::receive_messages_proof( assert_ok!(Module::<TestRuntime>::receive_messages_proof(
Origin::signed(1), Origin::signed(1),
Ok(vec![Message { Ok(vec![message(1, REGULAR_PAYLOAD)]),
key: MessageKey {
lane_id: TEST_LANE_ID,
nonce: 1,
},
data: MessageData {
payload: REGULAR_PAYLOAD,
fee: 0,
},
}]),
REGULAR_PAYLOAD.1, REGULAR_PAYLOAD.1,
)); ));
@@ -529,16 +525,7 @@ mod tests {
assert_noop!( assert_noop!(
Module::<TestRuntime>::receive_messages_proof( Module::<TestRuntime>::receive_messages_proof(
Origin::signed(1), Origin::signed(1),
Ok(vec![Message { Ok(vec![message(1, REGULAR_PAYLOAD)]),
key: MessageKey {
lane_id: TEST_LANE_ID,
nonce: 1,
},
data: MessageData {
payload: REGULAR_PAYLOAD,
fee: 0,
},
}]),
REGULAR_PAYLOAD.1 - 1, REGULAR_PAYLOAD.1 - 1,
), ),
Error::<TestRuntime, DefaultInstance>::InvalidMessagesDispatchWeight, Error::<TestRuntime, DefaultInstance>::InvalidMessagesDispatchWeight,
@@ -578,4 +565,46 @@ mod tests {
); );
}); });
} }
#[test]
fn receive_messages_accepts_single_message_with_invalid_payload() {
run_test(|| {
let mut invalid_message = message(1, REGULAR_PAYLOAD);
invalid_message.data.payload = Vec::new();
assert_ok!(Module::<TestRuntime, DefaultInstance>::receive_messages_proof(
Origin::signed(1),
Ok(vec![invalid_message]),
0, // weight may be zero in this case (all messages are improperly encoded)
),);
assert_eq!(
InboundLanes::<DefaultInstance>::get(&TEST_LANE_ID).latest_received_nonce,
1,
);
});
}
#[test]
fn receive_messages_accepts_batch_with_message_with_invalid_payload() {
run_test(|| {
let mut invalid_message = message(2, REGULAR_PAYLOAD);
invalid_message.data.payload = Vec::new();
assert_ok!(Module::<TestRuntime, DefaultInstance>::receive_messages_proof(
Origin::signed(1),
Ok(vec![
message(1, REGULAR_PAYLOAD),
invalid_message,
message(3, REGULAR_PAYLOAD),
]),
REGULAR_PAYLOAD.1 + REGULAR_PAYLOAD.1,
),);
assert_eq!(
InboundLanes::<DefaultInstance>::get(&TEST_LANE_ID).latest_received_nonce,
3,
);
});
}
} }
+37 -15
View File
@@ -18,9 +18,10 @@ use crate::Trait;
use bp_message_lane::{ use bp_message_lane::{
source_chain::{LaneMessageVerifier, MessageDeliveryAndDispatchPayment, TargetHeaderChain}, source_chain::{LaneMessageVerifier, MessageDeliveryAndDispatchPayment, TargetHeaderChain},
target_chain::{MessageDispatch, SourceHeaderChain}, target_chain::{DispatchMessage, MessageDispatch, SourceHeaderChain},
LaneId, Message, MessageData, MessageNonce, LaneId, Message, MessageData, MessageKey, MessageNonce,
}; };
use codec::Encode;
use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight}; use frame_support::{impl_outer_event, impl_outer_origin, parameter_types, weights::Weight};
use sp_core::H256; use sp_core::H256;
use sp_runtime::{ use sp_runtime::{
@@ -92,10 +93,14 @@ parameter_types! {
impl Trait for TestRuntime { impl Trait for TestRuntime {
type Event = TestEvent; type Event = TestEvent;
type Payload = TestPayload;
type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
type MessageFee = TestMessageFee; type OutboundPayload = TestPayload;
type OutboundMessageFee = TestMessageFee;
type InboundPayload = TestPayload;
type InboundMessageFee = TestMessageFee;
type TargetHeaderChain = TestTargetHeaderChain; type TargetHeaderChain = TestTargetHeaderChain;
type LaneMessageVerifier = TestLaneMessageVerifier; type LaneMessageVerifier = TestLaneMessageVerifier;
type MessageDeliveryAndDispatchPayment = TestMessageDeliveryAndDispatchPayment; type MessageDeliveryAndDispatchPayment = TestMessageDeliveryAndDispatchPayment;
@@ -194,14 +199,12 @@ impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee> for TestMessag
#[derive(Debug)] #[derive(Debug)]
pub struct TestSourceHeaderChain; pub struct TestSourceHeaderChain;
impl SourceHeaderChain<TestPayload, TestMessageFee> for TestSourceHeaderChain { impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
type Error = &'static str; type Error = &'static str;
type MessagesProof = Result<Vec<Message<TestPayload, TestMessageFee>>, ()>; type MessagesProof = Result<Vec<Message<TestMessageFee>>, ()>;
fn verify_messages_proof( fn verify_messages_proof(proof: Self::MessagesProof) -> Result<Vec<Message<TestMessageFee>>, Self::Error> {
proof: Self::MessagesProof,
) -> Result<Vec<Message<TestPayload, TestMessageFee>>, Self::Error> {
proof.map_err(|_| TEST_ERROR) proof.map_err(|_| TEST_ERROR)
} }
} }
@@ -210,17 +213,36 @@ impl SourceHeaderChain<TestPayload, TestMessageFee> for TestSourceHeaderChain {
#[derive(Debug)] #[derive(Debug)]
pub struct TestMessageDispatch; pub struct TestMessageDispatch;
impl MessageDispatch<TestPayload, TestMessageFee> for TestMessageDispatch { impl MessageDispatch<TestMessageFee> for TestMessageDispatch {
fn dispatch_weight(message: &Message<TestPayload, TestMessageFee>) -> Weight { type DispatchPayload = TestPayload;
message.data.payload.1
fn dispatch_weight(message: &DispatchMessage<TestPayload, TestMessageFee>) -> Weight {
match message.data.payload.as_ref() {
Ok(payload) => payload.1,
Err(_) => 0,
}
} }
fn dispatch(_message: Message<TestPayload, TestMessageFee>) {} fn dispatch(_message: DispatchMessage<TestPayload, TestMessageFee>) {}
}
/// Return test lane message with given nonce and payload.
pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message<TestMessageFee> {
Message {
key: MessageKey {
lane_id: TEST_LANE_ID,
nonce,
},
data: message_data(payload),
}
} }
/// Return message data with valid fee for given payload. /// Return message data with valid fee for given payload.
pub fn message_data(payload: TestPayload) -> MessageData<TestPayload, TestMessageFee> { pub fn message_data(payload: TestPayload) -> MessageData<TestMessageFee> {
MessageData { payload, fee: 1 } MessageData {
payload: payload.encode(),
fee: 1,
}
} }
/// Run message lane test. /// Run message lane test.
@@ -20,8 +20,6 @@ use bp_message_lane::{LaneId, MessageData, MessageNonce, OutboundLaneData};
/// Outbound lane storage. /// Outbound lane storage.
pub trait OutboundLaneStorage { pub trait OutboundLaneStorage {
/// Message payload.
type Payload;
/// Delivery and dispatch fee type on source chain. /// Delivery and dispatch fee type on source chain.
type MessageFee; type MessageFee;
@@ -33,9 +31,9 @@ pub trait OutboundLaneStorage {
fn set_data(&mut self, data: OutboundLaneData); fn set_data(&mut self, data: OutboundLaneData);
/// Returns saved outbound message payload. /// Returns saved outbound message payload.
#[cfg(test)] #[cfg(test)]
fn message(&self, nonce: &MessageNonce) -> Option<MessageData<Self::Payload, Self::MessageFee>>; fn message(&self, nonce: &MessageNonce) -> Option<MessageData<Self::MessageFee>>;
/// Save outbound message in the storage. /// Save outbound message in the storage.
fn save_message(&mut self, nonce: MessageNonce, message_data: MessageData<Self::Payload, Self::MessageFee>); fn save_message(&mut self, nonce: MessageNonce, message_data: MessageData<Self::MessageFee>);
/// Remove outbound message from the storage. /// Remove outbound message from the storage.
fn remove_message(&mut self, nonce: &MessageNonce); fn remove_message(&mut self, nonce: &MessageNonce);
} }
@@ -54,7 +52,7 @@ impl<S: OutboundLaneStorage> OutboundLane<S> {
/// Send message over lane. /// Send message over lane.
/// ///
/// Returns new message nonce. /// Returns new message nonce.
pub fn send_message(&mut self, message_data: MessageData<S::Payload, S::MessageFee>) -> MessageNonce { pub fn send_message(&mut self, message_data: MessageData<S::MessageFee>) -> MessageNonce {
let mut data = self.storage.data(); let mut data = self.storage.data();
let nonce = data.latest_generated_nonce + 1; let nonce = data.latest_generated_nonce + 1;
data.latest_generated_nonce = nonce; data.latest_generated_nonce = nonce;
+7 -4
View File
@@ -39,6 +39,9 @@ pub type MessageNonce = u64;
/// Message id as a tuple. /// Message id as a tuple.
pub type MessageId = (LaneId, MessageNonce); pub type MessageId = (LaneId, MessageNonce);
/// Opaque message payload. We only decode this payload when it is dispatched.
pub type MessagePayload = Vec<u8>;
/// Message key (unique message identifier) as it is stored in the storage. /// Message key (unique message identifier) as it is stored in the storage.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct MessageKey { pub struct MessageKey {
@@ -50,20 +53,20 @@ pub struct MessageKey {
/// Message data as it is stored in the storage. /// Message data as it is stored in the storage.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct MessageData<Payload, Fee> { pub struct MessageData<Fee> {
/// Message payload. /// Message payload.
pub payload: Payload, pub payload: MessagePayload,
/// Message delivery and dispatch fee, paid by the submitter. /// Message delivery and dispatch fee, paid by the submitter.
pub fee: Fee, pub fee: Fee,
} }
/// Message as it is stored in the storage. /// Message as it is stored in the storage.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct Message<Payload, Fee> { pub struct Message<Fee> {
/// Message key. /// Message key.
pub key: MessageKey, pub key: MessageKey,
/// Message data. /// Message data.
pub data: MessageData<Payload, Fee>, pub data: MessageData<Fee>,
} }
/// Inbound lane data. /// Inbound lane data.
@@ -16,17 +16,36 @@
//! Primitives of message lane module, that are used on the target chain. //! Primitives of message lane module, that are used on the target chain.
use crate::Message; use crate::{Message, MessageData, MessageKey};
use frame_support::{weights::Weight, Parameter}; use codec::{Decode, Error as CodecError};
use frame_support::{weights::Weight, Parameter, RuntimeDebug};
use sp_std::{fmt::Debug, prelude::*}; use sp_std::{fmt::Debug, prelude::*};
/// Message data with decoded dispatch payload.
#[derive(RuntimeDebug)]
pub struct DispatchMessageData<DispatchPayload, Fee> {
/// Result of dispatch payload decoding.
pub payload: Result<DispatchPayload, CodecError>,
/// Message delivery and dispatch fee, paid by the submitter.
pub fee: Fee,
}
/// Message with decoded dispatch payload.
#[derive(RuntimeDebug)]
pub struct DispatchMessage<DispatchPayload, Fee> {
/// Message key.
pub key: MessageKey,
/// Message data with decoded dispatch payload.
pub data: DispatchMessageData<DispatchPayload, Fee>,
}
/// Source chain API. Used by target chain, to verify source chain proofs. /// Source chain API. Used by target chain, to verify source chain proofs.
/// ///
/// All implementations of this trait should only work with finalized data that /// All implementations of this trait should only work with finalized data that
/// can't change. Wrong implementation may lead to invalid lane states (i.e. lane /// can't change. Wrong implementation may lead to invalid lane states (i.e. lane
/// that's stuck) and/or processing messages without paying fees. /// that's stuck) and/or processing messages without paying fees.
pub trait SourceHeaderChain<Payload, Fee> { pub trait SourceHeaderChain<Fee> {
/// Error type. /// Error type.
type Error: Debug + Into<&'static str>; type Error: Debug + Into<&'static str>;
@@ -37,20 +56,43 @@ pub trait SourceHeaderChain<Payload, Fee> {
/// ///
/// Messages vector is required to be sorted by nonce within each lane. Out-of-order /// Messages vector is required to be sorted by nonce within each lane. Out-of-order
/// messages will be rejected. /// messages will be rejected.
fn verify_messages_proof(proof: Self::MessagesProof) -> Result<Vec<Message<Payload, Fee>>, Self::Error>; fn verify_messages_proof(proof: Self::MessagesProof) -> Result<Vec<Message<Fee>>, Self::Error>;
} }
/// Called when inbound message is received. /// Called when inbound message is received.
pub trait MessageDispatch<Payload, Fee> { pub trait MessageDispatch<Fee> {
/// Decoded message payload type. Valid message may contain invalid payload. In this case
/// message is delivered, but dispatch fails. Therefore, two separate types of payload
/// (opaque `MessagePayload` used in delivery and this `DispatchPayload` used in dispatch).
type DispatchPayload: Decode;
/// Estimate dispatch weight. /// Estimate dispatch weight.
/// ///
/// This function must: (1) be instant and (2) return correct upper bound /// This function must: (1) be instant and (2) return correct upper bound
/// of dispatch weight. /// of dispatch weight.
fn dispatch_weight(message: &Message<Payload, Fee>) -> Weight; fn dispatch_weight(message: &DispatchMessage<Self::DispatchPayload, Fee>) -> Weight;
/// Called when inbound message is received. /// Called when inbound message is received.
/// ///
/// It is up to the implementers of this trait to determine whether the message /// It is up to the implementers of this trait to determine whether the message
/// is invalid (i.e. improperly encoded, has too large weight, ...) or not. /// is invalid (i.e. improperly encoded, has too large weight, ...) or not.
fn dispatch(message: Message<Payload, Fee>); fn dispatch(message: DispatchMessage<Self::DispatchPayload, Fee>);
}
impl<DispatchPayload: Decode, Fee> From<Message<Fee>> for DispatchMessage<DispatchPayload, Fee> {
fn from(message: Message<Fee>) -> Self {
DispatchMessage {
key: message.key,
data: message.data.into(),
}
}
}
impl<DispatchPayload: Decode, Fee> From<MessageData<Fee>> for DispatchMessageData<DispatchPayload, Fee> {
fn from(data: MessageData<Fee>) -> Self {
DispatchMessageData {
payload: DispatchPayload::decode(&mut &data.payload[..]),
fee: data.fee,
}
}
} }