Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions bin/millau/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bridge-runtime-common = { path = "../../runtime-common", default-features = fals
pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false }
pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
pallet-bridge-token-swap = { path = "../../../modules/token-swap", default-features = false }
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }

# Substrate Dependencies
Expand Down Expand Up @@ -77,6 +78,7 @@ std = [
"pallet-bridge-dispatch/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-bridge-token-swap/std",
"pallet-grandpa/std",
"pallet-randomness-collective-flip/std",
"pallet-session/std",
Expand Down
52 changes: 41 additions & 11 deletions bin/millau/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ parameter_types! {
pub const GetDeliveryConfirmationTransactionFee: Balance =
bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _;
pub const RootAccountForPayments: Option<AccountId> = None;
pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID;
pub const RialtoChainId: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID;
}

/// Instance of the messages pallet used to relay messages to/from Rialto chain.
Expand Down Expand Up @@ -394,11 +394,31 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
GetDeliveryConfirmationTransactionFee,
RootAccountForPayments,
>;
type OnDeliveryConfirmed = ();
type OnDeliveryConfirmed = pallet_bridge_token_swap::Pallet<Runtime, WithRialtoTokenSwapInstance>;

type SourceHeaderChain = crate::rialto_messages::Rialto;
type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch;
type BridgedChainId = BridgedChainId;
type BridgedChainId = RialtoChainId;
}

parameter_types! {
pub const TokenSwapMessagesLane: bp_messages::LaneId = *b"swap";
}

/// Instance of the with-Rialto token swap pallet.
pub type WithRialtoTokenSwapInstance = ();

impl pallet_bridge_token_swap::Config<WithRialtoTokenSwapInstance> for Runtime {
type Event = Event;

type BridgedChainId = RialtoChainId;
type OutboundMessageLaneId = TokenSwapMessagesLane;
type MessagesBridge = pallet_bridge_messages::Pallet<Runtime, WithRialtoMessagesInstance>;
type ThisCurrency = pallet_balances::Pallet<Runtime>;
type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter;

type BridgedChain = bp_rialto::Rialto;
type FromBridgedToThisAccountIdConverter = bp_millau::AccountIdConverter;
}

construct_runtime!(
Expand All @@ -407,20 +427,30 @@ construct_runtime!(
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},

// Must be before session.
Aura: pallet_aura::{Pallet, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},

Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},

// Consensus support.
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
ShiftSessionManager: pallet_shift_session_manager::{Pallet},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},

// Rialto bridge modules.
BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
BridgeRialtoTokenSwap: pallet_bridge_token_swap::{Pallet, Call, Storage, Event<T>},

// Westend bridge modules.
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
}
);

Expand Down
2 changes: 1 addition & 1 deletion bin/millau/runtime/src/rialto_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl messages::ThisChainWithMessages for Millau {
type Call = crate::Call;

fn is_outbound_lane_enabled(lane: &LaneId) -> bool {
*lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1]
*lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1] || *lane == crate::TokenSwapMessagesLane::get()
}

fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
Expand Down
219 changes: 131 additions & 88 deletions modules/messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ use bp_messages::{
};
use bp_runtime::{ChainId, Size};
use codec::{Decode, Encode};
use frame_support::{fail, traits::Get, weights::PostDispatchInfo};
use frame_support::{
fail,
traits::Get,
weights::{Pays, PostDispatchInfo},
};
use frame_system::RawOrigin;
use num_traits::{SaturatingAdd, Zero};
use sp_runtime::traits::BadOrigin;
Expand Down Expand Up @@ -241,94 +245,13 @@ pub mod pallet {
payload: T::OutboundPayload,
delivery_and_dispatch_fee: T::OutboundMessageFee,
) -> DispatchResultWithPostInfo {
ensure_normal_operating_mode::<T, I>()?;
let submitter = origin.into().map_err(|_| BadOrigin)?;

// initially, actual (post-dispatch) weight is equal to pre-dispatch weight
let mut actual_weight = T::WeightInfo::send_message_weight(&payload);

// let's first check if message can be delivered to target chain
T::TargetHeaderChain::verify_message(&payload).map_err(|err| {
log::trace!(
target: "runtime::bridge-messages",
"Message to lane {:?} is rejected by target chain: {:?}",
lane_id,
err,
);

Error::<T, I>::MessageRejectedByChainVerifier
})?;

// now let's enforce any additional lane rules
let mut lane = outbound_lane::<T, I>(lane_id);
T::LaneMessageVerifier::verify_message(
&submitter,
&delivery_and_dispatch_fee,
&lane_id,
&lane.data(),
&payload,
)
.map_err(|err| {
log::trace!(
target: "runtime::bridge-messages",
"Message to lane {:?} is rejected by lane verifier: {:?}",
lane_id,
err,
);

Error::<T, I>::MessageRejectedByLaneVerifier
})?;

// let's withdraw delivery and dispatch fee from submitter
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
&submitter,
&delivery_and_dispatch_fee,
&Self::relayer_fund_account_id(),
)
.map_err(|err| {
log::trace!(
target: "runtime::bridge-messages",
"Message to lane {:?} is rejected because submitter {:?} is unable to pay fee {:?}: {:?}",
lane_id,
submitter,
delivery_and_dispatch_fee,
err,
);

Error::<T, I>::FailedToWithdrawMessageFee
})?;

// finally, save message in outbound storage and emit event
let encoded_payload = payload.encode();
let encoded_payload_len = encoded_payload.len();
let nonce = lane.send_message(MessageData {
payload: encoded_payload,
fee: delivery_and_dispatch_fee,
});

