Skip to content

Commit

Permalink
Make relayer proofs more generic - new stub layer for proofs that are…
Browse files Browse the repository at this point in the history
… convertible to different kind of proofs (for backwards compatibility, that we need for relayers, when chains are upgraded asynchrounously) - part 2
  • Loading branch information
bkontur committed Jul 11, 2024
1 parent 9b358d1 commit 640290e
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 97 deletions.
30 changes: 25 additions & 5 deletions bridges/relays/lib-substrate-relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ impl<Call> BatchCallBuilder<Call> for () {
pub mod proofs {
use bp_messages::{LaneId, MessageNonce};
use bp_runtime::{HashOf, HasherOf, RawStorageProof, UnverifiedStorageProof};
use frame_support::pallet_prelude::{Decode, Encode, TypeInfo};
use relay_substrate_client::Chain;
use sp_core::storage::StorageKey;
use sp_trie::StorageProof;
Expand All @@ -157,15 +156,15 @@ pub mod proofs {
}

impl<SourceChain: Chain> TryInto<RawStorageProof> for Proof<SourceChain> {
type Error = ();
type Error = ProofConversionError;

fn try_into(self) -> Result<RawStorageProof, Self::Error> {
Ok(self.storage_proof.into_iter_nodes().collect())
}
}

impl<SourceChain: Chain> TryInto<UnverifiedStorageProof> for Proof<SourceChain> {
type Error = ();
type Error = ProofConversionError;

fn try_into(self) -> Result<UnverifiedStorageProof, Self::Error> {
let Self { storage_proof, storage_keys, state_root } = self;
Expand Down Expand Up @@ -205,7 +204,7 @@ pub mod proofs {
impl<C: Chain> TryFrom<FromBridgedChainMessagesProof<C>>
for bp_messages::target_chain::FromBridgedChainMessagesProof<HashOf<C>>
{
type Error = ();
type Error = ProofConversionError;

fn try_from(value: FromBridgedChainMessagesProof<C>) -> Result<Self, Self::Error> {
Ok(bp_messages::target_chain::FromBridgedChainMessagesProof {
Expand Down Expand Up @@ -234,7 +233,7 @@ pub mod proofs {
impl<C: Chain> TryFrom<FromBridgedChainMessagesDeliveryProof<C>>
for bp_messages::source_chain::FromBridgedChainMessagesDeliveryProof<HashOf<C>>
{
type Error = ();
type Error = ProofConversionError;

fn try_from(value: FromBridgedChainMessagesDeliveryProof<C>) -> Result<Self, Self::Error> {
Ok(bp_messages::source_chain::FromBridgedChainMessagesDeliveryProof {
Expand All @@ -244,4 +243,25 @@ pub mod proofs {
})
}
}

/// Stub that represents `use bp_polkadot_core::parachains::ParaHeadsProof` but
/// with a generic storage proof.
#[derive(Clone, Debug)]
pub struct ParaHeadsProof<C: Chain> {
/// Storage proof of finalized parachain heads.
pub storage_proof: Proof<C>,
}

impl<C: Chain> TryFrom<ParaHeadsProof<C>> for bp_polkadot_core::parachains::ParaHeadsProof {
type Error = ProofConversionError;

fn try_from(value: ParaHeadsProof<C>) -> Result<Self, Self::Error> {
Ok(bp_polkadot_core::parachains::ParaHeadsProof {
storage_proof: value.storage_proof.try_into()?,
})
}
}

/// Type represents error for various `TryInto` implementations for `Proof`
pub type ProofConversionError = ();
}
128 changes: 74 additions & 54 deletions bridges/relays/lib-substrate-relay/src/messages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{
target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget},
},
on_demand::OnDemandRelay,
proofs::ProofConversionError,
BatchCallBuilder, BatchCallBuilderConstructor, TransactionParams,
};

Expand Down Expand Up @@ -374,7 +375,7 @@ pub trait ReceiveMessagesProofCallBuilder<P: SubstrateMessageLane> {
messages_count: u32,
dispatch_weight: Weight,
trace_call: bool,
) -> CallOf<P::TargetChain>;
) -> Result<CallOf<P::TargetChain>, ()>;
}

/// Building `receive_messages_proof` call when you have direct access to the target
Expand All @@ -398,10 +399,10 @@ where
messages_count: u32,
dispatch_weight: Weight,
trace_call: bool,
) -> CallOf<P::TargetChain> {
) -> Result<CallOf<P::TargetChain>, ProofConversionError> {
let call: CallOf<P::TargetChain> = BridgeMessagesCall::<R, I>::receive_messages_proof {
relayer_id_at_bridged_chain: relayer_id_at_source,
proof: proof.1.into(),
proof: Box::new(proof.1.try_into()?),
messages_count,
dispatch_weight,
}
Expand All @@ -420,7 +421,7 @@ where
P::TargetChain::max_extrinsic_size(),
);
}
call
Ok(call)
}
}

Expand All @@ -447,17 +448,19 @@ macro_rules! generate_receive_message_proof_call_builder {
messages_count: u32,
dispatch_weight: bp_messages::Weight,
_trace_call: bool,
) -> relay_substrate_client::CallOf<
) -> Result<relay_substrate_client::CallOf<
<$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain
> {
bp_runtime::paste::item! {
$bridge_messages($receive_messages_proof {
relayer_id_at_bridged_chain: relayer_id_at_source,
proof: proof.1.into(),
messages_count: messages_count,
dispatch_weight: dispatch_weight,
})
}
>, ProofConversionError> {
Ok(
bp_runtime::paste::item! {
$bridge_messages($receive_messages_proof {
relayer_id_at_bridged_chain: relayer_id_at_source,
proof: Box::new(proof.1.try_into().expect("TODO: add result")),
messages_count: messages_count,
dispatch_weight: dispatch_weight,
})
}
)
}
}
};
Expand All @@ -470,7 +473,7 @@ pub trait ReceiveMessagesDeliveryProofCallBuilder<P: SubstrateMessageLane> {
fn build_receive_messages_delivery_proof_call(
proof: SubstrateMessagesDeliveryProof<P::TargetChain>,
trace_call: bool,
) -> CallOf<P::SourceChain>;
) -> Result<CallOf<P::SourceChain>, ProofConversionError>;
}

