Skip to content
This repository has been archived by the owner on Feb 29, 2024. It is now read-only.

Sync missing changes from different branches #191

Merged
merged 4 commits into from
Sep 27, 2022
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
16 changes: 16 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions bin/runtime-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ scale-info = { version = "2.0.1", default-features = false, features = ["derive"

bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false }
bp-messages = { path = "../../primitives/messages", default-features = false }
bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false }
bp-runtime = { path = "../../primitives/runtime", default-features = false }
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-parachains = { path = "../../modules/parachains", default-features = false }

# Substrate dependencies

Expand All @@ -41,6 +43,7 @@ default = ["std"]
std = [
"bp-message-dispatch/std",
"bp-messages/std",
"bp-polkadot-core/std",
"bp-runtime/std",
"codec/std",
"frame-support/std",
Expand All @@ -49,6 +52,7 @@ std = [
"pallet-bridge-dispatch/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-bridge-parachains/std",
"pallet-transaction-payment/std",
"scale-info/std",
"sp-api/std",
Expand Down
229 changes: 122 additions & 107 deletions bin/runtime-common/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@

use bp_message_dispatch::MessageDispatch as _;
use bp_messages::{
source_chain::LaneMessageVerifier,
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
};
use bp_polkadot_core::parachains::{ParaHash, ParaHasher, ParaId};
use bp_runtime::{
messages::{DispatchFeePayment, MessageDispatchResult},
messages::{ MessageDispatchResult},
ChainId, Size, StorageProofChecker,
};
use codec::{Decode, DecodeLimit, Encode};
Expand All @@ -39,7 +39,10 @@ use frame_support::{
use hash_db::Hasher;
use scale_info::TypeInfo;
use sp_runtime::{
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, Saturating, Zero},
traits::{
AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, Header as HeaderT, Saturating,
Zero,
},
FixedPointNumber, FixedPointOperand, FixedU128,
};
use sp_std::{
Expand Down Expand Up @@ -244,24 +247,6 @@ pub mod source {
pub type ParsedMessagesDeliveryProofFromBridgedChain<B> =
(LaneId, InboundLaneData<AccountIdOf<ThisChain<B>>>);

/// Message verifier that is doing all basic checks.
///
/// This verifier assumes following:
///
/// - all message lanes are equivalent, so all checks are the same;
/// - messages are being dispatched using `pallet-bridge-dispatch` pallet on the target chain.
///
/// Following checks are made:
///
/// - message is rejected if its lane is currently blocked;
/// - message is rejected if there are too many pending (undelivered) messages at the outbound
/// lane;
/// - check that the sender has rights to dispatch the call on target chain using provided
/// dispatch origin;
/// - check that the sender has paid enough funds for both message delivery and dispatch.
#[derive(RuntimeDebug)]
pub struct FromThisChainMessageVerifier<B>(PhantomData<B>);

/// The error message returned from LaneMessageVerifier when outbound lane is disabled.
pub const MESSAGE_REJECTED_BY_OUTBOUND_LANE: &str =
"The outbound message lane has rejected the message.";
Expand All @@ -273,77 +258,6 @@ pub mod source {
/// The error message returned from LaneMessageVerifier when the message fee is too low.
pub const TOO_LOW_FEE: &str = "Provided fee is below minimal threshold required by the lane.";

impl<B>
LaneMessageVerifier<
OriginOf<ThisChain<B>>,
AccountIdOf<ThisChain<B>>,
FromThisChainMessagePayload<B>,
BalanceOf<ThisChain<B>>,
> for FromThisChainMessageVerifier<B>
where
B: MessageBridge,
// matches requirements from the `frame_system::Config::Origin`
OriginOf<ThisChain<B>>: Clone
+ Into<Result<frame_system::RawOrigin<AccountIdOf<ThisChain<B>>>, OriginOf<ThisChain<B>>>>,
AccountIdOf<ThisChain<B>>: PartialEq + Clone,
{
type Error = &'static str;

#[allow(clippy::single_match)]
fn verify_message(
submitter: &OriginOf<ThisChain<B>>,
delivery_and_dispatch_fee: &BalanceOf<ThisChain<B>>,
lane: &LaneId,
lane_outbound_data: &OutboundLaneData,
payload: &FromThisChainMessagePayload<B>,
) -> Result<(), Self::Error> {
// reject message if lane is blocked
if !ThisChain::<B>::is_message_accepted(submitter, lane) {
return Err(MESSAGE_REJECTED_BY_OUTBOUND_LANE);
}

// reject message if there are too many pending messages at this lane
let max_pending_messages = ThisChain::<B>::maximal_pending_messages_at_outbound_lane();
let pending_messages = lane_outbound_data
.latest_generated_nonce
.saturating_sub(lane_outbound_data.latest_received_nonce);
if pending_messages > max_pending_messages {
return Err(TOO_MANY_PENDING_MESSAGES);
}

// Do the dispatch-specific check. We assume that the target chain uses
// `Dispatch`, so we verify the message accordingly.
let raw_origin_or_err: Result<
frame_system::RawOrigin<AccountIdOf<ThisChain<B>>>,
OriginOf<ThisChain<B>>,
> = submitter.clone().into();
if let Ok(raw_origin) = raw_origin_or_err {
pallet_bridge_dispatch::verify_message_origin(&raw_origin, payload)
.map(drop)
.map_err(|_| BAD_ORIGIN)?;
} else {
// so what it means that we've failed to convert origin to the
// `frame_system::RawOrigin`? now it means that the custom pallet origin has
// been used to send the message. Do we need to verify it? The answer is no,
// because pallet may craft any origin (e.g. root) && we can't verify whether it
// is valid, or not.
};

let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::<B>(
payload,
B::RELAYER_FEE_PERCENT,
None,
)?;

// compare with actual fee paid
if *delivery_and_dispatch_fee < minimal_fee_in_this_tokens {
return Err(TOO_LOW_FEE);
}

Ok(())
}
}

/// Return maximal message size of This -> Bridged chain message.
pub fn maximal_message_size<B: MessageBridge>() -> u32 {
super::target::maximal_incoming_message_size(BridgedChain::<B>::maximal_extrinsic_size())
Expand Down Expand Up @@ -380,6 +294,9 @@ pub mod source {
}

/// Verify proof of This -> Bridged chain messages delivery.
///
/// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged
/// parachains, please use the `verify_messages_delivery_proof_from_parachain`.
pub fn verify_messages_delivery_proof<B: MessageBridge, ThisRuntime, GrandpaInstance: 'static>(
proof: FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChain<B>>>,
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
Expand All @@ -396,23 +313,70 @@ pub mod source {
pallet_bridge_grandpa::Pallet::<ThisRuntime, GrandpaInstance>::parse_finalized_storage_proof(
bridged_header_hash.into(),
StorageProof::new(storage_proof),
|storage| {
// Messages delivery proof is just proof of single storage key read => any error
// is fatal.
let storage_inbound_lane_data_key =
bp_messages::storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane);
let raw_inbound_lane_data = storage
.read_value(storage_inbound_lane_data_key.0.as_ref())
.map_err(|_| "Failed to read inbound lane state from storage proof")?
.ok_or("Inbound lane state is missing from the messages proof")?;
let inbound_lane_data = InboundLaneData::decode(&mut &raw_inbound_lane_data[..])
.map_err(|_| "Failed to decode inbound lane state from the proof")?;

Ok((lane, inbound_lane_data))
},
|storage| do_verify_messages_delivery_proof::<
B,
bp_runtime::HasherOf<
<ThisRuntime as pallet_bridge_grandpa::Config<GrandpaInstance>>::BridgedChain,
>,
>(lane, storage),
)
.map_err(<&'static str>::from)?
}

/// Verify proof of This -> Bridged chain messages delivery.
///
/// This function is used when Bridged chain is using parachain finality. For Bridged
/// chains with direct GRANDPA finality, please use the `verify_messages_delivery_proof`.
///
/// This function currently only supports parachains, which are using header type that
/// implements `sp_runtime::traits::Header` trait.
pub fn verify_messages_delivery_proof_from_parachain<
B,
BridgedHeader,
ThisRuntime,
ParachainsInstance: 'static,
>(
bridged_parachain: ParaId,
proof: FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChain<B>>>,
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
where
B: MessageBridge,
B::BridgedChain: ChainWithMessages<Hash = ParaHash>,
BridgedHeader: HeaderT<Hash = HashOf<BridgedChain<B>>>,
ThisRuntime: pallet_bridge_parachains::Config<ParachainsInstance>,
{
let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } =
proof;
pallet_bridge_parachains::Pallet::<ThisRuntime, ParachainsInstance>::parse_finalized_storage_proof(
bridged_parachain,
bridged_header_hash,
StorageProof::new(storage_proof),
|para_head| BridgedHeader::decode(&mut &para_head.0[..]).ok().map(|h| *h.state_root()),
|storage| do_verify_messages_delivery_proof::<B, ParaHasher>(lane, storage),
)
.map_err(<&'static str>::from)?
}

/// The essense of This -> Bridged chain messages delivery proof verification.
fn do_verify_messages_delivery_proof<B: MessageBridge, H: Hasher>(
lane: LaneId,
storage: bp_runtime::StorageProofChecker<H>,
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str> {
// Messages delivery proof is just proof of single storage key read => any error
// is fatal.
let storage_inbound_lane_data_key = bp_messages::storage_keys::inbound_lane_data_key(
B::BRIDGED_MESSAGES_PALLET_NAME,
&lane,
);
let raw_inbound_lane_data = storage
.read_value(storage_inbound_lane_data_key.0.as_ref())
.map_err(|_| "Failed to read inbound lane state from storage proof")?
.ok_or("Inbound lane state is missing from the messages proof")?;
let inbound_lane_data = InboundLaneData::decode(&mut &raw_inbound_lane_data[..])
.map_err(|_| "Failed to decode inbound lane state from the proof")?;

Ok((lane, inbound_lane_data))
}
}

/// Sub-module that is declaring types required for processing Bridged -> This chain messages.
Expand Down Expand Up @@ -566,7 +530,7 @@ pub mod target {
fn from(encoded_call: FromBridgedChainEncodedMessageCall<DecodedCall>) -> Self {
DecodedCall::decode_with_depth_limit(
sp_api::MAX_EXTRINSIC_DEPTH,
&mut &encoded_call.encoded_call[..],
&mut &encoded_call.encoded_call[..],
)
.map_err(drop)
}
Expand All @@ -584,6 +548,9 @@ pub mod target {

/// Verify proof of Bridged -> This chain messages.
///
/// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged
/// parachains, please use the `verify_messages_proof_from_parachain`.
///
/// The `messages_count` argument verification (sane limits) is supposed to be made
/// outside of this function. This function only verifies that the proof declares exactly
/// `messages_count` messages.
Expand Down Expand Up @@ -618,6 +585,54 @@ pub mod target {
.map_err(Into::into)
}

/// Verify proof of Bridged -> This chain messages.
///
/// This function is used when Bridged chain is using parachain finality. For Bridged
/// chains with direct GRANDPA finality, please use the `verify_messages_proof`.
///
/// The `messages_count` argument verification (sane limits) is supposed to be made
/// outside of this function. This function only verifies that the proof declares exactly
/// `messages_count` messages.
///
/// This function currently only supports parachains, which are using header type that
/// implements `sp_runtime::traits::Header` trait.
pub fn verify_messages_proof_from_parachain<
B,
BridgedHeader,
ThisRuntime,
ParachainsInstance: 'static,
>(
bridged_parachain: ParaId,
proof: FromBridgedChainMessagesProof<HashOf<BridgedChain<B>>>,
messages_count: u32,
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
where
B: MessageBridge,
B::BridgedChain: ChainWithMessages<Hash = ParaHash>,
BridgedHeader: HeaderT<Hash = HashOf<BridgedChain<B>>>,
ThisRuntime: pallet_bridge_parachains::Config<ParachainsInstance>,
{
verify_messages_proof_with_parser::<B, _, _>(
proof,
messages_count,
|bridged_header_hash, bridged_storage_proof| {
pallet_bridge_parachains::Pallet::<ThisRuntime, ParachainsInstance>::parse_finalized_storage_proof(
bridged_parachain,
bridged_header_hash,
StorageProof::new(bridged_storage_proof),
|para_head| BridgedHeader::decode(&mut &para_head.0[..]).ok().map(|h| *h.state_root()),
|storage_adapter| storage_adapter,
)
.map(|storage| StorageProofCheckerAdapter::<_, B> {
storage,
_dummy: Default::default(),
})
.map_err(|err| MessageProofError::Custom(err.into()))
},
)
.map_err(Into::into)
}

#[derive(Debug, PartialEq)]
pub(crate) enum MessageProofError {
Empty,
Expand Down
Loading