Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify the TxPayload trait a little #638

Merged
merged 4 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 28 additions & 15 deletions subxt/src/tx/tx_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
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())
}
Expand Down Expand Up @@ -114,11 +114,10 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
};

// 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.
Expand Down Expand Up @@ -202,11 +201,10 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {

// 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,
))
}
}

Expand Down Expand Up @@ -330,6 +328,21 @@ where
T: Config,
C: OfflineClientT<T>,
{
/// 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<u8>) -> 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
Expand Down
50 changes: 22 additions & 28 deletions subxt/src/tx/tx_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,31 @@ 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,
metadata: &Metadata,
out: &mut Vec<u8>,
) -> 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<ValidationDetails<'_>> {
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<CallData> {
pallet_name: &'static str,
Expand Down Expand Up @@ -74,14 +78,6 @@ impl<CallData> StaticTxPayload<CallData> {
}

impl<CallData: Encode> TxPayload for StaticTxPayload<CallData> {
fn pallet_name(&self) -> &str {
self.pallet_name
}

fn call_name(&self) -> &str {
self.call_name
}

fn encode_call_data(
&self,
metadata: &Metadata,
Expand All @@ -97,8 +93,14 @@ impl<CallData: Encode> TxPayload for StaticTxPayload<CallData> {
Ok(())
}

fn validation_hash(&self) -> Option<[u8; 32]> {
self.validation_hash
fn validation_details(&self) -> Option<ValidationDetails<'_>> {
self.validation_hash.map(|hash| {
ValidationDetails {
pallet_name: self.pallet_name,
call_name: self.call_name,
hash,
}
})
}
}

Expand All @@ -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,
Expand Down