// message sender pays for pruning at most `MaxMessagesToPruneAtOnce` messages
// the cost of pruning every message is roughly single db write
// => lets refund sender if less than `MaxMessagesToPruneAtOnce` messages pruned
let max_messages_to_prune = T::MaxMessagesToPruneAtOnce::get();
let pruned_messages = lane.prune_messages(max_messages_to_prune);
if let Some(extra_messages) = max_messages_to_prune.checked_sub(pruned_messages) {
actual_weight = actual_weight.saturating_sub(T::DbWeight::get().writes(extra_messages));
}

log::trace!(
target: "runtime::bridge-messages",
"Accepted message {} to lane {:?}. Message size: {:?}",
nonce,
crate::send_message::<T, I>(
origin.into().map_err(|_| BadOrigin)?,
lane_id,
encoded_payload_len,
);

Self::deposit_event(Event::MessageAccepted(lane_id, nonce));

Ok(PostDispatchInfo {
actual_weight: Some(actual_weight),
pays_fee: Pays::Yes,
})
payload,
delivery_and_dispatch_fee,
)
.map(|sent_message| sent_message.post_dispatch_info)
}

/// Pay additional fee for the message.
Expand Down Expand Up @@ -899,6 +822,126 @@ pub mod storage_keys {
}
}

impl<T, I> bp_messages::source_chain::MessagesBridge<T::AccountId, T::OutboundMessageFee, T::OutboundPayload>
for Pallet<T, I>
where
T: Config<I>,
I: 'static,
{
type Error = sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>;

fn send_message(
sender: bp_messages::source_chain::Sender<T::AccountId>,
lane: LaneId,
message: T::OutboundPayload,
delivery_and_dispatch_fee: T::OutboundMessageFee,
) -> Result<MessageNonce, Self::Error> {
crate::send_message::<T, I>(sender, lane, message, delivery_and_dispatch_fee)
.map(|sent_message| sent_message.nonce)
}
}

/// Message that has been sent.
struct SentMessage {
/// Nonce of the message.
pub nonce: MessageNonce,
/// Post-dispatch call info.
pub post_dispatch_info: PostDispatchInfo,
}

/// Function that actually sends message.
fn send_message<T: Config<I>, I: 'static>(
submitter: bp_messages::source_chain::Sender<T::AccountId>,
lane_id: LaneId,
payload: T::OutboundPayload,
delivery_and_dispatch_fee: T::OutboundMessageFee,
) -> sp_std::result::Result<SentMessage, sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>> {
ensure_normal_operating_mode::<T, I>()?;

// initially, actual (post-dispatch) weight is equal to pre-dispatch weight
let mut actual_weight = T::WeightInfo::send_message_weight(&payload);

// let's first check if message can be delivered to target chain
T::TargetHeaderChain::verify_message(&payload).map_err(|err| {
log::trace!(
target: "runtime::bridge-messages",
"Message to lane {:?} is rejected by target chain: {:?}",
lane_id,
err,
);

Error::<T, I>::MessageRejectedByChainVerifier
})?;

// now let's enforce any additional lane rules
let mut lane = outbound_lane::<T, I>(lane_id);
T::LaneMessageVerifier::verify_message(&submitter, &delivery_and_dispatch_fee, &lane_id, &lane.data(), &payload)
.map_err(|err| {
log::trace!(
target: "runtime::bridge-messages",
"Message to lane {:?} is rejected by lane verifier: {:?}",
lane_id,
err,
);

Error::<T, I>::MessageRejectedByLaneVerifier
})?;

// let's withdraw delivery and dispatch fee from submitter
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
&submitter,
&delivery_and_dispatch_fee,
&Pallet::<T, I>::relayer_fund_account_id(),
)
.map_err(|err| {
log::trace!(
target: "runtime::bridge-messages",
"Message to lane {:?} is rejected because submitter {:?} is unable to pay fee {:?}: {:?}",
lane_id,
submitter,
delivery_and_dispatch_fee,
err,
);

Error::<T, I>::FailedToWithdrawMessageFee
})?;

// finally, save message in outbound storage and emit event
let encoded_payload = payload.encode();
let encoded_payload_len = encoded_payload.len();
let nonce = lane.send_message(MessageData {
payload: encoded_payload,
fee: delivery_and_dispatch_fee,
});

// message sender pays for pruning at most `MaxMessagesToPruneAtOnce` messages
// the cost of pruning every message is roughly single db write
// => lets refund sender if less than `MaxMessagesToPruneAtOnce` messages pruned
let max_messages_to_prune = T::MaxMessagesToPruneAtOnce::get();
let pruned_messages = lane.prune_messages(max_messages_to_prune);
if let Some(extra_messages) = max_messages_to_prune.checked_sub(pruned_messages) {
actual_weight = actual_weight.saturating_sub(T::DbWeight::get().writes(extra_messages));
}

log::trace!(
target: "runtime::bridge-messages",
"Accepted message {} to lane {:?}. Message size: {:?}",
nonce,
lane_id,
encoded_payload_len,
);

Pallet::<T, I>::deposit_event(Event::MessageAccepted(lane_id, nonce));

Ok(SentMessage {
nonce,
post_dispatch_info: PostDispatchInfo {
actual_weight: Some(actual_weight),
pays_fee: Pays::Yes,
},
})
}

/// Ensure that the origin is either root, or `PalletOwner`.
fn ensure_owner_or_root<T: Config<I>, I: 'static>(origin: T::Origin) -> Result<(), BadOrigin> {
match origin.into() {
Expand Down
2 changes: 1 addition & 1 deletion modules/token-swap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "mast
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }

[dev-dependencies]
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
Expand Down
Loading