-
Notifications
You must be signed in to change notification settings - Fork 254
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make subxt-core ready for publishing (#1508)
* Move Extrinsic decoding things to subxt_core and various tidy-ups * A couple more fixes and fmt * first pass moving tx logic to subxt_core * cargo fmt * fix wasm example * clippy * more clippy * WIP Adding examples and such * Move storage functionality more fully to subxt_core and nice examples for storage and txs * Add example for events * consistify how addresses/payloads are exposed in subxt-core and add runtime API fns * Add runtime API core example * fmt * remove scale-info patch * Add a little to the top level docs * swap args around * clippy * cargo fmt and fix wasm-example * doc fixes * no-std-ise new subxt-core additions * alloc, not core * more no-std fixes * A couple more fixes * Add back extrinsic decode test
- Loading branch information
Showing
89 changed files
with
4,415 additions
and
3,456 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// Copyright 2019-2024 Parity Technologies (UK) Ltd. | ||
// This file is dual-licensed as Apache-2.0 or GPL-3.0. | ||
// see LICENSE for license details. | ||
|
||
use crate::config::signed_extensions::{ | ||
ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce, | ||
}; | ||
use crate::config::SignedExtension; | ||
use crate::dynamic::Value; | ||
use crate::{config::Config, error::Error, Metadata}; | ||
use scale_decode::DecodeAsType; | ||
|
||
/// The signed extensions of an extrinsic. | ||
#[derive(Debug, Clone)] | ||
pub struct ExtrinsicSignedExtensions<'a, T: Config> { | ||
bytes: &'a [u8], | ||
metadata: &'a Metadata, | ||
_marker: core::marker::PhantomData<T>, | ||
} | ||
|
||
impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { | ||
pub(crate) fn new(bytes: &'a [u8], metadata: &'a Metadata) -> Self { | ||
Self { | ||
bytes, | ||
metadata, | ||
_marker: core::marker::PhantomData, | ||
} | ||
} | ||
|
||
/// Returns an iterator over each of the signed extension details of the extrinsic. | ||
/// If the decoding of any signed extension fails, an error item is yielded and the iterator stops. | ||
pub fn iter(&self) -> impl Iterator<Item = Result<ExtrinsicSignedExtension<T>, Error>> { | ||
let signed_extension_types = self.metadata.extrinsic().signed_extensions(); | ||
let num_signed_extensions = signed_extension_types.len(); | ||
let bytes = self.bytes; | ||
let mut index = 0; | ||
let mut byte_start_idx = 0; | ||
let metadata = &self.metadata; | ||
|
||
core::iter::from_fn(move || { | ||
if index == num_signed_extensions { | ||
return None; | ||
} | ||
|
||
let extension = &signed_extension_types[index]; | ||
let ty_id = extension.extra_ty(); | ||
let cursor = &mut &bytes[byte_start_idx..]; | ||
if let Err(err) = scale_decode::visitor::decode_with_visitor( | ||
cursor, | ||
&ty_id, | ||
metadata.types(), | ||
scale_decode::visitor::IgnoreVisitor::new(), | ||
) | ||
.map_err(|e| Error::Decode(e.into())) | ||
{ | ||
index = num_signed_extensions; // (such that None is returned in next iteration) | ||
return Some(Err(err)); | ||
} | ||
let byte_end_idx = bytes.len() - cursor.len(); | ||
let bytes = &bytes[byte_start_idx..byte_end_idx]; | ||
byte_start_idx = byte_end_idx; | ||
index += 1; | ||
Some(Ok(ExtrinsicSignedExtension { | ||
bytes, | ||
ty_id, | ||
identifier: extension.identifier(), | ||
metadata, | ||
_marker: core::marker::PhantomData, | ||
})) | ||
}) | ||
} | ||
|
||
/// Searches through all signed extensions to find a specific one. | ||
/// If the Signed Extension is not found `Ok(None)` is returned. | ||
/// If the Signed Extension is found but decoding failed `Err(_)` is returned. | ||
pub fn find<S: SignedExtension<T>>(&self) -> Result<Option<S::Decoded>, Error> { | ||
for ext in self.iter() { | ||
// If we encounter an error while iterating, we won't get any more results | ||
// back, so just return that error as we won't find the signed ext anyway. | ||
let ext = ext?; | ||
match ext.as_signed_extension::<S>() { | ||
// We found a match; return it: | ||
Ok(Some(e)) => return Ok(Some(e)), | ||
// No error, but no match either; next! | ||
Ok(None) => continue, | ||
// Error? return it | ||
Err(e) => return Err(e), | ||
} | ||
} | ||
Ok(None) | ||
} | ||
|
||
/// The tip of an extrinsic, extracted from the ChargeTransactionPayment or ChargeAssetTxPayment | ||
/// signed extension, depending on which is present. | ||
/// | ||
/// Returns `None` if `tip` was not found or decoding failed. | ||
pub fn tip(&self) -> Option<u128> { | ||
// Note: the overhead of iterating multiple time should be negligible. | ||
self.find::<ChargeTransactionPayment>() | ||
.ok() | ||
.flatten() | ||
.map(|e| e.tip()) | ||
.or_else(|| { | ||
self.find::<ChargeAssetTxPayment<T>>() | ||
.ok() | ||
.flatten() | ||
.map(|e| e.tip()) | ||
}) | ||
} | ||
|
||
/// The nonce of the account that submitted the extrinsic, extracted from the CheckNonce signed extension. | ||
/// | ||
/// Returns `None` if `nonce` was not found or decoding failed. | ||
pub fn nonce(&self) -> Option<u64> { | ||
self.find::<CheckNonce>().ok()? | ||
} | ||
} | ||
|
||
/// A single signed extension | ||
#[derive(Debug, Clone)] | ||
pub struct ExtrinsicSignedExtension<'a, T: Config> { | ||
bytes: &'a [u8], | ||
ty_id: u32, | ||
identifier: &'a str, | ||
metadata: &'a Metadata, | ||
_marker: core::marker::PhantomData<T>, | ||
} | ||
|
||
impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { | ||
/// The bytes representing this signed extension. | ||
pub fn bytes(&self) -> &'a [u8] { | ||
self.bytes | ||
} | ||
|
||
/// The name of the signed extension. | ||
pub fn name(&self) -> &'a str { | ||
self.identifier | ||
} | ||
|
||
/// The type id of the signed extension. | ||
pub fn type_id(&self) -> u32 { | ||
self.ty_id | ||
} | ||
|
||
/// Signed Extension as a [`scale_value::Value`] | ||
pub fn value(&self) -> Result<Value<u32>, Error> { | ||
let value = scale_value::scale::decode_as_type( | ||
&mut &self.bytes[..], | ||
&self.ty_id, | ||
self.metadata.types(), | ||
)?; | ||
Ok(value) | ||
} | ||
|
||
/// Decodes the bytes of this Signed Extension into its associated `Decoded` type. | ||
/// Returns `Ok(None)` if the data we have doesn't match the Signed Extension we're asking to | ||
/// decode with. | ||
pub fn as_signed_extension<S: SignedExtension<T>>(&self) -> Result<Option<S::Decoded>, Error> { | ||
if !S::matches(self.identifier, self.ty_id, self.metadata.types()) { | ||
return Ok(None); | ||
} | ||
self.as_type::<S::Decoded>().map(Some) | ||
} | ||
|
||
fn as_type<E: DecodeAsType>(&self) -> Result<E, Error> { | ||
let value = E::decode_as_type(&mut &self.bytes[..], &self.ty_id, self.metadata.types())?; | ||
Ok(value) | ||
} | ||
} |
Oops, something went wrong.