Skip to content

Commit

Permalink
Verify messages proofs (paritytech#480)
Browse files Browse the repository at this point in the history
* verify messages proofs

* fmt

* clippy

* grumbles
  • Loading branch information
svyatonik authored and serban300 committed Apr 9, 2024
1 parent b3f8b99 commit 8fec62f
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 7 deletions.
4 changes: 2 additions & 2 deletions bridges/bin/millau/runtime/src/rialto_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
type MessagesProof = FromRialtoMessagesProof;

fn verify_messages_proof(
_proof: Self::MessagesProof,
proof: Self::MessagesProof,
) -> Result<ProvedMessages<Message<bp_rialto::Balance>>, Self::Error> {
unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397")
messages::target::verify_messages_proof::<WithRialtoMessageBridge, Runtime>(proof)
}
}
4 changes: 2 additions & 2 deletions bridges/bin/rialto/runtime/src/millau_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
type MessagesProof = FromMillauMessagesProof;

fn verify_messages_proof(
_proof: Self::MessagesProof,
proof: Self::MessagesProof,
) -> Result<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397")
messages::target::verify_messages_proof::<WithMillauMessageBridge, Runtime>(proof)
}
}
76 changes: 73 additions & 3 deletions bridges/bin/runtime-common/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
use bp_message_dispatch::MessageDispatch as _;
use bp_message_lane::{
source_chain::LaneMessageVerifier,
target_chain::{DispatchMessage, MessageDispatch},
InboundLaneData, LaneId, MessageNonce,
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
};
use bp_runtime::InstanceId;
use codec::{Compact, Decode, Input};
Expand Down Expand Up @@ -90,7 +90,7 @@ pub trait ChainWithMessageLanes {
/// different weights.
type Weight: From<frame_support::weights::Weight>;
/// Type of balances that is used on the chain.
type Balance: CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From<u32> + Copy;
type Balance: Decode + CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From<u32> + Copy;

/// Instance of the message-lane pallet.
type MessageLaneInstance: Instance;
Expand Down Expand Up @@ -333,6 +333,76 @@ pub mod target {
}
}
}

/// Verify proof of Bridged -> This chain messages.
pub fn verify_messages_proof<B: MessageBridge, ThisRuntime>(
proof: FromBridgedChainMessagesProof<B>,
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
where
ThisRuntime: pallet_substrate_bridge::Trait,
ThisRuntime: pallet_message_lane::Trait<MessageLaneInstanceOf<BridgedChain<B>>>,
HashOf<BridgedChain<B>>:
Into<bp_runtime::HashOf<<ThisRuntime as pallet_substrate_bridge::Trait>::BridgedChain>>,
{
let (bridged_header_hash, bridged_storage_proof, lane_id, begin, end) = proof;
pallet_substrate_bridge::Module::<ThisRuntime>::parse_finalized_storage_proof(
bridged_header_hash.into(),
bridged_storage_proof,
|storage| {
// Read messages first. All messages that are claimed to be in the proof must
// be in the proof. So any error in `read_value`, or even missing value is fatal.
//
// Mind that we allow proofs with no messages if outbound lane state is proved.
let mut messages = Vec::with_capacity(end.saturating_sub(begin) as _);
for nonce in begin..=end {
let message_key = MessageKey { lane_id, nonce };
let storage_message_key = pallet_message_lane::storage_keys::message_key::<
ThisRuntime,
MessageLaneInstanceOf<BridgedChain<B>>,
>(&lane_id, nonce);
let raw_message_data = storage
.read_value(storage_message_key.0.as_ref())
.map_err(|_| "Failed to read message from storage proof")?
.ok_or("Message is missing from the messages proof")?;
let message_data = MessageData::<BalanceOf<BridgedChain<B>>>::decode(&mut &raw_message_data[..])
.map_err(|_| "Failed to decode message from the proof")?;
messages.push(Message {
key: message_key,
data: message_data,
});
}

// Now let's check if proof contains outbound lane state proof. It is optional, so we
// simply ignore `read_value` errors and missing value.
let mut proved_lane_messages = ProvedLaneMessages {
lane_state: None,
messages,
};
let storage_outbound_lane_data_key = pallet_message_lane::storage_keys::outbound_lane_data_key::<
MessageLaneInstanceOf<BridgedChain<B>>,
>(&lane_id);
let raw_outbound_lane_data = storage.read_value(storage_outbound_lane_data_key.0.as_ref());
if let Ok(Some(raw_outbound_lane_data)) = raw_outbound_lane_data {
proved_lane_messages.lane_state = Some(
OutboundLaneData::decode(&mut &raw_outbound_lane_data[..])
.map_err(|_| "Failed to decode outbound lane data from the proof")?,
);
}

// Now we may actually check if the proof is empty or not.
if proved_lane_messages.lane_state.is_none() && proved_lane_messages.messages.is_empty() {
return Err("Messages proof is empty");
}

// We only support single lane messages in this schema
let mut proved_messages = ProvedMessages::new();
proved_messages.insert(lane_id, proved_lane_messages);

Ok(proved_messages)
},
)
.map_err(<&'static str>::from)?
}
}

#[cfg(test)]
Expand Down

0 comments on commit 8fec62f

Please sign in to comment.