mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-01 02:11:01 +00:00
XCM: Tools for uniquely referencing messages (#7234)
* Tools for unique topic references * Formatting * Naming * Repot into routing.rs. * More things done * Universal Exporter supports topic-as-reference * Some tests for the topic routing * More tests * Paid bridge tests * Add message ID to sending events * Formatting * fix and integrate into test nets * Move DenyThenTry and friend from Cumulus * Append SetTopic rather than prepend * Docs * Docs * Work with new ProcessMessage ID API * Formatting * Fix build * Fixes * Formatting * Update xcm/xcm-builder/src/barriers.rs Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> * Update xcm/xcm-builder/src/routing.rs Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> * Docs * Rename message_hash * Formatting * ".git/.scripts/commands/fmt/fmt.sh" * Rename * Another Rename * ".git/.scripts/commands/fmt/fmt.sh" * ".git/.scripts/commands/fmt/fmt.sh" * Update xcm/xcm-builder/src/routing.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> --------- Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com> Co-authored-by: command-bot <> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
@@ -130,6 +130,10 @@ impl<T: Get<Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>>> ExporterFor
|
||||
}
|
||||
}
|
||||
|
||||
pub fn forward_id_for(original_id: &XcmHash) -> XcmHash {
|
||||
(b"forward_id_for", original_id).using_encoded(sp_io::hashing::blake2_256)
|
||||
}
|
||||
|
||||
/// Implementation of `SendXcm` which wraps the message inside an `ExportMessage` instruction
|
||||
/// and sends it to a destination known to be able to handle it.
|
||||
///
|
||||
@@ -139,6 +143,16 @@ impl<T: Get<Vec<(NetworkId, MultiLocation, Option<MultiAsset>)>>> ExporterFor
|
||||
///
|
||||
/// This is only useful if we have special dispensation by the remote bridges to have the
|
||||
/// `ExportMessage` instruction executed without payment.
|
||||
///
|
||||
/// The `XcmHash` value returned by `deliver` will always be the same as that returned by the
|
||||
/// message exporter (`Bridges`). Generally this should take notice of the message should it
|
||||
/// end with the `SetTopic` instruction.
|
||||
///
|
||||
/// In the case that the message ends with a `SetTopic(T)` (as should be the case if the top-level
|
||||
/// router is `EnsureUniqueTopic`), then the forwarding message (i.e. the one carrying the
|
||||
/// export instruction *to* the bridge in local consensus) will also end with a `SetTopic` whose
|
||||
/// inner is `forward_id_for(T)`. If this is not the case then the onward message will not be given
|
||||
/// the `SetTopic` afterword.
|
||||
pub struct UnpaidRemoteExporter<Bridges, Router, UniversalLocation>(
|
||||
PhantomData<(Bridges, Router, UniversalLocation)>,
|
||||
);
|
||||
@@ -155,21 +169,32 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
||||
let devolved = ensure_is_remote(UniversalLocation::get(), d).map_err(|_| NotApplicable)?;
|
||||
let (remote_network, remote_location) = devolved;
|
||||
let xcm = xcm.take().ok_or(MissingArgument)?;
|
||||
|
||||
let (bridge, maybe_payment) =
|
||||
Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?;
|
||||
ensure!(maybe_payment.is_none(), Unroutable);
|
||||
|
||||
// `xcm` should already end with `SetTopic` - if it does, then extract and derive into
|
||||
// an onward topic ID.
|
||||
let maybe_forward_id = match xcm.last() {
|
||||
Some(SetTopic(t)) => Some(forward_id_for(t)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// We then send a normal message to the bridge asking it to export the prepended
|
||||
// message to the remote chain. This will only work if the bridge will do the message
|
||||
// export for free. Common-good chains will typically be afforded this.
|
||||
let message = Xcm(vec![
|
||||
let mut message = Xcm(vec![
|
||||
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
|
||||
ExportMessage { network: remote_network, destination: remote_location, xcm },
|
||||
]);
|
||||
if let Some(forward_id) = maybe_forward_id {
|
||||
message.0.push(SetTopic(forward_id));
|
||||
}
|
||||
validate_send::<Router>(bridge, message)
|
||||
}
|
||||
|
||||
fn deliver(validation: Router::Ticket) -> Result<XcmHash, SendError> {
|
||||
fn deliver(validation: Self::Ticket) -> Result<XcmHash, SendError> {
|
||||
Router::deliver(validation)
|
||||
}
|
||||
}
|
||||
@@ -179,6 +204,16 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
||||
///
|
||||
/// The `ExportMessage` instruction on the bridge is paid for from the local chain's sovereign
|
||||
/// account on the bridge. The amount paid is determined through the `ExporterFor` trait.
|
||||
///
|
||||
/// The `XcmHash` value returned by `deliver` will always be the same as that returned by the
|
||||
/// message exporter (`Bridges`). Generally this should take notice of the message should it
|
||||
/// end with the `SetTopic` instruction.
|
||||
///
|
||||
/// In the case that the message ends with a `SetTopic(T)` (as should be the case if the top-level
|
||||
/// router is `EnsureUniqueTopic`), then the forwarding message (i.e. the one carrying the
|
||||
/// export instruction *to* the bridge in local consensus) will also end with a `SetTopic` whose
|
||||
/// inner is `forward_id_for(T)`. If this is not the case then the onward message will not be given
|
||||
/// the `SetTopic` afterword.
|
||||
pub struct SovereignPaidRemoteExporter<Bridges, Router, UniversalLocation>(
|
||||
PhantomData<(Bridges, Router, UniversalLocation)>,
|
||||
);
|
||||
@@ -196,6 +231,14 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
||||
let (remote_network, remote_location) = devolved;
|
||||
|
||||
let xcm = xcm.take().ok_or(MissingArgument)?;
|
||||
|
||||
// `xcm` should already end with `SetTopic` - if it does, then extract and derive into
|
||||
// an onward topic ID.
|
||||
let maybe_forward_id = match xcm.last() {
|
||||
Some(SetTopic(t)) => Some(forward_id_for(t)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let (bridge, maybe_payment) =
|
||||
Bridges::exporter_for(&remote_network, &remote_location, &xcm).ok_or(NotApplicable)?;
|
||||
|
||||
@@ -204,7 +247,7 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
||||
let export_instruction =
|
||||
ExportMessage { network: remote_network, destination: remote_location, xcm };
|
||||
|
||||
let message = Xcm(if let Some(ref payment) = maybe_payment {
|
||||
let mut message = Xcm(if let Some(ref payment) = maybe_payment {
|
||||
let fees = payment
|
||||
.clone()
|
||||
.reanchored(&bridge, UniversalLocation::get())
|
||||
@@ -219,6 +262,9 @@ impl<Bridges: ExporterFor, Router: SendXcm, UniversalLocation: Get<InteriorMulti
|
||||
} else {
|
||||
vec![export_instruction]
|
||||
});
|
||||
if let Some(forward_id) = maybe_forward_id {
|
||||
message.0.push(SetTopic(forward_id));
|
||||
}
|
||||
|
||||
// We then send a normal message to the bridge asking it to export the prepended
|
||||
// message to the remote chain.
|
||||
@@ -344,22 +390,24 @@ impl<Bridge: HaulBlob, BridgedNetwork: Get<NetworkId>, Price: Get<MultiAssets>>
|
||||
.ok_or(SendError::MissingArgument)?
|
||||
.split_global()
|
||||
.map_err(|()| SendError::Unroutable)?;
|
||||
let mut inner: Xcm<()> = vec![UniversalOrigin(GlobalConsensus(local_net))].into();
|
||||
let mut message = message.take().ok_or(SendError::MissingArgument)?;
|
||||
let maybe_id = match message.last() {
|
||||
Some(SetTopic(t)) => Some(*t),
|
||||
_ => None,
|
||||
};
|
||||
message.0.insert(0, UniversalOrigin(GlobalConsensus(local_net)));
|
||||
if local_sub != Here {
|
||||
inner.inner_mut().push(DescendOrigin(local_sub));
|
||||
message.0.insert(1, DescendOrigin(local_sub));
|
||||
}
|
||||
inner
|
||||
.inner_mut()
|
||||
.extend(message.take().ok_or(SendError::MissingArgument)?.into_iter());
|
||||
let message = VersionedXcm::from(inner);
|
||||
let hash = message.using_encoded(sp_io::hashing::blake2_256);
|
||||
let message = VersionedXcm::from(message);
|
||||
let id = maybe_id.unwrap_or_else(|| message.using_encoded(sp_io::hashing::blake2_256));
|
||||
let blob = BridgeMessage { universal_dest, message }.encode();
|
||||
Ok(((blob, hash), Price::get()))
|
||||
Ok(((blob, id), Price::get()))
|
||||
}
|
||||
|
||||
fn deliver((blob, hash): (Vec<u8>, XcmHash)) -> Result<XcmHash, SendError> {
|
||||
fn deliver((blob, id): (Vec<u8>, XcmHash)) -> Result<XcmHash, SendError> {
|
||||
Bridge::haul_blob(blob)?;
|
||||
Ok(hash)
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user