diff --git a/subxt/src/tx/tx_client.rs b/subxt/src/tx/tx_client.rs index 36d250fdbb..28d4e5bf28 100644 --- a/subxt/src/tx/tx_client.rs +++ b/subxt/src/tx/tx_client.rs @@ -57,14 +57,14 @@ impl> TxClient { where Call: TxPayload, { - if let Some(actual_hash) = call.validation_hash() { + if let Some(details) = call.validation_details() { let metadata = self.client.metadata(); let expected_hash = - metadata.call_hash(call.pallet_name(), call.call_name())?; - if actual_hash != expected_hash { + metadata.call_hash(details.pallet_name, details.call_name)?; + if details.hash != expected_hash { return Err(crate::metadata::MetadataError::IncompatibleCallMetadata( - call.pallet_name().into(), - call.call_name().into(), + details.pallet_name.into(), + details.call_name.into(), ) .into()) } @@ -114,11 +114,10 @@ impl> TxClient { }; // Wrap in Encoded to ensure that any more "encode" calls leave it in the right state. - Ok(SubmittableExtrinsic { - client: self.client.clone(), - encoded: Encoded(extrinsic), - marker: std::marker::PhantomData, - }) + Ok(SubmittableExtrinsic::from_bytes( + self.client.clone(), + extrinsic, + )) } /// Creates a raw signed extrinsic without submitting it. @@ -202,11 +201,10 @@ impl> TxClient { // Wrap in Encoded to ensure that any more "encode" calls leave it in the right state. // maybe we can just return the raw bytes.. - Ok(SubmittableExtrinsic { - client: self.client.clone(), - encoded: Encoded(extrinsic), - marker: std::marker::PhantomData, - }) + Ok(SubmittableExtrinsic::from_bytes( + self.client.clone(), + extrinsic, + )) } } @@ -330,6 +328,21 @@ where T: Config, C: OfflineClientT, { + /// Create a [`SubmittableExtrinsic`] from some already-signed and prepared + /// extrinsic bytes, and some client (anything implementing [`OfflineClientT`] + /// or [`OnlineClientT`]). + /// + /// Prefer to use [`TxClient`] to create and sign extrinsics. This is simply + /// exposed in case you want to skip this process and submit something you've + /// already created. + pub fn from_bytes(client: C, tx_bytes: Vec) -> Self { + Self { + client, + encoded: Encoded(tx_bytes), + marker: std::marker::PhantomData, + } + } + /// Returns the SCALE encoded extrinsic bytes. pub fn encoded(&self) -> &[u8] { &self.encoded.0 diff --git a/subxt/src/tx/tx_payload.rs b/subxt/src/tx/tx_payload.rs index d1928d0dcc..10c5cc5c34 100644 --- a/subxt/src/tx/tx_payload.rs +++ b/subxt/src/tx/tx_payload.rs @@ -19,12 +19,6 @@ use std::borrow::Cow; /// This represents a transaction payload that can be submitted /// to a node. pub trait TxPayload { - /// The name of the pallet that the call lives under. - fn pallet_name(&self) -> &str; - - /// The name of the call. - fn call_name(&self) -> &str; - /// Encode call data to the provided output. fn encode_call_data( &self, @@ -32,14 +26,24 @@ pub trait TxPayload { out: &mut Vec, ) -> Result<(), Error>; - /// An optional validation hash that can be provided - /// to verify that the shape of the call on the node - /// aligns with our expectations. - fn validation_hash(&self) -> Option<[u8; 32]> { + /// Returns the details needed to validate the call, which + /// include a statically generated hash, the pallet name, + /// and the call name. + fn validation_details(&self) -> Option> { None } } +pub struct ValidationDetails<'a> { + /// The pallet name. + pub pallet_name: &'a str, + /// The call name. + pub call_name: &'a str, + /// A hash (this is generated at compile time in our codegen) + /// to compare against the runtime code. + pub hash: [u8; 32], +} + /// This represents a statically generated transaction payload. pub struct StaticTxPayload { pallet_name: &'static str, @@ -74,14 +78,6 @@ impl StaticTxPayload { } impl TxPayload for StaticTxPayload { - fn pallet_name(&self) -> &str { - self.pallet_name - } - - fn call_name(&self) -> &str { - self.call_name - } - fn encode_call_data( &self, metadata: &Metadata, @@ -97,8 +93,14 @@ impl TxPayload for StaticTxPayload { Ok(()) } - fn validation_hash(&self) -> Option<[u8; 32]> { - self.validation_hash + fn validation_details(&self) -> Option> { + self.validation_hash.map(|hash| { + ValidationDetails { + pallet_name: self.pallet_name, + call_name: self.call_name, + hash, + } + }) } } @@ -123,14 +125,6 @@ pub fn dynamic<'a>( } impl<'a> TxPayload for DynamicTxPayload<'a> { - fn pallet_name(&self) -> &str { - &self.pallet_name - } - - fn call_name(&self) -> &str { - &self.call_name - } - fn encode_call_data( &self, metadata: &Metadata,