/// Building `receive_messages_delivery_proof` call when you have direct access to the source
Expand All @@ -491,10 +494,10 @@ where
fn build_receive_messages_delivery_proof_call(
proof: SubstrateMessagesDeliveryProof<P::TargetChain>,
trace_call: bool,
) -> CallOf<P::SourceChain> {
) -> Result<CallOf<P::SourceChain>, ProofConversionError> {
let call: CallOf<P::SourceChain> =
BridgeMessagesCall::<R, I>::receive_messages_delivery_proof {
proof: proof.1.into(),
proof: proof.1.try_into()?,
relayers_state: proof.0,
}
.into();
Expand All @@ -512,7 +515,7 @@ where
P::SourceChain::max_extrinsic_size(),
);
}
call
Ok(call)
}
}

Expand All @@ -534,14 +537,16 @@ macro_rules! generate_receive_message_delivery_proof_call_builder {
<$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain
>,
_trace_call: bool,
) -> relay_substrate_client::CallOf<
) -> Result<relay_substrate_client::CallOf<
<$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain
> {
>, ProofConversionError> {
bp_runtime::paste::item! {
$bridge_messages($receive_messages_delivery_proof {
proof: proof.1,
relayers_state: proof.0
})
Ok(
$bridge_messages($receive_messages_delivery_proof {
proof: proof.1.try_into()?,
relayers_state: proof.0
})
)
}
}
}
Expand Down Expand Up @@ -655,7 +660,8 @@ where
messages,
Weight::zero(),
false,
);
)
.map_err(|_| anyhow::format_err!("Failed to `build_receive_messages_proof_call`"))?;
P::TargetChain::sign_transaction(
SignParam {
spec_version: 0,
Expand All @@ -676,19 +682,17 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::proofs::Proof;
use bp_messages::UnrewardedRelayersState;
use relay_substrate_client::calls::{UtilityCall as MockUtilityCall, UtilityCall};
use sp_trie::StorageProof;

#[derive(codec::Decode, codec::Encode, Clone, Debug, PartialEq)]
pub enum RuntimeCall {
#[codec(index = 53)]
BridgeMessages(CodegenBridgeMessagesCall),
BridgeMessages(ActualBridgeMessagesCall),
#[codec(index = 123)]
Utility(UtilityCall<RuntimeCall>),
}
pub type CodegenBridgeMessagesCall = bp_messages::BridgeMessagesCall<
pub type ActualBridgeMessagesCall = bp_messages::BridgeMessagesCall<
u64,
Box<bp_messages::target_chain::FromBridgedChainMessagesProof<mock::BridgedHeaderHash>>,
bp_messages::source_chain::FromBridgedChainMessagesDeliveryProof<mock::BridgedHeaderHash>,
Expand All @@ -706,9 +710,10 @@ mod tests {
#[test]
fn ensure_macro_compatibility_for_generate_receive_message_proof_call_builder() {
// data
let receive_messages_proof = FromBridgedChainMessagesProof {
let receive_messages_proof = crate::proofs::FromBridgedChainMessagesProof {
bridged_header_hash: Default::default(),
storage_proof: Default::default(),
storage_proof: (sp_trie::StorageProof::empty(), Default::default(), Default::default())
.into(),
lane: LaneId([0, 0, 0, 0]),
nonces_start: 0,
nonces_end: 0,
Expand All @@ -721,27 +726,30 @@ mod tests {
let pallet_receive_messages_proof =
pallet_bridge_messages::Call::<mock::TestRuntime>::receive_messages_proof {
relayer_id_at_bridged_chain: account,
proof: receive_messages_proof.clone().into(),
proof: Box::new(
receive_messages_proof.clone().try_into().expect("conversion works"),
),
messages_count,
dispatch_weight,
};

// construct mock enum Call
let mock_enum_receive_messages_proof = CodegenBridgeMessagesCall::receive_messages_proof {
let mock_enum_receive_messages_proof = ActualBridgeMessagesCall::receive_messages_proof {
relayer_id_at_bridged_chain: account,
proof: receive_messages_proof.clone().into(),
proof: Box::new(receive_messages_proof.clone().try_into().expect("conversion works")),
messages_count,
dispatch_weight,
};

// now we should be able to use macro `generate_receive_message_proof_call_builder`
let relayer_call_builder_receive_messages_proof = relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder::build_receive_messages_proof_call(
let relayer_call_builder_receive_messages_proof =
relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder::build_receive_messages_proof_call(
account,
(Default::default(), receive_messages_proof),
messages_count,
dispatch_weight,
false,
);
).expect("`build_receive_messages_proof_call` works");

// ensure they are all equal
assert_eq!(
Expand All @@ -750,7 +758,7 @@ mod tests {
);
match relayer_call_builder_receive_messages_proof {
RuntimeCall::BridgeMessages(call) => match call {
call @ CodegenBridgeMessagesCall::receive_messages_proof { .. } =>
call @ ActualBridgeMessagesCall::receive_messages_proof { .. } =>
assert_eq!(pallet_receive_messages_proof.encode(), call.encode()),
_ => panic!("Unexpected CodegenBridgeMessagesCall type"),
},
Expand All @@ -761,11 +769,17 @@ mod tests {
#[test]
fn ensure_macro_compatibility_for_generate_receive_message_delivery_proof_call_builder() {
// data
let receive_messages_delivery_proof = FromBridgedChainMessagesDeliveryProof {
bridged_header_hash: Default::default(),
storage_proof: Default::default(),
lane: LaneId([0, 0, 0, 0]),
};
let receive_messages_delivery_proof =
crate::proofs::FromBridgedChainMessagesDeliveryProof {
bridged_header_hash: Default::default(),
storage_proof: (
sp_trie::StorageProof::empty(),
Default::default(),
Default::default(),
)
.into(),
lane: LaneId([0, 0, 0, 0]),
};
let relayers_state = UnrewardedRelayersState {
unrewarded_relayer_entries: 0,
messages_in_oldest_entry: 0,
Expand All @@ -774,24 +788,30 @@ mod tests {
};

// construct pallet Call directly
let pallet_receive_messages_delivery_proof =
pallet_bridge_messages::Call::<mock::TestRuntime>::receive_messages_delivery_proof {
proof: receive_messages_delivery_proof.clone(),
relayers_state: relayers_state.clone(),
};
let pallet_receive_messages_delivery_proof = pallet_bridge_messages::Call::<
mock::TestRuntime,
>::receive_messages_delivery_proof {
proof: receive_messages_delivery_proof.clone().try_into().expect("conversion works"),
relayers_state: relayers_state.clone(),
};

// construct mock enum Call
let mock_enum_receive_messages_delivery_proof =
CodegenBridgeMessagesCall::receive_messages_delivery_proof {
proof: receive_messages_delivery_proof.clone(),
ActualBridgeMessagesCall::receive_messages_delivery_proof {
proof: receive_messages_delivery_proof
.clone()
.try_into()
.expect("conversion works"),
relayers_state: relayers_state.clone(),
};

// now we should be able to use macro `generate_receive_message_proof_call_builder`
let relayer_call_builder_receive_messages_delivery_proof = relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call(
let relayer_call_builder_receive_messages_delivery_proof =
relayer::ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder
::build_receive_messages_delivery_proof_call(
(relayers_state, receive_messages_delivery_proof),
false,
);
).expect("`build_receive_messages_delivery_proof_call` works");

// ensure they are all equal
assert_eq!(
Expand All @@ -800,7 +820,7 @@ mod tests {
);
match relayer_call_builder_receive_messages_delivery_proof {
RuntimeCall::BridgeMessages(call) => match call {
call @ CodegenBridgeMessagesCall::receive_messages_delivery_proof { .. } =>
call @ ActualBridgeMessagesCall::receive_messages_delivery_proof { .. } =>
assert_eq!(pallet_receive_messages_delivery_proof.encode(), call.encode()),
_ => panic!("Unexpected CodegenBridgeMessagesCall type"),
},
Expand Down Expand Up @@ -1021,13 +1041,13 @@ mod tests {
ThisChainToBridgedChainMessageLane,
ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder,
RuntimeCall::BridgeMessages,
CodegenBridgeMessagesCall::receive_messages_proof
ActualBridgeMessagesCall::receive_messages_proof
);
generate_receive_message_delivery_proof_call_builder!(
ThisChainToBridgedChainMessageLane,
ThisChainToBridgedChainMessageLaneReceiveMessagesDeliveryProofCallBuilder,
RuntimeCall::BridgeMessages,
CodegenBridgeMessagesCall::receive_messages_delivery_proof
ActualBridgeMessagesCall::receive_messages_delivery_proof
);
}
}
7 changes: 6 additions & 1 deletion bridges/relays/lib-substrate-relay/src/messages/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,12 @@ where
P::ReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call(
proof,
maybe_batch_tx.is_none(),
);
)
.map_err(|_| {
SubstrateError::Custom(
"Failed to `build_receive_messages_delivery_proof_call`".into(),
)
})?;
let final_call = match maybe_batch_tx {
Some(batch_tx) => batch_tx.append_call_and_build(messages_proof_call),
None => messages_proof_call,
Expand Down
Loading

0 comments on commit 640290e

Please sign in to comment.