diff --git a/bridges/bin/millau/runtime/src/rialto_messages.rs b/bridges/bin/millau/runtime/src/rialto_messages.rs index fc20cf7b5628b..b810aa1522100 100644 --- a/bridges/bin/millau/runtime/src/rialto_messages.rs +++ b/bridges/bin/millau/runtime/src/rialto_messages.rs @@ -184,8 +184,8 @@ impl SourceHeaderChain for Rialto { type MessagesProof = FromRialtoMessagesProof; fn verify_messages_proof( - _proof: Self::MessagesProof, + proof: Self::MessagesProof, ) -> Result>, Self::Error> { - unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397") + messages::target::verify_messages_proof::(proof) } } diff --git a/bridges/bin/rialto/runtime/src/millau_messages.rs b/bridges/bin/rialto/runtime/src/millau_messages.rs index 79b03ba935579..65797322bca52 100644 --- a/bridges/bin/rialto/runtime/src/millau_messages.rs +++ b/bridges/bin/rialto/runtime/src/millau_messages.rs @@ -184,8 +184,8 @@ impl SourceHeaderChain for Millau { type MessagesProof = FromMillauMessagesProof; fn verify_messages_proof( - _proof: Self::MessagesProof, + proof: Self::MessagesProof, ) -> Result>, Self::Error> { - unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397") + messages::target::verify_messages_proof::(proof) } } diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs index 384b17e44a2fb..264efd409c208 100644 --- a/bridges/bin/runtime-common/src/messages.rs +++ b/bridges/bin/runtime-common/src/messages.rs @@ -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}; @@ -90,7 +90,7 @@ pub trait ChainWithMessageLanes { /// different weights. type Weight: From; /// Type of balances that is used on the chain. - type Balance: CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From + Copy; + type Balance: Decode + CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From + Copy; /// Instance of the message-lane pallet. type MessageLaneInstance: Instance; @@ -333,6 +333,76 @@ pub mod target { } } } + + /// Verify proof of Bridged -> This chain messages. + pub fn verify_messages_proof( + proof: FromBridgedChainMessagesProof, + ) -> Result>>>, &'static str> + where + ThisRuntime: pallet_substrate_bridge::Trait, + ThisRuntime: pallet_message_lane::Trait>>, + HashOf>: + Into::BridgedChain>>, + { + let (bridged_header_hash, bridged_storage_proof, lane_id, begin, end) = proof; + pallet_substrate_bridge::Module::::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>, + >(&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::>>::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>, + >(&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)]