// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see .
//! Tools for messages and delivery proof verification.
use crate::{BridgedChainOf, BridgedHeaderChainOf, Config};
use bp_header_chain::{HeaderChain, HeaderChainError};
use bp_messages::{
source_chain::FromBridgedChainMessagesDeliveryProof,
target_chain::{FromBridgedChainMessagesProof, ProvedLaneMessages, ProvedMessages},
ChainWithMessages, InboundLaneData, Message, MessageKey, MessageNonce, MessagePayload,
OutboundLaneData, VerificationError,
};
use bp_runtime::{
HashOf, HasherOf, RangeInclusiveExt, RawStorageProof, StorageProofChecker, StorageProofError,
};
use codec::Decode;
use sp_std::vec::Vec;
/// 'Parsed' message delivery proof - inbound lane id and its state.
pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain =
(>::LaneId, InboundLaneData<::AccountId>);
/// Verify proof of Bridged -> This chain messages.
///
/// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged
/// teyrchains, please use the `verify_messages_proof_from_teyrchain`.
///
/// 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.
pub fn verify_messages_proof, I: 'static>(
proof: FromBridgedChainMessagesProof>, T::LaneId>,
messages_count: u32,
) -> Result>, VerificationError> {
let FromBridgedChainMessagesProof {
bridged_header_hash,
storage_proof,
lane,
nonces_start,
nonces_end,
} = proof;
let mut parser: MessagesStorageProofAdapter =
MessagesStorageProofAdapter::try_new_with_verified_storage_proof(
bridged_header_hash,
storage_proof,
)
.map_err(VerificationError::HeaderChain)?;
let nonces_range = nonces_start..=nonces_end;
// receiving proofs where end < begin is ok (if proof includes outbound lane state)
let messages_in_the_proof = nonces_range.saturating_len();
if messages_in_the_proof != MessageNonce::from(messages_count) {
return Err(VerificationError::MessagesCountMismatch);
}
// 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(messages_in_the_proof as _);
for nonce in nonces_range {
let message_key = MessageKey { lane_id: lane, nonce };
let message_payload = parser
.read_and_decode_message_payload(&message_key)
.map_err(VerificationError::MessageStorage)?;
messages.push(Message { key: message_key, payload: message_payload });
}
// 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 proved_lane_messages = ProvedLaneMessages {
lane_state: parser
.read_and_decode_outbound_lane_data(&lane)
.map_err(VerificationError::OutboundLaneStorage)?,
messages,
};
// 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(VerificationError::EmptyMessageProof);
}
// Check that the storage proof doesn't have any untouched keys.
parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?;
Ok((lane, proved_lane_messages))
}
/// Verify proof of This -> Bridged chain messages delivery.
pub fn verify_messages_delivery_proof, I: 'static>(
proof: FromBridgedChainMessagesDeliveryProof>, T::LaneId>,
) -> Result, VerificationError> {
let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = proof;
let mut parser: MessagesStorageProofAdapter =
MessagesStorageProofAdapter::try_new_with_verified_storage_proof(
bridged_header_hash,
storage_proof,
)
.map_err(VerificationError::HeaderChain)?;
// 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(
T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME,
&lane,
);
let inbound_lane_data = parser
.read_and_decode_mandatory_value(&storage_inbound_lane_data_key)
.map_err(VerificationError::InboundLaneStorage)?;
// check that the storage proof doesn't have any untouched trie nodes
parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?;
Ok((lane, inbound_lane_data))
}
/// Abstraction over storage proof manipulation, hiding implementation details of actual storage
/// proofs.
trait StorageProofAdapter, I: 'static> {
fn read_and_decode_mandatory_value(
&mut self,
key: &impl AsRef<[u8]>,
) -> Result;
fn read_and_decode_optional_value(
&mut self,
key: &impl AsRef<[u8]>,
) -> Result