mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 05:11:09 +00:00
Verify Source origin in TargetChainVerifier (#558)
* Make sure to verify sender's origin. * Make sure to use dispatch verification. * Add tests. * cargo fmt --all * Remove superfluous lifetime. * Move the check to MessageLanVerifier. * cargo fmt --all * Fix docs.
This commit is contained in:
committed by
Bastian Köcher
parent
f57b7e9de0
commit
6f6c8c2417
@@ -30,11 +30,12 @@ use codec::{Decode, Encode};
|
||||
use frame_support::{
|
||||
decl_event, decl_module, decl_storage,
|
||||
dispatch::{Dispatchable, Parameter},
|
||||
ensure,
|
||||
traits::Get,
|
||||
weights::{extract_actual_weight, GetDispatchInfo},
|
||||
RuntimeDebug,
|
||||
};
|
||||
use frame_system::{ensure_root, ensure_signed, RawOrigin};
|
||||
use frame_system::RawOrigin;
|
||||
use sp_runtime::{
|
||||
traits::{BadOrigin, Convert, IdentifyAccount, MaybeDisplay, MaybeSerializeDeserialize, Member, Verify},
|
||||
DispatchResult,
|
||||
@@ -266,39 +267,31 @@ impl<T: Trait<I>, I: Instance> MessageDispatch<T::MessageId> for Module<T, I> {
|
||||
/// For example, if a message is sent from a "regular" account on the source chain it will not be
|
||||
/// allowed to be dispatched as Root on the target chain. This is a useful check to do on the source
|
||||
/// chain _before_ sending a message whose dispatch will be rejected on the target chain.
|
||||
pub fn verify_message_origin<
|
||||
SourceChainOuterOrigin,
|
||||
SourceChainAccountId,
|
||||
TargetChainAccountPublic,
|
||||
TargetChainSignature,
|
||||
Call,
|
||||
>(
|
||||
sender_origin: SourceChainOuterOrigin,
|
||||
pub fn verify_message_origin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Call>(
|
||||
sender_origin: &RawOrigin<SourceChainAccountId>,
|
||||
message: &MessagePayload<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Call>,
|
||||
) -> Result<Option<SourceChainAccountId>, BadOrigin>
|
||||
where
|
||||
SourceChainOuterOrigin: Into<Result<RawOrigin<SourceChainAccountId>, SourceChainOuterOrigin>>,
|
||||
SourceChainAccountId: PartialEq,
|
||||
SourceChainAccountId: PartialEq + Clone,
|
||||
{
|
||||
match message.origin {
|
||||
CallOrigin::SourceRoot => {
|
||||
ensure_root(sender_origin)?;
|
||||
ensure!(sender_origin == &RawOrigin::Root, BadOrigin);
|
||||
Ok(None)
|
||||
}
|
||||
CallOrigin::TargetAccount(ref source_account_id, _, _) => {
|
||||
let source_chain_signer = ensure_signed(sender_origin)?;
|
||||
if source_chain_signer != *source_account_id {
|
||||
return Err(BadOrigin);
|
||||
}
|
||||
|
||||
Ok(Some(source_chain_signer))
|
||||
ensure!(
|
||||
sender_origin == &RawOrigin::Signed(source_account_id.clone()),
|
||||
BadOrigin
|
||||
);
|
||||
Ok(Some(source_account_id.clone()))
|
||||
}
|
||||
CallOrigin::SourceAccount(ref source_account_id) => {
|
||||
let source_chain_signer = ensure_signed(sender_origin)?;
|
||||
if source_chain_signer != *source_account_id {
|
||||
return Err(BadOrigin);
|
||||
}
|
||||
Ok(Some(source_chain_signer))
|
||||
ensure!(
|
||||
sender_origin == &RawOrigin::Signed(source_account_id.clone()),
|
||||
BadOrigin
|
||||
);
|
||||
Ok(Some(source_account_id.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -617,14 +610,11 @@ mod tests {
|
||||
let message = prepare_root_message(call);
|
||||
|
||||
// When message is sent by Root, CallOrigin::SourceRoot is allowed
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Root), &message),
|
||||
Ok(None)
|
||||
));
|
||||
assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Ok(None)));
|
||||
|
||||
// when message is sent by some real account, CallOrigin::SourceRoot is not allowed
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Signed(1)), &message),
|
||||
verify_message_origin(&RawOrigin::Signed(1), &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
}
|
||||
@@ -636,20 +626,20 @@ mod tests {
|
||||
|
||||
// When message is sent by Root, CallOrigin::TargetAccount is not allowed
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Root), &message),
|
||||
verify_message_origin(&RawOrigin::Root, &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
|
||||
// When message is sent by some other account, it is rejected
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Signed(2)), &message),
|
||||
verify_message_origin(&RawOrigin::Signed(2), &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
|
||||
// When message is sent by a real account, it is allowed to have origin
|
||||
// CallOrigin::TargetAccount
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Signed(1)), &message),
|
||||
verify_message_origin(&RawOrigin::Signed(1), &message),
|
||||
Ok(Some(1))
|
||||
));
|
||||
}
|
||||
@@ -661,19 +651,19 @@ mod tests {
|
||||
|
||||
// Sending a message from the expected origin account works
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Signed(1)), &message),
|
||||
verify_message_origin(&RawOrigin::Signed(1), &message),
|
||||
Ok(Some(1))
|
||||
));
|
||||
|
||||
// If we send a message from a different account, it is rejected
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Signed(2)), &message),
|
||||
verify_message_origin(&RawOrigin::Signed(2), &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
|
||||
// If we try and send the message from Root, it is also rejected
|
||||
assert!(matches!(
|
||||
verify_message_origin(Origin::from(RawOrigin::Root), &message),
|
||||
verify_message_origin(&RawOrigin::Root, &message),
|
||||
Err(BadOrigin)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Implementation of `MessageDeliveryAndDispatchPayment` trait on top of `Currency` trait.
|
||||
//! All payments are instant.
|
||||
|
||||
use bp_message_lane::source_chain::MessageDeliveryAndDispatchPayment;
|
||||
use bp_message_lane::source_chain::{MessageDeliveryAndDispatchPayment, Sender};
|
||||
use codec::Encode;
|
||||
use frame_support::traits::{Currency as CurrencyT, ExistenceRequirement};
|
||||
use sp_std::fmt::Debug;
|
||||
@@ -37,11 +37,20 @@ where
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
submitter: &AccountId,
|
||||
submitter: &Sender<AccountId>,
|
||||
fee: &Currency::Balance,
|
||||
relayer_fund_account: &AccountId,
|
||||
) -> Result<(), Self::Error> {
|
||||
Currency::transfer(submitter, relayer_fund_account, *fee, ExistenceRequirement::AllowDeath).map_err(Into::into)
|
||||
match submitter {
|
||||
Sender::Signed(submitter) => {
|
||||
Currency::transfer(submitter, relayer_fund_account, *fee, ExistenceRequirement::AllowDeath)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
Sender::Root | Sender::None => {
|
||||
// fixme: we might want to add root account id to this struct.
|
||||
Err("Root and None account is not allowed to send regular messages.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pay_relayer_reward(
|
||||
|
||||
@@ -255,18 +255,19 @@ decl_module! {
|
||||
delivery_and_dispatch_fee: T::OutboundMessageFee,
|
||||
) -> DispatchResult {
|
||||
ensure_operational::<T, I>()?;
|
||||
let submitter = ensure_signed(origin)?;
|
||||
let submitter = origin.into().map_err(|_| BadOrigin)?;
|
||||
|
||||
// let's first check if message can be delivered to target chain
|
||||
T::TargetHeaderChain::verify_message(&payload).map_err(|err| {
|
||||
frame_support::debug::trace!(
|
||||
"Message to lane {:?} is rejected by target chain: {:?}",
|
||||
lane_id,
|
||||
err,
|
||||
);
|
||||
T::TargetHeaderChain::verify_message(&payload)
|
||||
.map_err(|err| {
|
||||
frame_support::debug::trace!(
|
||||
"Message to lane {:?} is rejected by target chain: {:?}",
|
||||
lane_id,
|
||||
err,
|
||||
);
|
||||
|
||||
Error::<T, I>::MessageRejectedByChainVerifier
|
||||
})?;
|
||||
Error::<T, I>::MessageRejectedByChainVerifier
|
||||
})?;
|
||||
|
||||
// now let's enforce any additional lane rules
|
||||
T::LaneMessageVerifier::verify_message(
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use crate::Trait;
|
||||
|
||||
use bp_message_lane::{
|
||||
source_chain::{LaneMessageVerifier, MessageDeliveryAndDispatchPayment, TargetHeaderChain},
|
||||
source_chain::{LaneMessageVerifier, MessageDeliveryAndDispatchPayment, Sender, TargetHeaderChain},
|
||||
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain},
|
||||
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce,
|
||||
};
|
||||
@@ -209,7 +209,7 @@ impl LaneMessageVerifier<AccountId, TestPayload, TestMessageFee> for TestLaneMes
|
||||
type Error = &'static str;
|
||||
|
||||
fn verify_message(
|
||||
_submitter: &AccountId,
|
||||
_submitter: &Sender<AccountId>,
|
||||
delivery_and_dispatch_fee: &TestMessageFee,
|
||||
_lane: &LaneId,
|
||||
_payload: &TestPayload,
|
||||
@@ -234,7 +234,7 @@ impl TestMessageDeliveryAndDispatchPayment {
|
||||
|
||||
/// Returns true if given fee has been paid by given submitter.
|
||||
pub fn is_fee_paid(submitter: AccountId, fee: TestMessageFee) -> bool {
|
||||
frame_support::storage::unhashed::get(b":message-fee:") == Some((submitter, fee))
|
||||
frame_support::storage::unhashed::get(b":message-fee:") == Some((Sender::Signed(submitter), fee))
|
||||
}
|
||||
|
||||
/// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is
|
||||
@@ -249,7 +249,7 @@ impl MessageDeliveryAndDispatchPayment<AccountId, TestMessageFee> for TestMessag
|
||||
type Error = &'static str;
|
||||
|
||||
fn pay_delivery_and_dispatch_fee(
|
||||
submitter: &AccountId,
|
||||
submitter: &Sender<AccountId>,
|
||||
fee: &TestMessageFee,
|
||||
_relayer_fund_account: &AccountId,
|
||||
) -> Result<(), Self::Error> {
|
||||
|
||||
Reference in New Issue
Block a user