mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 14:31:02 +00:00
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:
committed by
Bastian Köcher
parent
be050bda84
commit
7f7d62d813
@@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user