From c0226dc1163c1c73c554e89ce5272a057c961c61 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 9 Oct 2023 11:02:02 +0200 Subject: [PATCH 01/27] skeleton commit --- subxt/src/blocks/extrinsic_types.rs | 137 ++++++++++++++++++++++++---- 1 file changed, 117 insertions(+), 20 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index ba83173bbf..1e3bc2702f 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -11,7 +11,11 @@ use crate::{ metadata::types::PalletMetadata, Metadata, }; +use std::marker::PhantomData; +use std::ops::Range; +use crate::dynamic::DecodedValueThunk; +use crate::metadata::DecodeWithMetadata; use crate::utils::strip_compact_prefix; use codec::Decode; use derivative::Derivative; @@ -155,12 +159,8 @@ pub struct ExtrinsicDetails { index: u32, /// Extrinsic bytes. bytes: Arc<[u8]>, - /// True if the extrinsic payload is signed. - is_signed: bool, - /// The start index in the `bytes` from which the address is encoded. - address_start_idx: usize, - /// The end index of the address in the encoded `bytes`. - address_end_idx: usize, + /// Some if the extrinsic payload is signed. + signed: Option, /// The start index in the `bytes` from which the call is encoded. call_start_idx: usize, /// The pallet index. @@ -178,6 +178,20 @@ pub struct ExtrinsicDetails { _marker: std::marker::PhantomData, } +/// Details only available in signed extrinsics. +pub struct SignedExtrinsicDetails { + /// start index of the range in `bytes` of `ExtrinsicDetails` that encodes the address. + address_start_idx: usize, + /// end index of the range in `bytes` of `ExtrinsicDetails` that encodes the address. Equivalent to signature_start_idx. + address_end_idx: usize, + /// end index of the range in `bytes` of `ExtrinsicDetails` that encodes the signature. Equivalent to extra_start_idx. + signature_end_idx: usize, + /// end index of the range in `bytes` of `ExtrinsicDetails` that encodes the signature. + extra_end_idx: usize, + /// Extrinsic part type ids (address, signature, extra) + ids: ExtrinsicPartTypeIds, +} + impl ExtrinsicDetails where T: Config, @@ -217,12 +231,10 @@ where // Skip over the first byte which denotes the version and signing. let cursor = &mut &bytes[1..]; - let mut address_start_idx = 0; - let mut address_end_idx = 0; - - if is_signed { - address_start_idx = bytes.len() - cursor.len(); - + let signed = if !is_signed { + None + } else { + let address_start_idx = bytes.len() - cursor.len(); // Skip over the address, signature and extra fields. scale_decode::visitor::decode_with_visitor( cursor, @@ -231,7 +243,7 @@ where scale_decode::visitor::IgnoreVisitor, ) .map_err(scale_decode::Error::from)?; - address_end_idx = bytes.len() - cursor.len(); + let address_end_idx = bytes.len() - cursor.len(); scale_decode::visitor::decode_with_visitor( cursor, @@ -240,6 +252,7 @@ where scale_decode::visitor::IgnoreVisitor, ) .map_err(scale_decode::Error::from)?; + let signature_end_idx = bytes.len() - cursor.len(); scale_decode::visitor::decode_with_visitor( cursor, @@ -248,7 +261,16 @@ where scale_decode::visitor::IgnoreVisitor, ) .map_err(scale_decode::Error::from)?; - } + let extra_end_idx = bytes.len() - cursor.len(); + + Some(SignedExtrinsicDetails { + address_start_idx, + address_end_idx, + signature_end_idx, + extra_end_idx, + ids, + }) + }; let call_start_idx = bytes.len() - cursor.len(); @@ -261,9 +283,7 @@ where Ok(ExtrinsicDetails { index, bytes, - is_signed, - address_start_idx, - address_end_idx, + signed, call_start_idx, pallet_index, variant_index, @@ -277,7 +297,7 @@ where /// Is the extrinsic signed? pub fn is_signed(&self) -> bool { - self.is_signed + self.signed.is_some() } /// The index of the extrinsic in the block. @@ -326,8 +346,44 @@ where /// /// Returns `None` if the extrinsic is not signed. pub fn address_bytes(&self) -> Option<&[u8]> { - self.is_signed - .then(|| &self.bytes[self.address_start_idx..self.address_end_idx]) + self.signed + .as_ref() + .map(|e| &self.bytes[e.address_start_idx..e.address_end_idx]) + } + + /// Return only the bytes of the signature for this signed extrinsic. + /// + /// # Note + /// + /// Returns `None` if the extrinsic is not signed. + pub fn signature_bytes(&self) -> Option<&[u8]> { + self.signed + .as_ref() + .map(|e| &self.bytes[e.address_end_idx..e.signature_end_idx]) + } + + /// Return only the bytes of the extra fields for this signed extrinsic. + /// + /// # Note + /// + /// Returns `None` if the extrinsic is not signed. + pub fn extra_bytes(&self) -> Option<&[u8]> { + self.signed + .as_ref() + .map(|e| &self.bytes[e.signature_end_idx..e.extra_end_idx]) + } + + /// Returns a reference to the signed extensions. + pub fn signed_extensions(&self) -> Option<()> { + let extra_bytes = self.extra_bytes()?; + let cursor: &mut &[u8] = &mut &extra_bytes[..]; + let signed = self.signed.as_ref().unwrap(); + let d = DecodedValueThunk::decode_with_metadata(cursor, signed.ids.extra, &self.metadata) + .expect("decoding err"); + + let val = d.to_value().expect("ok"); + println!("{}", val.to_string()); + Some(()) } /// The index of the pallet that the extrinsic originated from. @@ -558,6 +614,47 @@ impl ExtrinsicEvents { } } +pub struct ExtrinsicSignedExtensions<'a, T: Config> { + bytes: &'a [u8], + phantom: PhantomData, +} + +pub struct ExtrinsicSignedExtension { + phantom: PhantomData, +} + +impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { + pub fn bytes(&self) -> &[u8] { + &self.bytes + } + + pub fn find(&self, signed_extension: impl AsRef) -> ExtrinsicSignedExtension { + todo!() + } + + pub fn tip() -> Option { + todo!() + } + + pub fn nonce() -> Option { + todo!() + } +} + +impl ExtrinsicSignedExtension { + pub fn bytes(&self) -> &[u8] { + todo!() + } + + pub fn type_id(&self) -> u32 { + todo!() + } + + pub fn value(&self) -> scale_value::Value { + todo!() + } +} + #[cfg(test)] mod tests { use super::*; From ffec0b1400f442d285b3907cb3431b2a7bef2155 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 12 Oct 2023 15:32:37 +0200 Subject: [PATCH 02/27] signed extension decoding --- subxt/src/blocks/extrinsic_types.rs | 141 +++++++++++++++++++++++----- subxt/src/config/polkadot.rs | 1 + subxt/src/config/substrate.rs | 1 + 3 files changed, 119 insertions(+), 24 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 1e3bc2702f..62496f6222 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -14,12 +14,14 @@ use crate::{ use std::marker::PhantomData; use std::ops::Range; -use crate::dynamic::DecodedValueThunk; +use crate::dynamic::{DecodedValue, DecodedValueThunk}; use crate::metadata::DecodeWithMetadata; use crate::utils::strip_compact_prefix; -use codec::Decode; +use codec::{Compact, Decode}; use derivative::Derivative; use scale_decode::{DecodeAsFields, DecodeAsType}; +use scale_info::form::PortableForm; +use scale_info::{PortableRegistry, TypeDef}; use std::sync::Arc; /// Trait to uniquely identify the extrinsic's identity from the runtime metadata. @@ -374,16 +376,71 @@ where } /// Returns a reference to the signed extensions. - pub fn signed_extensions(&self) -> Option<()> { - let extra_bytes = self.extra_bytes()?; - let cursor: &mut &[u8] = &mut &extra_bytes[..]; - let signed = self.signed.as_ref().unwrap(); - let d = DecodedValueThunk::decode_with_metadata(cursor, signed.ids.extra, &self.metadata) - .expect("decoding err"); + /// + /// Returns `None` if the extrinsic is not signed. + /// Returns `Some(Err(..))` if the extrinsic is singed but something went wrong decoding the signed extensions. + pub fn signed_extensions(&self) -> Option, Error>> { + fn signed_extensions_or_err<'a, T: Config>( + extra_bytes: &'a [u8], + extra_ty_id: u32, + metadata: &'a Metadata, + ) -> Result, Error> { + let extra_type = metadata + .types() + .resolve(extra_ty_id) + .ok_or(MetadataError::TypeNotFound(extra_ty_id))?; + // the type behind this is expected to be a tuple that holds all the individual signed extensions + let TypeDef::Tuple(extra_tuple_type_def) = &extra_type.type_def else { + return Err(Error::Other( + "singed extra type def should be a tuple".into(), + )); + }; + + let mut signed_extensions: Vec> = vec![]; + + let mut cursor: &mut &[u8] = &mut &extra_bytes[..]; + let mut start_idx: usize = 0; + for field in extra_tuple_type_def.fields.iter() { + let ty_id = field.id; + let ty = metadata + .types() + .resolve(ty_id) + .ok_or(MetadataError::TypeNotFound(ty_id))?; + let name = ty.path.segments.last().ok_or_else(|| Error::Other("signed extension path segments should contain the signed extension name as the last element".into()))?; + scale_decode::visitor::decode_with_visitor( + cursor, + ty_id, + metadata.types(), + scale_decode::visitor::IgnoreVisitor, + ) + .map_err(|e| Error::Decode(e.into()))?; + let end_idx = extra_bytes.len() - cursor.len(); + let bytes = &extra_bytes[start_idx..end_idx]; + start_idx = end_idx; + signed_extensions.push(ExtrinsicSignedExtension { + bytes, + ty_id, + name, + metadata, + phantom: PhantomData, + }); + } + + Ok(ExtrinsicSignedExtensions { + bytes: extra_bytes, + signed_extensions, + metadata, + phantom: PhantomData, + }) + } - let val = d.to_value().expect("ok"); - println!("{}", val.to_string()); - Some(()) + let signed = self.signed.as_ref()?; + let extra_bytes = &self.bytes[signed.signature_end_idx..signed.extra_end_idx]; + Some(signed_extensions_or_err( + extra_bytes, + signed.ids.extra, + &self.metadata, + )) } /// The index of the pallet that the extrinsic originated from. @@ -614,44 +671,80 @@ impl ExtrinsicEvents { } } +#[derive(Debug, Clone)] pub struct ExtrinsicSignedExtensions<'a, T: Config> { + signed_extensions: Vec>, bytes: &'a [u8], + metadata: &'a Metadata, phantom: PhantomData, } -pub struct ExtrinsicSignedExtension { +#[derive(Debug, Clone)] +pub struct ExtrinsicSignedExtension<'a, T: Config> { + bytes: &'a [u8], + ty_id: u32, + name: &'a str, + metadata: &'a Metadata, phantom: PhantomData, } impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { + /// Returns the slice of bytes pub fn bytes(&self) -> &[u8] { - &self.bytes + self.bytes } - pub fn find(&self, signed_extension: impl AsRef) -> ExtrinsicSignedExtension { - todo!() + /// Returns a slice of all signed extensions + pub fn signed_extensions(&self) -> &[ExtrinsicSignedExtension] { + &self.signed_extensions } - pub fn tip() -> Option { - todo!() + /// Get a certain signed extension by its name. + pub fn find(&self, signed_extension: impl AsRef) -> Option<&ExtrinsicSignedExtension> { + self.signed_extensions + .iter() + .find(|e| e.name == signed_extension.as_ref()) + } + + /// The tip of an extrinsic, extracted from the ChargeTransactionPayment signed extension. + pub fn tip(&self) -> Option { + let tip = self.find("ChargeTransactionPayment")?; + let tip = Compact::::decode(&mut tip.bytes()).ok()?.0; + Some(tip) } - pub fn nonce() -> Option { - todo!() + /// The nonce of the account that submitted the extrinsic, extracted from the CheckNonce signed extension. + pub fn nonce(&self) -> Option { + let nonce = self.find("CheckNonce")?; + let nonce = Compact::::decode(&mut nonce.bytes()).ok()?.0; + Some(nonce) } } -impl ExtrinsicSignedExtension { +impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { pub fn bytes(&self) -> &[u8] { - todo!() + self.bytes + } + + pub fn name(&self) -> &str { + self.name } pub fn type_id(&self) -> u32 { - todo!() + self.ty_id } - pub fn value(&self) -> scale_value::Value { - todo!() + pub fn decoded(&self) -> Result { + let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( + &mut &self.bytes[..], + self.ty_id, + self.metadata, + )?; + Ok(decoded_value_thunk) + } + pub fn value(&self) -> Result { + let value = self.decoded()?.to_value()?; + Ok(value) } } diff --git a/subxt/src/config/polkadot.rs b/subxt/src/config/polkadot.rs index 5fb3390483..f47ae176f2 100644 --- a/subxt/src/config/polkadot.rs +++ b/subxt/src/config/polkadot.rs @@ -11,6 +11,7 @@ use crate::SubstrateConfig; pub use primitive_types::{H256, U256}; /// Default set of commonly used types by Polkadot nodes. +#[derive(Debug)] pub enum PolkadotConfig {} impl Config for PolkadotConfig { diff --git a/subxt/src/config/substrate.rs b/subxt/src/config/substrate.rs index 609b20a778..ea1d4a0a95 100644 --- a/subxt/src/config/substrate.rs +++ b/subxt/src/config/substrate.rs @@ -14,6 +14,7 @@ pub use primitive_types::{H256, U256}; /// Default set of commonly used types by Substrate runtimes. // Note: We only use this at the type level, so it should be impossible to // create an instance of it. +#[derive(Debug)] pub enum SubstrateConfig {} impl Config for SubstrateConfig { From b0fb96afd9ce901ab89e09bde8b611e226f940f0 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 16 Oct 2023 10:09:26 +0200 Subject: [PATCH 03/27] fix some minor things --- subxt/src/blocks/extrinsic_types.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 62496f6222..1d1a2ca9bc 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -12,7 +12,6 @@ use crate::{ Metadata, }; use std::marker::PhantomData; -use std::ops::Range; use crate::dynamic::{DecodedValue, DecodedValueThunk}; use crate::metadata::DecodeWithMetadata; @@ -20,8 +19,8 @@ use crate::utils::strip_compact_prefix; use codec::{Compact, Decode}; use derivative::Derivative; use scale_decode::{DecodeAsFields, DecodeAsType}; -use scale_info::form::PortableForm; -use scale_info::{PortableRegistry, TypeDef}; + +use scale_info::TypeDef; use std::sync::Arc; /// Trait to uniquely identify the extrinsic's identity from the runtime metadata. @@ -398,7 +397,7 @@ where let mut signed_extensions: Vec> = vec![]; - let mut cursor: &mut &[u8] = &mut &extra_bytes[..]; + let cursor: &mut &[u8] = &mut &extra_bytes[..]; let mut start_idx: usize = 0; for field in extra_tuple_type_def.fields.iter() { let ty_id = field.id; @@ -429,6 +428,7 @@ where Ok(ExtrinsicSignedExtensions { bytes: extra_bytes, signed_extensions, + ty_id: extra_ty_id, metadata, phantom: PhantomData, }) @@ -675,6 +675,7 @@ impl ExtrinsicEvents { pub struct ExtrinsicSignedExtensions<'a, T: Config> { signed_extensions: Vec>, bytes: &'a [u8], + ty_id: u32, metadata: &'a Metadata, phantom: PhantomData, } @@ -694,6 +695,17 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { self.bytes } + /// Returns a DecodedValueThunk of the signed extensions type. + /// Can be used to get all signed extensions as a scale value. + pub fn decoded(&self) -> Result { + let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( + &mut &self.bytes[..], + self.ty_id, + self.metadata, + )?; + Ok(decoded_value_thunk) + } + /// Returns a slice of all signed extensions pub fn signed_extensions(&self) -> &[ExtrinsicSignedExtension] { &self.signed_extensions @@ -722,18 +734,22 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { } impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { + /// The extra bytes associated with the signed extension. pub fn bytes(&self) -> &[u8] { self.bytes } + /// The name of the signed extension. pub fn name(&self) -> &str { self.name } + /// The type id of the signed extension. pub fn type_id(&self) -> u32 { self.ty_id } + /// DecodedValueThunk representing the type of the extra of this signed extension. pub fn decoded(&self) -> Result { let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( &mut &self.bytes[..], @@ -742,6 +758,8 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { )?; Ok(decoded_value_thunk) } + + /// Signed Extension as a [`scale_value::Value`] pub fn value(&self) -> Result { let value = self.decoded()?.to_value()?; Ok(value) From c87f165f71df924e9235b09521313415072ebd9a Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 23 Oct 2023 10:50:36 +0200 Subject: [PATCH 04/27] make api more similar to Extrinsics --- subxt/src/blocks/extrinsic_types.rs | 219 +++++++++++++--------------- subxt/src/config/polkadot.rs | 1 - subxt/src/config/substrate.rs | 1 - 3 files changed, 104 insertions(+), 117 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 1d1a2ca9bc..21bbd2bd67 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -11,7 +11,6 @@ use crate::{ metadata::types::PalletMetadata, Metadata, }; -use std::marker::PhantomData; use crate::dynamic::{DecodedValue, DecodedValueThunk}; use crate::metadata::DecodeWithMetadata; @@ -20,7 +19,6 @@ use codec::{Compact, Decode}; use derivative::Derivative; use scale_decode::{DecodeAsFields, DecodeAsType}; -use scale_info::TypeDef; use std::sync::Arc; /// Trait to uniquely identify the extrinsic's identity from the runtime metadata. @@ -161,7 +159,7 @@ pub struct ExtrinsicDetails { /// Extrinsic bytes. bytes: Arc<[u8]>, /// Some if the extrinsic payload is signed. - signed: Option, + signed_details: Option, /// The start index in the `bytes` from which the call is encoded. call_start_idx: usize, /// The pallet index. @@ -189,8 +187,6 @@ pub struct SignedExtrinsicDetails { signature_end_idx: usize, /// end index of the range in `bytes` of `ExtrinsicDetails` that encodes the signature. extra_end_idx: usize, - /// Extrinsic part type ids (address, signature, extra) - ids: ExtrinsicPartTypeIds, } impl ExtrinsicDetails @@ -232,46 +228,45 @@ where // Skip over the first byte which denotes the version and signing. let cursor = &mut &bytes[1..]; - let signed = if !is_signed { - None - } else { - let address_start_idx = bytes.len() - cursor.len(); - // Skip over the address, signature and extra fields. - scale_decode::visitor::decode_with_visitor( - cursor, - ids.address, - metadata.types(), - scale_decode::visitor::IgnoreVisitor, - ) - .map_err(scale_decode::Error::from)?; - let address_end_idx = bytes.len() - cursor.len(); - - scale_decode::visitor::decode_with_visitor( - cursor, - ids.signature, - metadata.types(), - scale_decode::visitor::IgnoreVisitor, - ) - .map_err(scale_decode::Error::from)?; - let signature_end_idx = bytes.len() - cursor.len(); - - scale_decode::visitor::decode_with_visitor( - cursor, - ids.extra, - metadata.types(), - scale_decode::visitor::IgnoreVisitor, - ) - .map_err(scale_decode::Error::from)?; - let extra_end_idx = bytes.len() - cursor.len(); - - Some(SignedExtrinsicDetails { - address_start_idx, - address_end_idx, - signature_end_idx, - extra_end_idx, - ids, + let signed_details = is_signed + .then(|| -> Result { + let address_start_idx = bytes.len() - cursor.len(); + // Skip over the address, signature and extra fields. + scale_decode::visitor::decode_with_visitor( + cursor, + ids.address, + metadata.types(), + scale_decode::visitor::IgnoreVisitor, + ) + .map_err(scale_decode::Error::from)?; + let address_end_idx = bytes.len() - cursor.len(); + + scale_decode::visitor::decode_with_visitor( + cursor, + ids.signature, + metadata.types(), + scale_decode::visitor::IgnoreVisitor, + ) + .map_err(scale_decode::Error::from)?; + let signature_end_idx = bytes.len() - cursor.len(); + + scale_decode::visitor::decode_with_visitor( + cursor, + ids.extra, + metadata.types(), + scale_decode::visitor::IgnoreVisitor, + ) + .map_err(scale_decode::Error::from)?; + let extra_end_idx = bytes.len() - cursor.len(); + + Ok(SignedExtrinsicDetails { + address_start_idx, + address_end_idx, + signature_end_idx, + extra_end_idx, + }) }) - }; + .transpose()?; let call_start_idx = bytes.len() - cursor.len(); @@ -284,7 +279,7 @@ where Ok(ExtrinsicDetails { index, bytes, - signed, + signed_details, call_start_idx, pallet_index, variant_index, @@ -298,7 +293,7 @@ where /// Is the extrinsic signed? pub fn is_signed(&self) -> bool { - self.signed.is_some() + self.signed_details.is_some() } /// The index of the extrinsic in the block. @@ -347,7 +342,7 @@ where /// /// Returns `None` if the extrinsic is not signed. pub fn address_bytes(&self) -> Option<&[u8]> { - self.signed + self.signed_details .as_ref() .map(|e| &self.bytes[e.address_start_idx..e.address_end_idx]) } @@ -358,7 +353,7 @@ where /// /// Returns `None` if the extrinsic is not signed. pub fn signature_bytes(&self) -> Option<&[u8]> { - self.signed + self.signed_details .as_ref() .map(|e| &self.bytes[e.address_end_idx..e.signature_end_idx]) } @@ -369,7 +364,7 @@ where /// /// Returns `None` if the extrinsic is not signed. pub fn extra_bytes(&self) -> Option<&[u8]> { - self.signed + self.signed_details .as_ref() .map(|e| &self.bytes[e.signature_end_idx..e.extra_end_idx]) } @@ -378,29 +373,18 @@ where /// /// Returns `None` if the extrinsic is not signed. /// Returns `Some(Err(..))` if the extrinsic is singed but something went wrong decoding the signed extensions. - pub fn signed_extensions(&self) -> Option, Error>> { - fn signed_extensions_or_err<'a, T: Config>( + pub fn signed_extensions(&self) -> Option> { + fn signed_extensions_or_err<'a>( extra_bytes: &'a [u8], - extra_ty_id: u32, metadata: &'a Metadata, - ) -> Result, Error> { - let extra_type = metadata - .types() - .resolve(extra_ty_id) - .ok_or(MetadataError::TypeNotFound(extra_ty_id))?; - // the type behind this is expected to be a tuple that holds all the individual signed extensions - let TypeDef::Tuple(extra_tuple_type_def) = &extra_type.type_def else { - return Err(Error::Other( - "singed extra type def should be a tuple".into(), - )); - }; - - let mut signed_extensions: Vec> = vec![]; + ) -> Result, Error> { + let signed_extension_types = metadata.extrinsic().signed_extensions(); + let mut signed_extensions: Vec = vec![]; let cursor: &mut &[u8] = &mut &extra_bytes[..]; let mut start_idx: usize = 0; - for field in extra_tuple_type_def.fields.iter() { - let ty_id = field.id; + for signed_extension_type in signed_extension_types { + let ty_id = signed_extension_type.extra_ty(); let ty = metadata .types() .resolve(ty_id) @@ -419,28 +403,20 @@ where signed_extensions.push(ExtrinsicSignedExtension { bytes, ty_id, - name, - metadata, - phantom: PhantomData, + identifier: name, + metadata: metadata.clone(), }); } Ok(ExtrinsicSignedExtensions { bytes: extra_bytes, - signed_extensions, - ty_id: extra_ty_id, - metadata, - phantom: PhantomData, + metadata: metadata.clone(), }) } - let signed = self.signed.as_ref()?; + let signed = self.signed_details.as_ref()?; let extra_bytes = &self.bytes[signed.signature_end_idx..signed.extra_end_idx]; - Some(signed_extensions_or_err( - extra_bytes, - signed.ids.extra, - &self.metadata, - )) + Some(signed_extensions_or_err(extra_bytes, &self.metadata)) } /// The index of the pallet that the extrinsic originated from. @@ -672,50 +648,63 @@ impl ExtrinsicEvents { } #[derive(Debug, Clone)] -pub struct ExtrinsicSignedExtensions<'a, T: Config> { - signed_extensions: Vec>, +pub struct ExtrinsicSignedExtensions<'a> { bytes: &'a [u8], - ty_id: u32, - metadata: &'a Metadata, - phantom: PhantomData, + metadata: Metadata, } #[derive(Debug, Clone)] -pub struct ExtrinsicSignedExtension<'a, T: Config> { +pub struct ExtrinsicSignedExtension<'a> { bytes: &'a [u8], ty_id: u32, - name: &'a str, - metadata: &'a Metadata, - phantom: PhantomData, + identifier: &'a str, + metadata: Metadata, } -impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { - /// Returns the slice of bytes - pub fn bytes(&self) -> &[u8] { - self.bytes +impl<'a> ExtrinsicSignedExtensions<'a> { + /// Get a certain signed extension by its name. + pub fn find(&self, signed_extension: impl AsRef) -> Option { + self.iter() + .find_map(|e| e.ok().filter(|e| e.name() == signed_extension.as_ref())) } - /// Returns a DecodedValueThunk of the signed extensions type. - /// Can be used to get all signed extensions as a scale value. - pub fn decoded(&self) -> Result { - let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( - &mut &self.bytes[..], - self.ty_id, - self.metadata, - )?; - Ok(decoded_value_thunk) - } + pub fn iter(&'a self) -> impl Iterator, Error>> { + let signed_extension_types = self.metadata.extrinsic().signed_extensions(); + let num_signed_extensions = signed_extension_types.len(); + let mut index = 0; + let mut byte_start_idx = 0; - /// Returns a slice of all signed extensions - pub fn signed_extensions(&self) -> &[ExtrinsicSignedExtension] { - &self.signed_extensions - } + std::iter::from_fn(move || { + if index == num_signed_extensions { + None + } else { + let extension = &signed_extension_types[index]; + let ty_id = extension.extra_ty(); + let cursor = &mut &self.bytes[byte_start_idx..]; + if let Err(err) = scale_decode::visitor::decode_with_visitor( + cursor, + ty_id, + self.metadata.types(), + scale_decode::visitor::IgnoreVisitor, + ) + .map_err(|e| Error::Decode(e.into())) + { + index = num_signed_extensions; // (Such that None is returned in next iteration) + return Some(Err(err)); + } - /// Get a certain signed extension by its name. - pub fn find(&self, signed_extension: impl AsRef) -> Option<&ExtrinsicSignedExtension> { - self.signed_extensions - .iter() - .find(|e| e.name == signed_extension.as_ref()) + let byte_end_idx = self.bytes.len() - cursor.len(); + byte_start_idx = byte_end_idx; + index += 1; + + Some(Ok(ExtrinsicSignedExtension { + bytes: &self.bytes[byte_start_idx..byte_end_idx], + ty_id, + identifier: extension.identifier(), + metadata: self.metadata.clone(), + })) + } + }) } /// The tip of an extrinsic, extracted from the ChargeTransactionPayment signed extension. @@ -733,7 +722,7 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { } } -impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { +impl<'a> ExtrinsicSignedExtension<'a> { /// The extra bytes associated with the signed extension. pub fn bytes(&self) -> &[u8] { self.bytes @@ -741,7 +730,7 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { /// The name of the signed extension. pub fn name(&self) -> &str { - self.name + self.identifier } /// The type id of the signed extension. @@ -754,7 +743,7 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( &mut &self.bytes[..], self.ty_id, - self.metadata, + &self.metadata, )?; Ok(decoded_value_thunk) } diff --git a/subxt/src/config/polkadot.rs b/subxt/src/config/polkadot.rs index f47ae176f2..5fb3390483 100644 --- a/subxt/src/config/polkadot.rs +++ b/subxt/src/config/polkadot.rs @@ -11,7 +11,6 @@ use crate::SubstrateConfig; pub use primitive_types::{H256, U256}; /// Default set of commonly used types by Polkadot nodes. -#[derive(Debug)] pub enum PolkadotConfig {} impl Config for PolkadotConfig { diff --git a/subxt/src/config/substrate.rs b/subxt/src/config/substrate.rs index ea1d4a0a95..609b20a778 100644 --- a/subxt/src/config/substrate.rs +++ b/subxt/src/config/substrate.rs @@ -14,7 +14,6 @@ pub use primitive_types::{H256, U256}; /// Default set of commonly used types by Substrate runtimes. // Note: We only use this at the type level, so it should be impossible to // create an instance of it. -#[derive(Debug)] pub enum SubstrateConfig {} impl Config for SubstrateConfig { From 4ed554d39734843f2c77f8b74d29b6474b046e0c Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 23 Oct 2023 14:42:23 +0200 Subject: [PATCH 05/27] defer decoding of signed extensions --- subxt/src/blocks/extrinsic_types.rs | 50 +++-------------------------- 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 21bbd2bd67..b01affb4d1 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -369,54 +369,14 @@ where .map(|e| &self.bytes[e.signature_end_idx..e.extra_end_idx]) } - /// Returns a reference to the signed extensions. - /// /// Returns `None` if the extrinsic is not signed. - /// Returns `Some(Err(..))` if the extrinsic is singed but something went wrong decoding the signed extensions. - pub fn signed_extensions(&self) -> Option> { - fn signed_extensions_or_err<'a>( - extra_bytes: &'a [u8], - metadata: &'a Metadata, - ) -> Result, Error> { - let signed_extension_types = metadata.extrinsic().signed_extensions(); - let mut signed_extensions: Vec = vec![]; - - let cursor: &mut &[u8] = &mut &extra_bytes[..]; - let mut start_idx: usize = 0; - for signed_extension_type in signed_extension_types { - let ty_id = signed_extension_type.extra_ty(); - let ty = metadata - .types() - .resolve(ty_id) - .ok_or(MetadataError::TypeNotFound(ty_id))?; - let name = ty.path.segments.last().ok_or_else(|| Error::Other("signed extension path segments should contain the signed extension name as the last element".into()))?; - scale_decode::visitor::decode_with_visitor( - cursor, - ty_id, - metadata.types(), - scale_decode::visitor::IgnoreVisitor, - ) - .map_err(|e| Error::Decode(e.into()))?; - let end_idx = extra_bytes.len() - cursor.len(); - let bytes = &extra_bytes[start_idx..end_idx]; - start_idx = end_idx; - signed_extensions.push(ExtrinsicSignedExtension { - bytes, - ty_id, - identifier: name, - metadata: metadata.clone(), - }); - } - - Ok(ExtrinsicSignedExtensions { - bytes: extra_bytes, - metadata: metadata.clone(), - }) - } - + pub fn signed_extensions(&self) -> Option { let signed = self.signed_details.as_ref()?; let extra_bytes = &self.bytes[signed.signature_end_idx..signed.extra_end_idx]; - Some(signed_extensions_or_err(extra_bytes, &self.metadata)) + Some(ExtrinsicSignedExtensions { + bytes: extra_bytes, + metadata: self.metadata.clone(), + }) } /// The index of the pallet that the extrinsic originated from. From 460bfaf55e7d0c4091a034dc3241b6e7eff64eca Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 23 Oct 2023 15:46:06 +0200 Subject: [PATCH 06/27] fix byte slices --- subxt/src/blocks/extrinsic_types.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index b01affb4d1..de864be178 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -649,16 +649,15 @@ impl<'a> ExtrinsicSignedExtensions<'a> { ) .map_err(|e| Error::Decode(e.into())) { - index = num_signed_extensions; // (Such that None is returned in next iteration) + index = num_signed_extensions; // (such that None is returned in next iteration) return Some(Err(err)); } - let byte_end_idx = self.bytes.len() - cursor.len(); + let bytes = &self.bytes[byte_start_idx..byte_end_idx]; byte_start_idx = byte_end_idx; index += 1; - Some(Ok(ExtrinsicSignedExtension { - bytes: &self.bytes[byte_start_idx..byte_end_idx], + bytes, ty_id, identifier: extension.identifier(), metadata: self.metadata.clone(), From ea59e6c5b5c48e8d2be88eeeb1fc69017f0391d8 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 23 Oct 2023 17:50:37 +0200 Subject: [PATCH 07/27] add test for nonce signed extension --- .../src/full_client/blocks/mod.rs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 3ea80a4afe..a8b1e0deb0 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -227,3 +227,54 @@ async fn fetch_block_and_decode_extrinsic_details() { assert_eq!(ext.value, 10_000); assert!(tx.is_signed()); } + +#[tokio::test] +async fn decode_signed_extensions_from_blocks() { + let ctx = test_context().await; + let api = ctx.client(); + let alice = dev::alice(); + let bob = dev::bob(); + + let submit_tranfer_extrinsic_and_get_it_back = || async { + let tx = node_runtime::tx() + .balances() + .transfer_allow_death(bob.public_key().into(), 10_000); + + let signed_extrinsic = api + .tx() + .create_signed(&tx, &alice, Default::default()) + .await + .unwrap(); + + let in_block = signed_extrinsic + .submit_and_watch() + .await + .unwrap() + .wait_for_in_block() + .await + .unwrap(); + + let block_hash = in_block.block_hash(); + let block = api.blocks().at(block_hash).await.unwrap(); + let extrinsics = block.extrinsics().await.unwrap(); + let extrinsic_details = extrinsics.iter().next().unwrap().unwrap(); + extrinsic_details + }; + + let first_transaction = submit_tranfer_extrinsic_and_get_it_back().await; + let first_transaction_nonce = first_transaction + .signed_extensions() + .unwrap() + .nonce() + .unwrap(); + + let second_transaction = submit_tranfer_extrinsic_and_get_it_back().await; + let second_transaction_nonce = first_transaction + .signed_extensions() + .unwrap() + .nonce() + .unwrap(); + + assert_eq!(first_transaction_nonce, 0); + assert_eq!(second_transaction_nonce, 1); +} From 3dad99711e3d83eea93931ce7d99daf0d6dfd52d Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 24 Oct 2023 10:32:00 +0200 Subject: [PATCH 08/27] adjust test and extend for tip --- subxt/src/blocks/extrinsic_types.rs | 2 +- .../src/full_client/blocks/mod.rs | 91 +++++++++++-------- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index de864be178..3ca0f1b50b 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -668,7 +668,7 @@ impl<'a> ExtrinsicSignedExtensions<'a> { /// The tip of an extrinsic, extracted from the ChargeTransactionPayment signed extension. pub fn tip(&self) -> Option { - let tip = self.find("ChargeTransactionPayment")?; + let tip = self.find("ChargeAssetTxPayment")?; let tip = Compact::::decode(&mut tip.bytes()).ok()?.0; Some(tip) } diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index a8b1e0deb0..14d16c272a 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -2,9 +2,13 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +use crate::utils::TestContext; use crate::{test_context, utils::node_runtime}; use codec::{Compact, Encode}; use futures::StreamExt; +use std::future::Future; +use std::time::Duration; +use subxt::config::DefaultExtrinsicParamsBuilder; use subxt_metadata::Metadata; use subxt_signer::sr25519::dev; @@ -235,46 +239,53 @@ async fn decode_signed_extensions_from_blocks() { let alice = dev::alice(); let bob = dev::bob(); - let submit_tranfer_extrinsic_and_get_it_back = || async { - let tx = node_runtime::tx() - .balances() - .transfer_allow_death(bob.public_key().into(), 10_000); - - let signed_extrinsic = api - .tx() - .create_signed(&tx, &alice, Default::default()) - .await - .unwrap(); - - let in_block = signed_extrinsic - .submit_and_watch() - .await - .unwrap() - .wait_for_in_block() - .await - .unwrap(); - - let block_hash = in_block.block_hash(); - let block = api.blocks().at(block_hash).await.unwrap(); - let extrinsics = block.extrinsics().await.unwrap(); - let extrinsic_details = extrinsics.iter().next().unwrap().unwrap(); - extrinsic_details - }; - - let first_transaction = submit_tranfer_extrinsic_and_get_it_back().await; - let first_transaction_nonce = first_transaction - .signed_extensions() - .unwrap() - .nonce() - .unwrap(); + macro_rules! submit_transfer_extrinsic_and_get_it_back { + ($tip:expr) => {{ + let tx = node_runtime::tx() + .balances() + .transfer_allow_death(bob.public_key().into(), 10_000); + + let signed_extrinsic = api + .tx() + .create_signed( + &tx, + &alice, + DefaultExtrinsicParamsBuilder::new().tip($tip).build(), + ) + .await + .unwrap(); + + let in_block = signed_extrinsic + .submit_and_watch() + .await + .unwrap() + .wait_for_finalized() + .await + .unwrap(); + + let block_hash = in_block.block_hash(); + let block = api.blocks().at(block_hash).await.unwrap(); + let extrinsics = block.extrinsics().await.unwrap(); + let extrinsic_details = extrinsics + .iter() + .find_map(|e| e.ok().filter(|e| e.is_signed())) + .unwrap(); + extrinsic_details + }}; + } - let second_transaction = submit_tranfer_extrinsic_and_get_it_back().await; - let second_transaction_nonce = first_transaction - .signed_extensions() - .unwrap() - .nonce() - .unwrap(); + let transaction1 = submit_transfer_extrinsic_and_get_it_back!(1234); + let extensions1 = transaction1.signed_extensions().unwrap(); + let nonce1 = extensions1.nonce().unwrap(); + let tip1 = extensions1.tip().unwrap(); + + let transaction2 = submit_transfer_extrinsic_and_get_it_back!(5678); + let extensions2 = transaction2.signed_extensions().unwrap(); + let nonce2 = extensions2.nonce().unwrap(); + let tip2 = extensions2.tip().unwrap(); - assert_eq!(first_transaction_nonce, 0); - assert_eq!(second_transaction_nonce, 1); + assert_eq!(nonce1, 0); + assert_eq!(tip1, 1234); + assert_eq!(nonce2, 1); + assert_eq!(tip2, 5678); } From 0eabab961805ef983479a4dc2bf54e35a8c922d4 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 24 Oct 2023 13:18:20 +0200 Subject: [PATCH 09/27] clippy --- testing/integration-tests/src/full_client/blocks/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 14d16c272a..c9278aa0c4 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -2,12 +2,12 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use crate::utils::TestContext; + use crate::{test_context, utils::node_runtime}; use codec::{Compact, Encode}; use futures::StreamExt; -use std::future::Future; -use std::time::Duration; + + use subxt::config::DefaultExtrinsicParamsBuilder; use subxt_metadata::Metadata; use subxt_signer::sr25519::dev; From 58fd6543d6f45c4840c4525e62706cb1d18cad30 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 24 Oct 2023 13:50:01 +0200 Subject: [PATCH 10/27] support both ChargeTransactionPayment and ChargeAssetTxPayment --- subxt/src/blocks/extrinsic_types.rs | 6 +++++- testing/integration-tests/src/full_client/blocks/mod.rs | 2 -- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 3ca0f1b50b..543577b8f0 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -668,7 +668,11 @@ impl<'a> ExtrinsicSignedExtensions<'a> { /// The tip of an extrinsic, extracted from the ChargeTransactionPayment signed extension. pub fn tip(&self) -> Option { - let tip = self.find("ChargeAssetTxPayment")?; + let tip = self + .find("ChargeTransactionPayment") + .or_else(|| self.find("ChargeAssetTxPayment"))?; + // Note: ChargeAssetTxPayment might have addition information in it (asset_id). + // But both should start with a compact encoded u128, so this decoding is fine. let tip = Compact::::decode(&mut tip.bytes()).ok()?.0; Some(tip) } diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index c9278aa0c4..209f76bef2 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -2,12 +2,10 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. - use crate::{test_context, utils::node_runtime}; use codec::{Compact, Encode}; use futures::StreamExt; - use subxt::config::DefaultExtrinsicParamsBuilder; use subxt_metadata::Metadata; use subxt_signer::sr25519::dev; From 1dd8f53656e84341cf07c4e0b443a77673380c4f Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Wed, 25 Oct 2023 19:38:30 +0200 Subject: [PATCH 11/27] address PR comments --- subxt/src/blocks/extrinsic_types.rs | 98 ++++++++++--------- .../src/full_client/blocks/mod.rs | 20 ++++ 2 files changed, 72 insertions(+), 46 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 543577b8f0..8ba413c3f3 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -358,12 +358,13 @@ where .map(|e| &self.bytes[e.address_end_idx..e.signature_end_idx]) } - /// Return only the bytes of the extra fields for this signed extrinsic. + /// Returns the signed extension `extra` bytes of the extrinsic. + /// Each signed extension has an `extra` type (May be zero-sized). + /// These bytes are the scale encoded `extra` fields of each signed extension in order of the signed extensions. + /// They do *not* include the `additional` signed bytes that are used as part of the payload that is signed. /// - /// # Note - /// - /// Returns `None` if the extrinsic is not signed. - pub fn extra_bytes(&self) -> Option<&[u8]> { + /// Note: Returns `None` if the extrinsic is not signed. + pub fn signed_extensions_bytes(&self) -> Option<&[u8]> { self.signed_details .as_ref() .map(|e| &self.bytes[e.signature_end_idx..e.extra_end_idx]) @@ -607,12 +608,14 @@ impl ExtrinsicEvents { } } +/// The signed extensions of an extrinsic. #[derive(Debug, Clone)] pub struct ExtrinsicSignedExtensions<'a> { bytes: &'a [u8], metadata: Metadata, } +/// A single signed extension #[derive(Debug, Clone)] pub struct ExtrinsicSignedExtension<'a> { bytes: &'a [u8], @@ -622,12 +625,8 @@ pub struct ExtrinsicSignedExtension<'a> { } impl<'a> ExtrinsicSignedExtensions<'a> { - /// Get a certain signed extension by its name. - pub fn find(&self, signed_extension: impl AsRef) -> Option { - self.iter() - .find_map(|e| e.ok().filter(|e| e.name() == signed_extension.as_ref())) - } - + /// Returns an iterator ove all signed extensions, allowing access to their names, bytes and types. + /// If the decoding of any signed extension fails, an error item is yielded and the iterator stops. pub fn iter(&'a self) -> impl Iterator, Error>> { let signed_extension_types = self.metadata.extrinsic().signed_extensions(); let num_signed_extensions = signed_extension_types.len(); @@ -636,41 +635,43 @@ impl<'a> ExtrinsicSignedExtensions<'a> { std::iter::from_fn(move || { if index == num_signed_extensions { - None - } else { - let extension = &signed_extension_types[index]; - let ty_id = extension.extra_ty(); - let cursor = &mut &self.bytes[byte_start_idx..]; - if let Err(err) = scale_decode::visitor::decode_with_visitor( - cursor, - ty_id, - self.metadata.types(), - scale_decode::visitor::IgnoreVisitor, - ) - .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 = self.bytes.len() - cursor.len(); - let bytes = &self.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: self.metadata.clone(), - })) + return None; + } + + let extension = &signed_extension_types[index]; + let ty_id = extension.extra_ty(); + let cursor = &mut &self.bytes[byte_start_idx..]; + if let Err(err) = scale_decode::visitor::decode_with_visitor( + cursor, + ty_id, + self.metadata.types(), + scale_decode::visitor::IgnoreVisitor, + ) + .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 = self.bytes.len() - cursor.len(); + let bytes = &self.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: self.metadata.clone(), + })) }) } - /// The tip of an extrinsic, extracted from the ChargeTransactionPayment signed extension. + /// The tip of an extrinsic, extracted from the ChargeTransactionPayment or ChargeAssetTxPayment signed extension, depending on which is present. pub fn tip(&self) -> Option { - let tip = self - .find("ChargeTransactionPayment") - .or_else(|| self.find("ChargeAssetTxPayment"))?; + let tip = self.iter().find_map(|e| { + e.ok().filter(|e| { + e.name() == "ChargeTransactionPayment" || e.name() == "ChargeAssetTxPayment" + }) + })?; // Note: ChargeAssetTxPayment might have addition information in it (asset_id). // But both should start with a compact encoded u128, so this decoding is fine. let tip = Compact::::decode(&mut tip.bytes()).ok()?.0; @@ -679,14 +680,16 @@ impl<'a> ExtrinsicSignedExtensions<'a> { /// The nonce of the account that submitted the extrinsic, extracted from the CheckNonce signed extension. pub fn nonce(&self) -> Option { - let nonce = self.find("CheckNonce")?; + let nonce = self + .iter() + .find_map(|e| e.ok().filter(|e| e.name() == "CheckNonce"))?; let nonce = Compact::::decode(&mut nonce.bytes()).ok()?.0; Some(nonce) } } impl<'a> ExtrinsicSignedExtension<'a> { - /// The extra bytes associated with the signed extension. + /// The bytes representing this signed extension. pub fn bytes(&self) -> &[u8] { self.bytes } @@ -702,7 +705,7 @@ impl<'a> ExtrinsicSignedExtension<'a> { } /// DecodedValueThunk representing the type of the extra of this signed extension. - pub fn decoded(&self) -> Result { + fn decoded(&self) -> Result { let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( &mut &self.bytes[..], self.ty_id, @@ -713,8 +716,11 @@ impl<'a> ExtrinsicSignedExtension<'a> { /// Signed Extension as a [`scale_value::Value`] pub fn value(&self) -> Result { - let value = self.decoded()?.to_value()?; - Ok(value) + self.decoded()?.to_value() + } + + pub fn as_type(&self) -> Result { + self.decoded()?.as_type::().map_err(Into::into) } } diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 209f76bef2..52bebe2e59 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -272,6 +272,17 @@ async fn decode_signed_extensions_from_blocks() { }}; } + let expected_signed_extensions = [ + "CheckNonZeroSender", + "CheckSpecVersion", + "CheckTxVersion", + "CheckGenesis", + "CheckMortality", + "CheckNonce", + "CheckWeight", + "ChargeAssetTxPayment", + ]; + let transaction1 = submit_transfer_extrinsic_and_get_it_back!(1234); let extensions1 = transaction1.signed_extensions().unwrap(); let nonce1 = extensions1.nonce().unwrap(); @@ -286,4 +297,13 @@ async fn decode_signed_extensions_from_blocks() { assert_eq!(tip1, 1234); assert_eq!(nonce2, 1); assert_eq!(tip2, 5678); + + assert_eq!(extensions1.iter().count(), expected_signed_extensions.len()); + for (e, expected_name) in extensions1.iter().zip(expected_signed_extensions.iter()) { + assert_eq!(e.unwrap().name(), *expected_name); + } + assert_eq!(extensions2.iter().count(), expected_signed_extensions.len()); + for (e, expected_name) in extensions2.iter().zip(expected_signed_extensions.iter()) { + assert_eq!(e.unwrap().name(), *expected_name); + } } From 64b5c90852bfca7dfa00c8dc80e2818f05075bdb Mon Sep 17 00:00:00 2001 From: James Wilson Date: Fri, 27 Oct 2023 16:06:37 +0100 Subject: [PATCH 12/27] Extend lifetimes, expose pub structs, remove as_type --- subxt/src/blocks/extrinsic_types.rs | 73 +++++++++++++---------------- subxt/src/blocks/mod.rs | 5 +- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 8ba413c3f3..3bf4f87acc 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -12,8 +12,7 @@ use crate::{ Metadata, }; -use crate::dynamic::{DecodedValue, DecodedValueThunk}; -use crate::metadata::DecodeWithMetadata; +use crate::dynamic::DecodedValue; use crate::utils::strip_compact_prefix; use codec::{Compact, Decode}; use derivative::Derivative; @@ -371,12 +370,12 @@ where } /// Returns `None` if the extrinsic is not signed. - pub fn signed_extensions(&self) -> Option { + pub fn signed_extensions(&self) -> Option> { let signed = self.signed_details.as_ref()?; let extra_bytes = &self.bytes[signed.signature_end_idx..signed.extra_end_idx]; Some(ExtrinsicSignedExtensions { bytes: extra_bytes, - metadata: self.metadata.clone(), + metadata: &self.metadata, }) } @@ -612,24 +611,17 @@ impl ExtrinsicEvents { #[derive(Debug, Clone)] pub struct ExtrinsicSignedExtensions<'a> { bytes: &'a [u8], - metadata: Metadata, -} - -/// A single signed extension -#[derive(Debug, Clone)] -pub struct ExtrinsicSignedExtension<'a> { - bytes: &'a [u8], - ty_id: u32, - identifier: &'a str, - metadata: Metadata, + metadata: &'a Metadata, } impl<'a> ExtrinsicSignedExtensions<'a> { - /// Returns an iterator ove all signed extensions, allowing access to their names, bytes and types. + /// 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(&'a self) -> impl Iterator, Error>> { + pub fn iter(&self) -> impl Iterator, Error>> { let signed_extension_types = self.metadata.extrinsic().signed_extensions(); let num_signed_extensions = signed_extension_types.len(); + let bytes = self.bytes; + let metadata = self.metadata; let mut index = 0; let mut byte_start_idx = 0; @@ -640,11 +632,11 @@ impl<'a> ExtrinsicSignedExtensions<'a> { let extension = &signed_extension_types[index]; let ty_id = extension.extra_ty(); - let cursor = &mut &self.bytes[byte_start_idx..]; + let cursor = &mut &bytes[byte_start_idx..]; if let Err(err) = scale_decode::visitor::decode_with_visitor( cursor, ty_id, - self.metadata.types(), + metadata.types(), scale_decode::visitor::IgnoreVisitor, ) .map_err(|e| Error::Decode(e.into())) @@ -652,33 +644,36 @@ impl<'a> ExtrinsicSignedExtensions<'a> { index = num_signed_extensions; // (such that None is returned in next iteration) return Some(Err(err)); } - let byte_end_idx = self.bytes.len() - cursor.len(); - let bytes = &self.bytes[byte_start_idx..byte_end_idx]; + 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: self.metadata.clone(), + metadata, })) }) } - /// The tip of an extrinsic, extracted from the ChargeTransactionPayment or ChargeAssetTxPayment signed extension, depending on which is present. + /// The tip of an extrinsic, extracted from the `ChargeTransactionPayment` or + /// `ChargeAssetTxPayment` signed extension, depending on which is present. pub fn tip(&self) -> Option { let tip = self.iter().find_map(|e| { e.ok().filter(|e| { e.name() == "ChargeTransactionPayment" || e.name() == "ChargeAssetTxPayment" }) })?; + // Note: ChargeAssetTxPayment might have addition information in it (asset_id). - // But both should start with a compact encoded u128, so this decoding is fine. + // But both should start with a compact encoded u128, so this decoding is fine. let tip = Compact::::decode(&mut tip.bytes()).ok()?.0; Some(tip) } - /// The nonce of the account that submitted the extrinsic, extracted from the CheckNonce signed extension. + /// The nonce of the account that submitted the extrinsic, extracted from the + /// CheckNonce signed extension. pub fn nonce(&self) -> Option { let nonce = self .iter() @@ -688,14 +683,23 @@ impl<'a> ExtrinsicSignedExtensions<'a> { } } +/// A single signed extension +#[derive(Debug, Clone)] +pub struct ExtrinsicSignedExtension<'a> { + bytes: &'a [u8], + ty_id: u32, + identifier: &'a str, + metadata: &'a Metadata, +} + impl<'a> ExtrinsicSignedExtension<'a> { /// The bytes representing this signed extension. - pub fn bytes(&self) -> &[u8] { + pub fn bytes(&self) -> &'a [u8] { self.bytes } /// The name of the signed extension. - pub fn name(&self) -> &str { + pub fn name(&self) -> &'a str { self.identifier } @@ -704,23 +708,12 @@ impl<'a> ExtrinsicSignedExtension<'a> { self.ty_id } - /// DecodedValueThunk representing the type of the extra of this signed extension. - fn decoded(&self) -> Result { - let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( - &mut &self.bytes[..], - self.ty_id, - &self.metadata, - )?; - Ok(decoded_value_thunk) - } - /// Signed Extension as a [`scale_value::Value`] pub fn value(&self) -> Result { - self.decoded()?.to_value() - } + let value = + DecodedValue::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?; - pub fn as_type(&self) -> Result { - self.decoded()?.as_type::().map_err(Into::into) + Ok(value) } } diff --git a/subxt/src/blocks/mod.rs b/subxt/src/blocks/mod.rs index fd06594e60..7cf2501b9d 100644 --- a/subxt/src/blocks/mod.rs +++ b/subxt/src/blocks/mod.rs @@ -13,7 +13,10 @@ pub use crate::backend::BlockRef; pub use block_types::Block; pub use blocks_client::BlocksClient; -pub use extrinsic_types::{ExtrinsicDetails, ExtrinsicEvents, Extrinsics, StaticExtrinsic}; +pub use extrinsic_types::{ + ExtrinsicDetails, ExtrinsicEvents, ExtrinsicSignedExtension, ExtrinsicSignedExtensions, + Extrinsics, StaticExtrinsic, +}; // We get account nonce info in tx_client, too, so re-use the logic: pub(crate) use block_types::get_account_nonce; From fe1db8c154f1e051c85c2d58a0da560f95ab2e4f Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 30 Oct 2023 16:57:44 +0100 Subject: [PATCH 13/27] add signed extensions to block subscribing example --- subxt/examples/blocks_subscribing.rs | 11 +++++++++++ subxt/src/blocks/extrinsic_types.rs | 17 ++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/subxt/examples/blocks_subscribing.rs b/subxt/examples/blocks_subscribing.rs index 4f06221484..80b732795c 100644 --- a/subxt/examples/blocks_subscribing.rs +++ b/subxt/examples/blocks_subscribing.rs @@ -34,6 +34,17 @@ async fn main() -> Result<(), Box> { let decoded_ext = ext.as_root_extrinsic::(); println!(" Extrinsic #{idx}:"); + if let Some(signed_extensions) = ext.signed_extensions() { + println!(" Signed Extensions:"); + for signed_extension in signed_extensions.iter() { + let signed_extension = signed_extension?; + let name = signed_extension.name(); + let value = signed_extension.value()?.to_string(); + println!(" {name}: {value}"); + } + } else { + println!(" No Signed Extensions"); + } println!(" Bytes: {bytes_hex}"); println!(" Decoded: {decoded_ext:?}"); println!(" Events:"); diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 3bf4f87acc..6f9d1fbf39 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -346,11 +346,7 @@ where .map(|e| &self.bytes[e.address_start_idx..e.address_end_idx]) } - /// Return only the bytes of the signature for this signed extrinsic. - /// - /// # Note - /// - /// Returns `None` if the extrinsic is not signed. + /// Returns Some(signature_bytes) if the extrinsic was signed otherwise None is returned. pub fn signature_bytes(&self) -> Option<&[u8]> { self.signed_details .as_ref() @@ -657,8 +653,10 @@ impl<'a> ExtrinsicSignedExtensions<'a> { }) } - /// The tip of an extrinsic, extracted from the `ChargeTransactionPayment` or - /// `ChargeAssetTxPayment` signed extension, depending on which is present. + /// 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 { let tip = self.iter().find_map(|e| { e.ok().filter(|e| { @@ -672,8 +670,9 @@ impl<'a> ExtrinsicSignedExtensions<'a> { Some(tip) } - /// The nonce of the account that submitted the extrinsic, extracted from the - /// CheckNonce signed extension. + /// 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 { let nonce = self .iter() From 8c93d5b7bc3e7d66f081b154019132022c905d9c Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 30 Oct 2023 18:52:44 +0100 Subject: [PATCH 14/27] add Decoded type --- subxt/src/blocks/extrinsic_types.rs | 74 +++++++++++++------ subxt/src/config/signed_extensions.rs | 21 +++++- subxt/src/utils/era.rs | 6 +- .../src/full_client/blocks/mod.rs | 7 ++ 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 6f9d1fbf39..97a8d90e73 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -12,12 +12,14 @@ use crate::{ Metadata, }; -use crate::dynamic::DecodedValue; +use crate::config::signed_extensions::{ChargeAssetTxPayment, ChargeTransactionPayment}; +use crate::config::SignedExtension; +use crate::dynamic::{DecodedValue, DecodedValueThunk}; +use crate::metadata::DecodeWithMetadata; use crate::utils::strip_compact_prefix; use codec::{Compact, Decode}; use derivative::Derivative; use scale_decode::{DecodeAsFields, DecodeAsType}; - use std::sync::Arc; /// Trait to uniquely identify the extrinsic's identity from the runtime metadata. @@ -366,12 +368,13 @@ where } /// Returns `None` if the extrinsic is not signed. - pub fn signed_extensions(&self) -> Option> { + pub fn signed_extensions(&self) -> Option> { let signed = self.signed_details.as_ref()?; let extra_bytes = &self.bytes[signed.signature_end_idx..signed.extra_end_idx]; Some(ExtrinsicSignedExtensions { bytes: extra_bytes, - metadata: &self.metadata, + metadata: self.metadata.clone(), + _marker: std::marker::PhantomData, }) } @@ -605,19 +608,19 @@ impl ExtrinsicEvents { /// The signed extensions of an extrinsic. #[derive(Debug, Clone)] -pub struct ExtrinsicSignedExtensions<'a> { +pub struct ExtrinsicSignedExtensions<'a, T: Config> { bytes: &'a [u8], - metadata: &'a Metadata, + metadata: Metadata, + _marker: std::marker::PhantomData, } -impl<'a> ExtrinsicSignedExtensions<'a> { +impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { /// 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, Error>> { + pub fn iter(&'a self) -> impl Iterator, Error>> { let signed_extension_types = self.metadata.extrinsic().signed_extensions(); let num_signed_extensions = signed_extension_types.len(); let bytes = self.bytes; - let metadata = self.metadata; let mut index = 0; let mut byte_start_idx = 0; @@ -632,7 +635,7 @@ impl<'a> ExtrinsicSignedExtensions<'a> { if let Err(err) = scale_decode::visitor::decode_with_visitor( cursor, ty_id, - metadata.types(), + self.metadata.types(), scale_decode::visitor::IgnoreVisitor, ) .map_err(|e| Error::Decode(e.into())) @@ -648,21 +651,35 @@ impl<'a> ExtrinsicSignedExtensions<'a> { bytes, ty_id, identifier: extension.identifier(), - metadata, + metadata: self.metadata.clone(), + _marker: std::marker::PhantomData, })) }) } + fn find_by_name(&self, name: impl AsRef) -> Option> { + let signed_extension = self + .iter() + .find_map(|e| e.ok().filter(|e| e.name() == name.as_ref()))?; + Some(signed_extension) + } + + /// Searches through all signed extensions to find a specific one. + /// If the Signed Extension is found, but decoding failed, `Some(Err(err))` is returned. + pub fn find>(&self) -> Option> { + let signed_extension = self.find_by_name(S::NAME)?; + Some(signed_extension.as_type().map_err(Into::into)) + } + /// 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 { - let tip = self.iter().find_map(|e| { - e.ok().filter(|e| { - e.name() == "ChargeTransactionPayment" || e.name() == "ChargeAssetTxPayment" - }) - })?; + // Note: the overhead of iterating twice should be negligible. + let tip = self + .find_by_name(>::NAME) + .or_else(|| self.find_by_name(>::NAME))?; // Note: ChargeAssetTxPayment might have addition information in it (asset_id). // But both should start with a compact encoded u128, so this decoding is fine. @@ -684,14 +701,15 @@ impl<'a> ExtrinsicSignedExtensions<'a> { /// A single signed extension #[derive(Debug, Clone)] -pub struct ExtrinsicSignedExtension<'a> { +pub struct ExtrinsicSignedExtension<'a, T: Config> { bytes: &'a [u8], ty_id: u32, identifier: &'a str, - metadata: &'a Metadata, + metadata: Metadata, + _marker: std::marker::PhantomData, } -impl<'a> ExtrinsicSignedExtension<'a> { +impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { /// The bytes representing this signed extension. pub fn bytes(&self) -> &'a [u8] { self.bytes @@ -707,12 +725,24 @@ impl<'a> ExtrinsicSignedExtension<'a> { self.ty_id } + /// DecodedValueThunk representing the type of the extra of this signed extension. + fn decoded(&self) -> Result { + let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( + &mut &self.bytes[..], + self.ty_id, + &self.metadata, + )?; + Ok(decoded_value_thunk) + } + /// Signed Extension as a [`scale_value::Value`] pub fn value(&self) -> Result { - let value = - DecodedValue::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?; + self.decoded()?.to_value() + } - Ok(value) + /// Decodes the `extra` bytes of this Signed Extension into a static type. + pub fn as_type(&self) -> Result { + self.decoded()?.as_type::().map_err(Into::into) } } diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index 5b6e43d58a..77a6a8d4a1 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -12,6 +12,7 @@ use crate::utils::Era; use crate::{client::OfflineClientT, Config}; use codec::{Compact, Encode}; use core::fmt::Debug; +use scale_decode::DecodeAsType; use std::collections::HashMap; /// A single [`SignedExtension`] has a unique name, but is otherwise the @@ -21,6 +22,11 @@ pub trait SignedExtension: ExtrinsicParams { /// The name of the signed extension. This is used to associate it /// with the signed extensions that the node is making use of. const NAME: &'static str; + + /// The type representing the `extra` bytes of a signed extension. + /// Decoding from this type should be symmetrical to the respective + /// `ExtrinsicParamsEncoder::encode_extra_to()` implementation of this signed extension. + type Decoded: DecodeAsType; } /// The [`CheckSpecVersion`] signed extension. @@ -48,6 +54,7 @@ impl ExtrinsicParamsEncoder for CheckSpecVersion { impl SignedExtension for CheckSpecVersion { const NAME: &'static str = "CheckSpecVersion"; + type Decoded = (); } /// The [`CheckNonce`] signed extension. @@ -75,6 +82,7 @@ impl ExtrinsicParamsEncoder for CheckNonce { impl SignedExtension for CheckNonce { const NAME: &'static str = "CheckNonce"; + type Decoded = Compact; } /// The [`CheckTxVersion`] signed extension. @@ -102,6 +110,7 @@ impl ExtrinsicParamsEncoder for CheckTxVersion { impl SignedExtension for CheckTxVersion { const NAME: &'static str = "CheckTxVersion"; + type Decoded = (); } /// The [`CheckGenesis`] signed extension. @@ -134,6 +143,7 @@ impl ExtrinsicParamsEncoder for CheckGenesis { impl SignedExtension for CheckGenesis { const NAME: &'static str = "CheckGenesis"; + type Decoded = (); } /// The [`CheckMortality`] signed extension. @@ -213,10 +223,11 @@ impl ExtrinsicParamsEncoder for CheckMortality { impl SignedExtension for CheckMortality { const NAME: &'static str = "CheckMortality"; + type Decoded = Era; } /// The [`ChargeAssetTxPayment`] signed extension. -#[derive(Debug)] +#[derive(Debug, Encode, DecodeAsType)] pub struct ChargeAssetTxPayment { tip: Compact, asset_id: Option, @@ -271,16 +282,17 @@ impl ExtrinsicParams for ChargeAssetTxPayment { impl ExtrinsicParamsEncoder for ChargeAssetTxPayment { fn encode_extra_to(&self, v: &mut Vec) { - (self.tip, self.asset_id).encode_to(v); + self.encode_to(v); } } impl SignedExtension for ChargeAssetTxPayment { const NAME: &'static str = "ChargeAssetTxPayment"; + type Decoded = Self; } /// The [`ChargeTransactionPayment`] signed extension. -#[derive(Debug)] +#[derive(Debug, Encode, DecodeAsType)] pub struct ChargeTransactionPayment { tip: Compact, } @@ -319,12 +331,13 @@ impl ExtrinsicParams for ChargeTransactionPayment { impl ExtrinsicParamsEncoder for ChargeTransactionPayment { fn encode_extra_to(&self, v: &mut Vec) { - self.tip.encode_to(v); + self.encode_to(v); } } impl SignedExtension for ChargeTransactionPayment { const NAME: &'static str = "ChargeTransactionPayment"; + type Decoded = Self; } /// This accepts a tuple of [`SignedExtension`]s, and will dynamically make use of whichever diff --git a/subxt/src/utils/era.rs b/subxt/src/utils/era.rs index 63bede4432..6bea303de4 100644 --- a/subxt/src/utils/era.rs +++ b/subxt/src/utils/era.rs @@ -2,9 +2,13 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. +use scale_decode::DecodeAsType; + // Dev note: This and related bits taken from `sp_runtime::generic::Era` /// An era to describe the longevity of a transaction. -#[derive(PartialEq, Default, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] +#[derive( + PartialEq, Default, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize, DecodeAsType, +)] pub enum Era { /// The transaction is valid forever. The genesis hash must be present in the signed content. #[default] diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 52bebe2e59..ca431c00b8 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -6,6 +6,7 @@ use crate::{test_context, utils::node_runtime}; use codec::{Compact, Encode}; use futures::StreamExt; +use subxt::config::signed_extensions::{ChargeAssetTxPayment, CheckNonce}; use subxt::config::DefaultExtrinsicParamsBuilder; use subxt_metadata::Metadata; use subxt_signer::sr25519::dev; @@ -286,7 +287,9 @@ async fn decode_signed_extensions_from_blocks() { let transaction1 = submit_transfer_extrinsic_and_get_it_back!(1234); let extensions1 = transaction1.signed_extensions().unwrap(); let nonce1 = extensions1.nonce().unwrap(); + let nonce1_static = extensions1.find::().0; let tip1 = extensions1.tip().unwrap(); + let tip1_static: u128 = extensions1.find::().tip.0; let transaction2 = submit_transfer_extrinsic_and_get_it_back!(5678); let extensions2 = transaction2.signed_extensions().unwrap(); @@ -294,9 +297,13 @@ async fn decode_signed_extensions_from_blocks() { let tip2 = extensions2.tip().unwrap(); assert_eq!(nonce1, 0); + assert_eq!(nonce1, nonce1_static); assert_eq!(tip1, 1234); + assert_eq!(tip1, tip1_static); assert_eq!(nonce2, 1); + assert_eq!(nonce2, nonce2_static); assert_eq!(tip2, 5678); + assert_eq!(tip2, tip2_static); assert_eq!(extensions1.iter().count(), expected_signed_extensions.len()); for (e, expected_name) in extensions1.iter().zip(expected_signed_extensions.iter()) { From 26928824ce10187fa6ef970ddf3ff0e227c56c55 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 31 Oct 2023 11:09:32 +0100 Subject: [PATCH 15/27] fix merging bug and tests --- subxt/src/blocks/extrinsic_types.rs | 2 +- subxt/src/config/signed_extensions.rs | 9 ++++++--- testing/integration-tests/src/full_client/blocks/mod.rs | 6 ++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 9b2f7f732b..f4fa3170e1 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -738,7 +738,7 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { /// Signed Extension as a [`scale_value::Value`] pub fn value(&self) -> Result { - self.decoded()?.to_value() metadata: Metadata, + self.decoded()?.to_value() } /// Decodes the `extra` bytes of this Signed Extension into a static type. diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index 77a6a8d4a1..c5ab90d048 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -229,8 +229,10 @@ impl SignedExtension for CheckMortality { /// The [`ChargeAssetTxPayment`] signed extension. #[derive(Debug, Encode, DecodeAsType)] pub struct ChargeAssetTxPayment { - tip: Compact, - asset_id: Option, + /// Tip + pub tip: Compact, + /// Asset Id + pub asset_id: Option, } /// Parameters to configure the [`ChargeAssetTxPayment`] signed extension. @@ -294,7 +296,8 @@ impl SignedExtension for ChargeAssetTxPayment { /// The [`ChargeTransactionPayment`] signed extension. #[derive(Debug, Encode, DecodeAsType)] pub struct ChargeTransactionPayment { - tip: Compact, + /// Tip + pub tip: Compact, } /// Parameters to configure the [`ChargeTransactionPayment`] signed extension. diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 5315b97506..11b63855d1 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -287,14 +287,16 @@ async fn decode_signed_extensions_from_blocks() { let transaction1 = submit_transfer_extrinsic_and_get_it_back!(1234); let extensions1 = transaction1.signed_extensions().unwrap(); let nonce1 = extensions1.nonce().unwrap(); - let nonce1_static = extensions1.find::().0; + let nonce1_static = extensions1.find::().unwrap().unwrap().0; let tip1 = extensions1.tip().unwrap(); - let tip1_static: u128 = extensions1.find::().tip.0; + let tip1_static: u128 = extensions1.find::().unwrap().unwrap().tip.0; let transaction2 = submit_transfer_extrinsic_and_get_it_back!(5678); let extensions2 = transaction2.signed_extensions().unwrap(); let nonce2 = extensions2.nonce().unwrap(); + let nonce2_static = extensions2.find::().unwrap().unwrap().0; let tip2 = extensions2.tip().unwrap(); + let tip2_static: u128 = extensions2.find::().unwrap().unwrap().tip.0; assert_eq!(nonce1, 0); assert_eq!(nonce1, nonce1_static); From 0d52317528c4c28f01bc223b1f0434ad6da52570 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 31 Oct 2023 11:34:05 +0100 Subject: [PATCH 16/27] add decoded type in CustomSignedExtension --- subxt/examples/setup_config_signed_extension.rs | 1 + .../src/full_client/blocks/mod.rs | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/subxt/examples/setup_config_signed_extension.rs b/subxt/examples/setup_config_signed_extension.rs index 38e871bfa1..92274924c1 100644 --- a/subxt/examples/setup_config_signed_extension.rs +++ b/subxt/examples/setup_config_signed_extension.rs @@ -45,6 +45,7 @@ pub struct CustomSignedExtension; // up in the chain metadata in order to know when and if to use it. impl signed_extensions::SignedExtension for CustomSignedExtension { const NAME: &'static str = "CustomSignedExtension"; + type Decoded = (); } // Gather together any params we need for our signed extension, here none. diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 11b63855d1..3627c57deb 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -289,14 +289,24 @@ async fn decode_signed_extensions_from_blocks() { let nonce1 = extensions1.nonce().unwrap(); let nonce1_static = extensions1.find::().unwrap().unwrap().0; let tip1 = extensions1.tip().unwrap(); - let tip1_static: u128 = extensions1.find::().unwrap().unwrap().tip.0; + let tip1_static: u128 = extensions1 + .find::() + .unwrap() + .unwrap() + .tip + .0; let transaction2 = submit_transfer_extrinsic_and_get_it_back!(5678); let extensions2 = transaction2.signed_extensions().unwrap(); let nonce2 = extensions2.nonce().unwrap(); let nonce2_static = extensions2.find::().unwrap().unwrap().0; let tip2 = extensions2.tip().unwrap(); - let tip2_static: u128 = extensions2.find::().unwrap().unwrap().tip.0; + let tip2_static: u128 = extensions2 + .find::() + .unwrap() + .unwrap() + .tip + .0; assert_eq!(nonce1, 0); assert_eq!(nonce1, nonce1_static); From 7ff7552f88d75a788217c4157b3a1a05b2bb8751 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 31 Oct 2023 18:25:48 +0100 Subject: [PATCH 17/27] fix minor issues, extend test --- subxt/examples/blocks_subscribing.rs | 13 +----- subxt/src/blocks/extrinsic_types.rs | 19 ++++---- subxt/src/config/signed_extensions.rs | 36 ++++++++++----- .../src/full_client/blocks/mod.rs | 44 ++++++++++++------- 4 files changed, 64 insertions(+), 48 deletions(-) diff --git a/subxt/examples/blocks_subscribing.rs b/subxt/examples/blocks_subscribing.rs index 843e9b0132..c705ddf8d5 100644 --- a/subxt/examples/blocks_subscribing.rs +++ b/subxt/examples/blocks_subscribing.rs @@ -34,24 +34,13 @@ async fn main() -> Result<(), Box> { let decoded_ext = ext.as_root_extrinsic::(); println!(" Extrinsic #{idx}:"); - if let Some(signed_extensions) = ext.signed_extensions() { - println!(" Signed Extensions:"); - for signed_extension in signed_extensions.iter() { - let signed_extension = signed_extension?; - let name = signed_extension.name(); - let value = signed_extension.value()?.to_string(); - println!(" {name}: {value}"); - } - } else { - println!(" No Signed Extensions"); - } println!(" Bytes: {bytes_hex}"); println!(" Decoded: {decoded_ext:?}"); println!(" Events:"); for evt in events.iter() { let evt = evt?; - + let pallet_name = evt.pallet_name(); let event_name = evt.variant_name(); let event_values = evt.field_values()?; diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index f4fa3170e1..11683d54b7 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -374,7 +374,7 @@ where let extra_bytes = &self.bytes[signed.signature_end_idx..signed.extra_end_idx]; Some(ExtrinsicSignedExtensions { bytes: extra_bytes, - metadata: self.metadata.clone(), + metadata: &self.metadata, _marker: std::marker::PhantomData, }) } @@ -611,19 +611,20 @@ impl ExtrinsicEvents { #[derive(Debug, Clone)] pub struct ExtrinsicSignedExtensions<'a, T: Config> { bytes: &'a [u8], - metadata: Metadata, + metadata: &'a Metadata, _marker: std::marker::PhantomData, } impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { /// 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(&'a self) -> impl Iterator, Error>> { + pub fn iter(&self) -> impl Iterator, 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; std::iter::from_fn(move || { if index == num_signed_extensions { @@ -636,7 +637,7 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { if let Err(err) = scale_decode::visitor::decode_with_visitor( cursor, ty_id, - self.metadata.types(), + metadata.types(), scale_decode::visitor::IgnoreVisitor, ) .map_err(|e| Error::Decode(e.into())) @@ -652,16 +653,16 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { bytes, ty_id, identifier: extension.identifier(), - metadata: self.metadata.clone(), + metadata, _marker: std::marker::PhantomData, })) }) } - fn find_by_name(&self, name: impl AsRef) -> Option> { + fn find_by_name(&self, name: &str) -> Option> { let signed_extension = self .iter() - .find_map(|e| e.ok().filter(|e| e.name() == name.as_ref()))?; + .find_map(|e| e.ok().filter(|e| e.name() == name))?; Some(signed_extension) } @@ -706,7 +707,7 @@ pub struct ExtrinsicSignedExtension<'a, T: Config> { bytes: &'a [u8], ty_id: u32, identifier: &'a str, - metadata: Metadata, + metadata: &'a Metadata, _marker: std::marker::PhantomData, } @@ -731,7 +732,7 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( &mut &self.bytes[..], self.ty_id, - &self.metadata, + self.metadata, )?; Ok(decoded_value_thunk) } diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index c5ab90d048..29f01dd6d6 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -227,12 +227,22 @@ impl SignedExtension for CheckMortality { } /// The [`ChargeAssetTxPayment`] signed extension. -#[derive(Debug, Encode, DecodeAsType)] +#[derive(Debug, DecodeAsType)] pub struct ChargeAssetTxPayment { - /// Tip - pub tip: Compact, - /// Asset Id - pub asset_id: Option, + tip: Compact, + asset_id: Option, +} + +impl ChargeAssetTxPayment { + /// Tip to the extrinsic author in the native chain token. + pub fn tip(&self) -> u128 { + self.tip.0 + } + + /// Tip to the extrinsic author using the asset ID given. + pub fn asset_id(&self) -> Option { + self.asset_id + } } /// Parameters to configure the [`ChargeAssetTxPayment`] signed extension. @@ -284,7 +294,7 @@ impl ExtrinsicParams for ChargeAssetTxPayment { impl ExtrinsicParamsEncoder for ChargeAssetTxPayment { fn encode_extra_to(&self, v: &mut Vec) { - self.encode_to(v); + (self.tip, self.asset_id).encode_to(v); } } @@ -294,10 +304,16 @@ impl SignedExtension for ChargeAssetTxPayment { } /// The [`ChargeTransactionPayment`] signed extension. -#[derive(Debug, Encode, DecodeAsType)] +#[derive(Debug, DecodeAsType)] pub struct ChargeTransactionPayment { - /// Tip - pub tip: Compact, + tip: Compact, +} + +impl ChargeTransactionPayment { + /// Tip to the extrinsic author in the native chain token. + pub fn tip(&self) -> u128 { + self.tip.0 + } } /// Parameters to configure the [`ChargeTransactionPayment`] signed extension. @@ -334,7 +350,7 @@ impl ExtrinsicParams for ChargeTransactionPayment { impl ExtrinsicParamsEncoder for ChargeTransactionPayment { fn encode_extra_to(&self, v: &mut Vec) { - self.encode_to(v); + self.tip.encode_to(v); } } diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 3627c57deb..3330c01e72 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -5,9 +5,10 @@ use crate::{test_context, utils::node_runtime}; use codec::{Compact, Encode}; use futures::StreamExt; - -use subxt::config::signed_extensions::{ChargeAssetTxPayment, CheckNonce}; +use subxt::config::signed_extensions::{ChargeAssetTxPayment, CheckMortality, CheckNonce}; use subxt::config::DefaultExtrinsicParamsBuilder; +use subxt::config::SubstrateConfig; +use subxt::utils::Era; use subxt_metadata::Metadata; use subxt_signer::sr25519::dev; @@ -273,17 +274,6 @@ async fn decode_signed_extensions_from_blocks() { }}; } - let expected_signed_extensions = [ - "CheckNonZeroSender", - "CheckSpecVersion", - "CheckTxVersion", - "CheckGenesis", - "CheckMortality", - "CheckNonce", - "CheckWeight", - "ChargeAssetTxPayment", - ]; - let transaction1 = submit_transfer_extrinsic_and_get_it_back!(1234); let extensions1 = transaction1.signed_extensions().unwrap(); let nonce1 = extensions1.nonce().unwrap(); @@ -293,8 +283,7 @@ async fn decode_signed_extensions_from_blocks() { .find::() .unwrap() .unwrap() - .tip - .0; + .tip(); let transaction2 = submit_transfer_extrinsic_and_get_it_back!(5678); let extensions2 = transaction2.signed_extensions().unwrap(); @@ -305,8 +294,7 @@ async fn decode_signed_extensions_from_blocks() { .find::() .unwrap() .unwrap() - .tip - .0; + .tip(); assert_eq!(nonce1, 0); assert_eq!(nonce1, nonce1_static); @@ -316,12 +304,34 @@ async fn decode_signed_extensions_from_blocks() { assert_eq!(nonce2, nonce2_static); assert_eq!(tip2, 5678); assert_eq!(tip2, tip2_static); + + let expected_signed_extensions = [ + "CheckNonZeroSender", + "CheckSpecVersion", + "CheckTxVersion", + "CheckGenesis", + "CheckMortality", + "CheckNonce", + "CheckWeight", + "ChargeAssetTxPayment", + ]; + assert_eq!(extensions1.iter().count(), expected_signed_extensions.len()); for (e, expected_name) in extensions1.iter().zip(expected_signed_extensions.iter()) { assert_eq!(e.unwrap().name(), *expected_name); } + assert_eq!(extensions2.iter().count(), expected_signed_extensions.len()); for (e, expected_name) in extensions2.iter().zip(expected_signed_extensions.iter()) { assert_eq!(e.unwrap().name(), *expected_name); } + + // check that era decodes: + for extensions in [&extensions1, &extensions2] { + let era: Era = extensions + .find::>() + .unwrap() + .unwrap(); + assert_eq!(era, Era::Immortal) + } } From f200d0f0e9d94f7b6f5c9b5566c928f0d965e7f5 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 2 Nov 2023 10:34:55 +0100 Subject: [PATCH 18/27] cargo fmt differences --- subxt/examples/blocks_subscribing.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/subxt/examples/blocks_subscribing.rs b/subxt/examples/blocks_subscribing.rs index c705ddf8d5..109a81bf5f 100644 --- a/subxt/examples/blocks_subscribing.rs +++ b/subxt/examples/blocks_subscribing.rs @@ -40,7 +40,6 @@ async fn main() -> Result<(), Box> { for evt in events.iter() { let evt = evt?; - let pallet_name = evt.pallet_name(); let event_name = evt.variant_name(); let event_values = evt.field_values()?; From 5afe150e0391be43ac8af915858994beafcc1870 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 2 Nov 2023 18:19:59 +0100 Subject: [PATCH 19/27] remove the `decoded` function --- subxt/src/blocks/extrinsic_types.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 11683d54b7..e2907fc279 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -14,8 +14,7 @@ use crate::{ use crate::config::signed_extensions::{ChargeAssetTxPayment, ChargeTransactionPayment}; use crate::config::SignedExtension; -use crate::dynamic::{DecodedValue, DecodedValueThunk}; -use crate::metadata::DecodeWithMetadata; +use crate::dynamic::DecodedValue; use crate::utils::strip_compact_prefix; use codec::{Compact, Decode}; use derivative::Derivative; @@ -727,24 +726,15 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { self.ty_id } - /// DecodedValueThunk representing the type of the extra of this signed extension. - fn decoded(&self) -> Result { - let decoded_value_thunk = DecodedValueThunk::decode_with_metadata( - &mut &self.bytes[..], - self.ty_id, - self.metadata, - )?; - Ok(decoded_value_thunk) - } - /// Signed Extension as a [`scale_value::Value`] pub fn value(&self) -> Result { - self.decoded()?.to_value() + self.as_type() } /// Decodes the `extra` bytes of this Signed Extension into a static type. pub fn as_type(&self) -> Result { - self.decoded()?.as_type::().map_err(Into::into) + let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?; + Ok(value) } } From 42a0423a7ac9cf4393c1d245ff84d95ac7757063 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 2 Nov 2023 19:18:45 +0100 Subject: [PATCH 20/27] new as_signed_extra fn, do not expose as_type anymore --- subxt/src/blocks/extrinsic_types.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index e2907fc279..2295b6196a 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -669,7 +669,7 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { /// If the Signed Extension is found, but decoding failed, `Some(Err(err))` is returned. pub fn find>(&self) -> Option> { let signed_extension = self.find_by_name(S::NAME)?; - Some(signed_extension.as_type().map_err(Into::into)) + signed_extension.as_signed_extra::().transpose() } /// The tip of an extrinsic, extracted from the ChargeTransactionPayment or ChargeAssetTxPayment @@ -678,14 +678,13 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { /// Returns `None` if `tip` was not found or decoding failed. pub fn tip(&self) -> Option { // Note: the overhead of iterating twice should be negligible. - let tip = self - .find_by_name(>::NAME) - .or_else(|| self.find_by_name(>::NAME))?; - - // Note: ChargeAssetTxPayment might have addition information in it (asset_id). - // But both should start with a compact encoded u128, so this decoding is fine. - let tip = Compact::::decode(&mut tip.bytes()).ok()?.0; - Some(tip) + self.find::() + .map(|e| e.map(|e| e.tip())) + .or_else(|| { + self.find::() + .map(|e| e.map(|e| e.tip())) + })? + .ok() } /// The nonce of the account that submitted the extrinsic, extracted from the CheckNonce signed extension. @@ -732,10 +731,19 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> { } /// Decodes the `extra` bytes of this Signed Extension into a static type. - pub fn as_type(&self) -> Result { + fn as_type(&self) -> Result { let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?; Ok(value) } + + /// Decodes the `extra` bytes of this Signed Extension into its associated `Decoded` type. + /// Returns `Ok(None)` if the identitfier of this Signed Extension object does not line up with the `NAME` constant of the provided Signed Extension type. + pub fn as_signed_extra>(&self) -> Result, Error> { + if self.identifier != S::NAME { + return Ok(None); + } + self.as_type::().map(Some) + } } #[cfg(test)] From b7d94119e3f86ef5b6dbadf25469702768c5f245 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 3 Nov 2023 10:25:38 +0100 Subject: [PATCH 21/27] fix Result-Option order, simplify obtaining Nonce --- subxt/src/blocks/extrinsic_types.rs | 36 ++++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index 2295b6196a..f540cd7ec4 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -12,11 +12,13 @@ use crate::{ Metadata, }; -use crate::config::signed_extensions::{ChargeAssetTxPayment, ChargeTransactionPayment}; +use crate::config::signed_extensions::{ + ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce, +}; use crate::config::SignedExtension; use crate::dynamic::DecodedValue; use crate::utils::strip_compact_prefix; -use codec::{Compact, Decode}; +use codec::Decode; use derivative::Derivative; use scale_decode::{DecodeAsFields, DecodeAsType}; @@ -666,10 +668,16 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { } /// Searches through all signed extensions to find a specific one. - /// If the Signed Extension is found, but decoding failed, `Some(Err(err))` is returned. - pub fn find>(&self) -> Option> { - let signed_extension = self.find_by_name(S::NAME)?; - signed_extension.as_signed_extra::().transpose() + /// 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>(&self) -> Result, Error> { + self.find_by_name(S::NAME) + .map(|s| { + s.as_signed_extra::().map(|e| { + e.expect("signed extra name is correct, because it was found before; qed.") + }) + }) + .transpose() } /// The tip of an extrinsic, extracted from the ChargeTransactionPayment or ChargeAssetTxPayment @@ -679,22 +687,22 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { pub fn tip(&self) -> Option { // Note: the overhead of iterating twice should be negligible. self.find::() - .map(|e| e.map(|e| e.tip())) + .ok() + .flatten() + .map(|e| e.tip()) .or_else(|| { self.find::() - .map(|e| e.map(|e| e.tip())) - })? - .ok() + .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 { - let nonce = self - .iter() - .find_map(|e| e.ok().filter(|e| e.name() == "CheckNonce"))?; - let nonce = Compact::::decode(&mut nonce.bytes()).ok()?.0; + let nonce = self.find::().ok()??.0; Some(nonce) } } From 13e3f2d893f6d04a67755b900c135c6e241e7c54 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:50:00 +0200 Subject: [PATCH 22/27] tx: Remove `wait_for_in_block` helper method (#1237) Signed-off-by: Alexandru Vasile --- subxt/src/tx/tx_progress.rs | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/subxt/src/tx/tx_progress.rs b/subxt/src/tx/tx_progress.rs index 65164b1ffe..b949de2be4 100644 --- a/subxt/src/tx/tx_progress.rs +++ b/subxt/src/tx/tx_progress.rs @@ -71,37 +71,6 @@ where StreamExt::next(self).await } - /// Wait for the transaction to be in a block (but not necessarily finalized), and return - /// an [`TxInBlock`] instance when this happens, or an error if there was a problem - /// waiting for this to happen. - /// - /// **Note:** consumes `self`. If you'd like to perform multiple actions as the state of the - /// transaction progresses, use [`TxProgress::next()`] instead. - /// - /// **Note:** transaction statuses like `Invalid`/`Usurped`/`Dropped` indicate with some - /// probability that the transaction will not make it into a block but there is no guarantee - /// that this is true. In those cases the stream is closed however, so you currently have no way to find - /// out if they finally made it into a block or not. - pub async fn wait_for_in_block(mut self) -> Result, Error> { - while let Some(status) = self.next().await { - match status? { - // Finalized or otherwise in a block! Return. - TxStatus::InBestBlock(s) | TxStatus::InFinalizedBlock(s) => return Ok(s), - // Error scenarios; return the error. - TxStatus::Error { message } => return Err(TransactionError::Error(message).into()), - TxStatus::Invalid { message } => { - return Err(TransactionError::Invalid(message).into()) - } - TxStatus::Dropped { message } => { - return Err(TransactionError::Dropped(message).into()) - } - // Ignore anything else and wait for next status event: - _ => continue, - } - } - Err(RpcError::SubscriptionDropped.into()) - } - /// Wait for the transaction to be finalized, and return a [`TxInBlock`] /// instance when it is, or an error if there was a problem waiting for finalization. /// From 39f1a308d1f27e201bbf528a674390bcfe6931d5 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Fri, 3 Nov 2023 15:14:54 +0200 Subject: [PATCH 23/27] Update smoldot to 0.12 (#1212) * Update lightclient Signed-off-by: Alexandru Vasile * testing: Fix typo Signed-off-by: Alexandru Vasile * testing: Update cargo.toml Signed-off-by: Alexandru Vasile * lightclient: Add tracing logs to improve debugging Signed-off-by: Alexandru Vasile * lightclient: Add socket buffers module for `PlatformRef` Signed-off-by: Alexandru Vasile * lightclient: Update `SubxtPlatform` Signed-off-by: Alexandru Vasile * cargo: Add lightclient dependencies Signed-off-by: Alexandru Vasile * Update cargo.lock of wasm tests Signed-off-by: Alexandru Vasile * lightclient: Add constant for with-buffer module Signed-off-by: Alexandru Vasile * lightclient: Replace rand crate with getrandom Signed-off-by: Alexandru Vasile * example: Update cargo lock file Signed-off-by: Alexandru Vasile * examples: Update deps Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: Tadeo Hepperle <62739623+tadeohepperle@users.noreply.github.com> --- Cargo.lock | 266 +++---- Cargo.toml | 6 +- examples/parachain-example/Cargo.lock | 308 ++++---- lightclient/Cargo.toml | 2 + lightclient/src/background.rs | 10 + lightclient/src/platform/wasm_helpers.rs | 452 +++++++++--- lightclient/src/platform/wasm_platform.rs | 358 +++------ testing/wasm-lightclient-tests/Cargo.lock | 720 ++++++++----------- testing/wasm-lightclient-tests/tests/wasm.rs | 2 +- 9 files changed, 1067 insertions(+), 1057 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d2497a5eb..527f8f7273 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,41 +36,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "opaque-debug 0.3.0", -] - -[[package]] -name = "aes-gcm" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "ahash" version = "0.7.6" @@ -103,6 +68,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -339,10 +310,10 @@ dependencies = [ ] [[package]] -name = "atomic" -version = "0.5.3" +name = "atomic-take" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" +checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "atomic-waker" @@ -633,27 +604,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "zeroize", -] - -[[package]] -name = "chacha20poly1305" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", ] [[package]] @@ -697,11 +654,12 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array 0.14.7", + "crypto-common", + "inout", ] [[package]] @@ -898,7 +856,7 @@ dependencies = [ "ciborium", "clap 3.2.25", "criterion-plot", - "itertools", + "itertools 0.10.5", "lazy_static", "num-traits", "oorandom", @@ -919,7 +877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -1001,15 +959,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher", -] - [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -1045,6 +994,7 @@ dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", + "digest 0.10.7", "fiat-crypto", "platforms", "rustc_version", @@ -1244,7 +1194,16 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature 2.1.0", ] [[package]] @@ -1254,7 +1213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek 3.2.0", - "ed25519", + "ed25519 1.5.3", "sha2 0.9.9", "zeroize", ] @@ -1273,6 +1232,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519-zebra" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +dependencies = [ + "curve25519-dalek 4.1.1", + "ed25519 2.2.3", + "hashbrown 0.14.1", + "hex", + "rand_core 0.6.4", + "sha2 0.10.8", + "zeroize", +] + [[package]] name = "either" version = "1.9.0" @@ -1585,16 +1559,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "ghash" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" -dependencies = [ - "opaque-debug 0.3.0", - "polyval", -] - [[package]] name = "gimli" version = "0.27.3" @@ -1734,6 +1698,8 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" dependencies = [ + "ahash 0.8.3", + "allocator-api2", "serde", ] @@ -1988,6 +1954,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "instant" version = "0.1.12" @@ -2035,12 +2010,6 @@ dependencies = [ "wabt", ] -[[package]] -name = "intx" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" - [[package]] name = "io-lifetimes" version = "1.0.11" @@ -2061,6 +2030,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -2278,9 +2256,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" [[package]] name = "mach" @@ -2751,22 +2729,10 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" -dependencies = [ - "cpufeatures", - "opaque-debug 0.3.0", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cfg-if", "cpufeatures", "opaque-debug 0.3.0", "universal-hash", @@ -3593,6 +3559,12 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" + [[package]] name = "siphasher" version = "0.3.11" @@ -3633,29 +3605,30 @@ dependencies = [ [[package]] name = "smoldot" -version = "0.8.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cce5e2881b30bad7ef89f383a816ad0b22c45915911f28499026de4a76d20ee" +checksum = "4388a7690d9f76320dedc7f97f213160fbe4fb4a38a8b4cc8bb96e0fd05e0971" dependencies = [ "arrayvec 0.7.4", "async-lock", - "atomic", + "atomic-take", "base64 0.21.4", "bip39", "blake2-rfc", "bs58 0.5.0", + "chacha20", "crossbeam-queue", "derive_more", - "ed25519-zebra", + "ed25519-zebra 4.0.3", "either", "event-listener", "fnv", - "futures-channel", + "futures-lite", "futures-util", "hashbrown 0.14.1", "hex", "hmac 0.12.1", - "itertools", + "itertools 0.11.0", "libsecp256k1", "merlin 3.0.0", "no-std-net", @@ -3665,6 +3638,7 @@ dependencies = [ "num-traits", "pbkdf2 0.12.2", "pin-project", + "poly1305", "rand 0.8.5", "rand_chacha 0.3.1", "ruzstd", @@ -3672,60 +3646,51 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", + "sha3", "siphasher", "slab", "smallvec", - "smol", - "snow", "soketto", - "tiny-keccak", "twox-hash", "wasmi", + "x25519-dalek", + "zeroize", ] [[package]] name = "smoldot-light" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2f7b4687b83ff244ef6137735ed5716ad37dcdf3ee16c4eb1a32fb9808fa47" +checksum = "bea3d21923cbdb1362205ff8b2adb5da67e6b81b34c4bba1baaef9b88cbd83b8" dependencies = [ + "async-channel", "async-lock", + "base64 0.21.4", "blake2-rfc", "derive_more", "either", "event-listener", "fnv", "futures-channel", + "futures-lite", "futures-util", "hashbrown 0.14.1", "hex", - "itertools", + "itertools 0.11.0", "log", "lru", + "no-std-net", "parking_lot", + "pin-project", "rand 0.8.5", + "rand_chacha 0.3.1", "serde", "serde_json", "siphasher", "slab", "smol", "smoldot", -] - -[[package]] -name = "snow" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155" -dependencies = [ - "aes-gcm", - "blake2", - "chacha20poly1305", - "curve25519-dalek 4.1.1", - "rand_core 0.6.4", - "rustc_version", - "sha2 0.10.8", - "subtle", + "zeroize", ] [[package]] @@ -3804,7 +3769,7 @@ dependencies = [ "bounded-collections", "bs58 0.4.0", "dyn-clonable", - "ed25519-zebra", + "ed25519-zebra 3.1.0", "futures", "hash-db", "hash256-std-hasher", @@ -3882,7 +3847,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d597e35a9628fe7454b08965b2442e3ec0f264b0a90d41328e87422cec02e99" dependencies = [ "bytes", - "ed25519", + "ed25519 1.5.3", "ed25519-dalek", "futures", "libsecp256k1", @@ -4292,6 +4257,7 @@ dependencies = [ "getrandom 0.2.10", "instant", "js-sys", + "pin-project", "send_wrapper 0.6.0", "serde", "serde_json", @@ -4488,15 +4454,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -4846,11 +4803,11 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array 0.14.7", + "crypto-common", "subtle", ] @@ -5017,11 +4974,10 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasmi" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51fb5c61993e71158abf5bb863df2674ca3ec39ed6471c64f07aeaf751d67b4" +checksum = "1f341edb80021141d4ae6468cbeefc50798716a347d4085c3811900049ea8945" dependencies = [ - "intx", "smallvec", "spin 0.9.8", "wasmi_arena", @@ -5037,9 +4993,9 @@ checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" [[package]] name = "wasmi_core" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" +checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" dependencies = [ "downcast-rs", "libm", @@ -5410,6 +5366,18 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +dependencies = [ + "curve25519-dalek 4.1.1", + "rand_core 0.6.4", + "serde", + "zeroize", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index a7a37de90b..608abfafb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,10 +82,12 @@ wasm-bindgen-test = "0.3.24" which = "4.4.2" # Light client support: -smoldot = { version = "0.8.0", default-features = false } -smoldot-light = { version = "0.6.0", default-features = false } +smoldot = { version = "0.12.0", default-features = false } +smoldot-light = { version = "0.10.0", default-features = false } tokio-stream = "0.1.14" futures-util = "0.3.28" +rand = "0.8.5" +pin-project = "1.1.3" # Light client wasm: web-sys = { version = "0.3.61", features = ["BinaryType", "CloseEvent", "MessageEvent", "WebSocket"] } diff --git a/examples/parachain-example/Cargo.lock b/examples/parachain-example/Cargo.lock index 8cde25b366..e7d3678c4b 100644 --- a/examples/parachain-example/Cargo.lock +++ b/examples/parachain-example/Cargo.lock @@ -27,41 +27,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "opaque-debug 0.3.0", -] - -[[package]] -name = "aes-gcm" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "ahash" version = "0.7.6" @@ -94,6 +59,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -271,10 +242,10 @@ dependencies = [ ] [[package]] -name = "atomic" -version = "0.5.3" +name = "atomic-take" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" +checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "atomic-waker" @@ -532,27 +503,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "zeroize", -] - -[[package]] -name = "chacha20poly1305" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", ] [[package]] @@ -569,11 +526,12 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array 0.14.7", + "crypto-common", + "inout", ] [[package]] @@ -710,15 +668,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher", -] - [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -747,18 +696,32 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.1" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", "fiat-crypto", - "packed_simd_2", "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "curve25519-dalek-ng" version = "4.1.1" @@ -934,7 +897,16 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature 2.1.0", ] [[package]] @@ -944,7 +916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek 3.2.0", - "ed25519", + "ed25519 1.5.3", "sha2 0.9.9", "zeroize", ] @@ -963,6 +935,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519-zebra" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +dependencies = [ + "curve25519-dalek 4.1.1", + "ed25519 2.2.3", + "hashbrown 0.14.0", + "hex", + "rand_core 0.6.4", + "sha2 0.10.7", + "zeroize", +] + [[package]] name = "either" version = "1.9.0" @@ -1031,9 +1018,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.1.20" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" [[package]] name = "fixed-hash" @@ -1243,16 +1230,6 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] -[[package]] -name = "ghash" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" -dependencies = [ - "opaque-debug 0.3.0", - "polyval", -] - [[package]] name = "gimli" version = "0.27.3" @@ -1322,6 +1299,8 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ + "ahash 0.8.3", + "allocator-api2", "serde", ] @@ -1561,6 +1540,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "instant" version = "0.1.12" @@ -1579,12 +1567,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "intx" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" - [[package]] name = "io-lifetimes" version = "1.0.11" @@ -1598,9 +1580,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -1729,12 +1711,6 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" -[[package]] -name = "libm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" - [[package]] name = "libm" version = "0.2.7" @@ -1819,9 +1795,9 @@ checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "lru" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" [[package]] name = "mach" @@ -2050,16 +2026,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm 0.1.4", -] - [[package]] name = "parachain-example" version = "0.1.0" @@ -2172,18 +2138,18 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", @@ -2226,27 +2192,15 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", "universal-hash", ] -[[package]] -name = "polyval" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug 0.3.0", - "universal-hash", -] - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -3084,6 +3038,12 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" + [[package]] name = "siphasher" version = "0.3.10" @@ -3101,9 +3061,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smol" @@ -3124,24 +3084,25 @@ dependencies = [ [[package]] name = "smoldot" -version = "0.8.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cce5e2881b30bad7ef89f383a816ad0b22c45915911f28499026de4a76d20ee" +checksum = "4388a7690d9f76320dedc7f97f213160fbe4fb4a38a8b4cc8bb96e0fd05e0971" dependencies = [ "arrayvec 0.7.4", "async-lock", - "atomic", + "atomic-take", "base64 0.21.2", "bip39", "blake2-rfc", "bs58 0.5.0", + "chacha20", "crossbeam-queue", "derive_more", - "ed25519-zebra", + "ed25519-zebra 4.0.3", "either", "event-listener", "fnv", - "futures-channel", + "futures-lite", "futures-util", "hashbrown 0.14.0", "hex", @@ -3156,6 +3117,7 @@ dependencies = [ "num-traits", "pbkdf2 0.12.2", "pin-project", + "poly1305", "rand 0.8.5", "rand_chacha 0.3.1", "ruzstd", @@ -3163,60 +3125,51 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.7", + "sha3", "siphasher", "slab", "smallvec", - "smol", - "snow", "soketto", - "tiny-keccak", "twox-hash", "wasmi", + "x25519-dalek", + "zeroize", ] [[package]] name = "smoldot-light" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2f7b4687b83ff244ef6137735ed5716ad37dcdf3ee16c4eb1a32fb9808fa47" +checksum = "bea3d21923cbdb1362205ff8b2adb5da67e6b81b34c4bba1baaef9b88cbd83b8" dependencies = [ + "async-channel", "async-lock", + "base64 0.21.2", "blake2-rfc", "derive_more", "either", "event-listener", "fnv", "futures-channel", + "futures-lite", "futures-util", "hashbrown 0.14.0", "hex", "itertools", "log", "lru", + "no-std-net", "parking_lot", + "pin-project", "rand 0.8.5", + "rand_chacha 0.3.1", "serde", "serde_json", "siphasher", "slab", "smol", "smoldot", -] - -[[package]] -name = "snow" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" -dependencies = [ - "aes-gcm", - "blake2", - "chacha20poly1305", - "curve25519-dalek 4.0.0-rc.1", - "rand_core 0.6.4", - "rustc_version", - "sha2 0.10.7", - "subtle", + "zeroize", ] [[package]] @@ -3295,7 +3248,7 @@ dependencies = [ "bounded-collections", "bs58 0.4.0", "dyn-clonable", - "ed25519-zebra", + "ed25519-zebra 3.1.0", "futures", "hash-db", "hash256-std-hasher", @@ -3373,7 +3326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d597e35a9628fe7454b08965b2442e3ec0f264b0a90d41328e87422cec02e99" dependencies = [ "bytes", - "ed25519", + "ed25519 1.5.3", "ed25519-dalek", "futures", "libsecp256k1", @@ -3720,6 +3673,7 @@ name = "subxt-macro" version = "0.32.1" dependencies = [ "darling 0.20.3", + "parity-scale-codec", "proc-macro-error", "subxt-codegen", "syn 2.0.38", @@ -3859,15 +3813,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -4103,7 +4048,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] @@ -4154,11 +4099,11 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array 0.14.7", + "crypto-common", "subtle", ] @@ -4280,11 +4225,10 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasmi" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51fb5c61993e71158abf5bb863df2674ca3ec39ed6471c64f07aeaf751d67b4" +checksum = "1f341edb80021141d4ae6468cbeefc50798716a347d4085c3811900049ea8945" dependencies = [ - "intx", "smallvec", "spin 0.9.8", "wasmi_arena", @@ -4300,12 +4244,12 @@ checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" [[package]] name = "wasmi_core" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" +checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" dependencies = [ "downcast-rs", - "libm 0.2.7", + "libm", "num-traits", "paste", ] @@ -4667,6 +4611,18 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +dependencies = [ + "curve25519-dalek 4.1.1", + "rand_core 0.6.4", + "serde", + "zeroize", +] + [[package]] name = "yap" version = "0.11.0" diff --git a/lightclient/Cargo.toml b/lightclient/Cargo.toml index f27832048a..8242c64262 100644 --- a/lightclient/Cargo.toml +++ b/lightclient/Cargo.toml @@ -42,6 +42,7 @@ web = [ "wasm-bindgen-futures", "futures-timer/wasm-bindgen", "instant/wasm-bindgen", + "pin-project", # For websocket. "js-sys", @@ -72,6 +73,7 @@ wasm-bindgen-futures = { workspace = true, optional = true } futures-timer = { workspace = true, optional = true } instant = { workspace = true, optional = true } tokio-util = { workspace = true, optional = true } +pin-project = { workspace = true, optional = true } # Included if "web" feature is enabled, to enable its js feature. getrandom = { workspace = true, optional = true } diff --git a/lightclient/src/background.rs b/lightclient/src/background.rs index 7dc88788d2..c6ecf935bd 100644 --- a/lightclient/src/background.rs +++ b/lightclient/src/background.rs @@ -114,6 +114,8 @@ impl BackgroundTask { self.requests.insert(id, sender); + tracing::trace!(target: LOG_TARGET, "Generated unique id={id} for request={request}"); + let result = self.client.json_rpc_request(request, self.chain_id); if let Err(err) = result { tracing::warn!( @@ -136,6 +138,8 @@ impl BackgroundTask { "Cannot send RPC request error to id={id}", ); } + } else { + tracing::trace!(target: LOG_TARGET, "Submitted to smoldot request with id={id}"); } } FromSubxt::Subscription { @@ -154,6 +158,8 @@ impl BackgroundTask { self.id_to_subscription.insert(id, (sub_id, sender)); + tracing::trace!(target: LOG_TARGET, "Generated unique id={id} for subscription request={request}"); + let result = self.client.json_rpc_request(request, self.chain_id); if let Err(err) = result { tracing::warn!( @@ -176,6 +182,8 @@ impl BackgroundTask { "Cannot send RPC request error to id={id}", ); } + } else { + tracing::trace!(target: LOG_TARGET, "Submitted to smoldot subscription request with id={id}"); } } }; @@ -183,6 +191,8 @@ impl BackgroundTask { /// Parse the response received from the light client and sent it to the appropriate user. fn handle_rpc_response(&mut self, response: String) { + tracing::trace!(target: LOG_TARGET, "Received from smoldot response={:?}", response); + match RpcResponse::from_str(&response) { Ok(RpcResponse::Error { id, error }) => { let Ok(id) = id.parse::() else { diff --git a/lightclient/src/platform/wasm_helpers.rs b/lightclient/src/platform/wasm_helpers.rs index 0bef476249..3ccbe160b6 100644 --- a/lightclient/src/platform/wasm_helpers.rs +++ b/lightclient/src/platform/wasm_helpers.rs @@ -5,20 +5,10 @@ //! Wasm implementation for the light client's platform using //! custom websockets. -use core::time::Duration; -use futures_util::{future, FutureExt}; -use smoldot::libp2p::multiaddr::ProtocolRef; -use smoldot_light::platform::{ConnectError, PlatformConnection}; -use std::{ - collections::VecDeque, - net::{IpAddr, SocketAddr}, -}; - use super::wasm_socket::WasmSocket; -pub fn spawn(task: future::BoxFuture<'static, ()>) { - wasm_bindgen_futures::spawn_local(task); -} +use core::time::Duration; +use futures_util::{future, FutureExt}; pub fn now_from_unix_epoch() -> Duration { instant::SystemTime::now() @@ -40,87 +30,381 @@ pub fn sleep(duration: Duration) -> Delay { futures_timer::Delay::new(duration).boxed() } -pub struct Stream { - pub socket: WasmSocket, - /// Read and write buffers of the connection, or `None` if the socket has been reset. - pub buffers: Option<(StreamReadBuffer, StreamWriteBuffer)>, -} +/// Implementation detail of a stream from the `SubxtPlatform`. +#[pin_project::pin_project] +pub struct Stream(#[pin] pub with_buffers::WithBuffers); -pub enum StreamReadBuffer { - Open { - buffer: Vec, - cursor: std::ops::Range, - }, - Closed, -} +pub mod with_buffers { + use smoldot::libp2p::read_write; -pub enum StreamWriteBuffer { - Open { - buffer: VecDeque, - must_flush: bool, - must_close: bool, - }, - Closed, -} + use core::{ + fmt, future, mem, ops, + pin::{self, Pin}, + task::Poll, + }; + + use crate::platform::wasm_helpers::Instant; + use futures_util::{AsyncRead, AsyncWrite}; + use std::io; + /// Holds an implementation of `AsyncRead` and `AsyncWrite`, alongside with a read buffer and a + /// write buffer. + #[pin_project::pin_project] + pub struct WithBuffers { + /// Actual socket to read from/write to. + #[pin] + socket: T, + /// Error that has happened on the socket, if any. + error: Option, + /// Storage for data read from the socket. The first [`WithBuffers::read_buffer_valid`] bytes + /// contain actual socket data, while the rest contains garbage data. + /// The capacity of this buffer is at least equal to the amount of bytes requested by the + /// inner data consumer. + read_buffer: Vec, + /// Number of bytes of data in [`WithBuffers::read_buffer`] that contain actual data. + read_buffer_valid: usize, + read_buffer_reasonable_capacity: usize, + /// True if reading from the socket has returned `Ok(0)` earlier, in other words "end of + /// file". + read_closed: bool, + /// Storage for data to write to the socket. + write_buffers: Vec>, + /// True if the consumer has closed the writing side earlier. + write_closed: bool, + /// True if the consumer has closed the writing side earlier, and the socket still has to + /// be closed. + close_pending: bool, + /// True if data has been written on the socket and the socket needs to be flushed. + flush_pending: bool, + + /// Value of [`read_write::ReadWrite::now`] that was fed by the latest call to + /// [`WithBuffers::read_write_access`]. + read_write_now: Option, + /// Value of [`read_write::ReadWrite::wake_up_after`] produced by the latest call + /// to [`WithBuffers::read_write_access`]. + read_write_wake_up_after: Option, + } + + const BUFFER_CAPACITY: usize = 65536; + const WRITE_BYTES_QUEUEABLE: usize = 128 * 1024; -pub async fn connect<'a>( - proto1: ProtocolRef<'a>, - proto2: ProtocolRef<'a>, - proto3: Option>, -) -> Result, ConnectError> { - // Ensure ahead of time that the multiaddress is supported. - let addr = match (&proto1, &proto2, &proto3) { - (ProtocolRef::Ip4(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V4((*ip).into()), *port); - format!("ws://{}", addr.to_string()) + impl WithBuffers { + /// Initializes a new [`WithBuffers`] with the given socket. + /// + /// The socket must still be open in both directions. + pub fn new(socket: T) -> Self { + WithBuffers { + socket, + error: None, + read_buffer: Vec::with_capacity(BUFFER_CAPACITY), + read_buffer_valid: 0, + read_buffer_reasonable_capacity: BUFFER_CAPACITY, + read_closed: false, + write_buffers: Vec::with_capacity(64), + write_closed: false, + close_pending: false, + flush_pending: false, + read_write_now: None, + read_write_wake_up_after: None, + } } - (ProtocolRef::Ip6(ip), ProtocolRef::Tcp(port), Some(ProtocolRef::Ws)) => { - let addr = SocketAddr::new(IpAddr::V6((*ip).into()), *port); - format!("ws://{}", addr.to_string()) + + /// Returns an object that implements `Deref`. This object can be used + /// to push or pull data to/from the socket. + /// + /// > **Note**: The parameter requires `Self` to be pinned for consistency with + /// > [`WithBuffers::wait_read_write_again`]. + pub fn read_write_access( + self: Pin<&mut Self>, + now: Instant, + ) -> Result { + let this = self.project(); + + debug_assert!(this + .read_write_now + .as_ref() + .map_or(true, |old_now| *old_now <= now)); + *this.read_write_wake_up_after = None; + *this.read_write_now = Some(now); + + if let Some(error) = this.error.as_ref() { + return Err(error); + } + + this.read_buffer.truncate(*this.read_buffer_valid); + + let write_bytes_queued = this.write_buffers.iter().map(Vec::len).sum(); + + Ok(ReadWriteAccess { + read_buffer_len_before: this.read_buffer.len(), + write_buffers_len_before: this.write_buffers.len(), + read_write: read_write::ReadWrite { + now, + incoming_buffer: mem::take(this.read_buffer), + expected_incoming_bytes: if !*this.read_closed { Some(0) } else { None }, + read_bytes: 0, + write_bytes_queued, + write_buffers: mem::take(this.write_buffers), + write_bytes_queueable: if !*this.write_closed { + // Limit outgoing buffer size to 128kiB. + Some(WRITE_BYTES_QUEUEABLE.saturating_sub(write_bytes_queued)) + } else { + None + }, + wake_up_after: this.read_write_wake_up_after.take(), + }, + read_buffer: this.read_buffer, + read_buffer_valid: this.read_buffer_valid, + read_buffer_reasonable_capacity: *this.read_buffer_reasonable_capacity, + write_buffers: this.write_buffers, + write_closed: this.write_closed, + close_pending: this.close_pending, + read_write_wake_up_after: this.read_write_wake_up_after, + }) + } + } + + impl WithBuffers + where + T: AsyncRead + AsyncWrite, + { + /// Waits until [`WithBuffers::read_write_access`] should be called again. + /// + /// Returns if an error happens on the socket. If an error happened in the past on the socket, + /// the future never yields. + pub async fn wait_read_write_again( + self: Pin<&mut Self>, + timer_builder: impl FnOnce(Instant) -> F, + ) where + F: future::Future, + { + let mut this = self.project(); + + // Return immediately if `wake_up_after <= now`. + match (&*this.read_write_wake_up_after, &*this.read_write_now) { + (Some(when_wake_up), Some(now)) if *when_wake_up <= *now => { + return; + } + _ => {} + } + + let mut timer = pin::pin!({ + let fut = this + .read_write_wake_up_after + .as_ref() + .map(|when| timer_builder(*when)); + async { + if let Some(fut) = fut { + fut.await; + } else { + future::pending::<()>().await; + } + } + }); + + // Grow the read buffer in order to make space for potentially more data. + this.read_buffer.resize(this.read_buffer.capacity(), 0); + + future::poll_fn(move |cx| { + if this.error.is_some() { + // Never return. + return Poll::Pending; + } + + // If still `true` at the end of the function, `Poll::Pending` is returned. + let mut pending = true; + + match future::Future::poll(Pin::new(&mut timer), cx) { + Poll::Pending => {} + Poll::Ready(()) => { + pending = false; + } + } + + if !*this.read_closed { + let read_result = AsyncRead::poll_read( + this.socket.as_mut(), + cx, + &mut this.read_buffer[*this.read_buffer_valid..], + ); + + match read_result { + Poll::Pending => {} + Poll::Ready(Ok(0)) => { + *this.read_closed = true; + pending = false; + } + Poll::Ready(Ok(n)) => { + *this.read_buffer_valid += n; + // TODO: consider waking up only if the expected bytes of the consumer are exceeded + pending = false; + } + Poll::Ready(Err(err)) => { + *this.error = Some(err); + return Poll::Ready(()); + } + }; + } + + loop { + if this.write_buffers.iter().any(|b| !b.is_empty()) { + let write_result = { + let buffers = this + .write_buffers + .iter() + .map(|buf| io::IoSlice::new(buf)) + .collect::>(); + AsyncWrite::poll_write_vectored(this.socket.as_mut(), cx, &buffers) + }; + + match write_result { + Poll::Ready(Ok(0)) => { + // It is not legal for `poll_write` to return 0 bytes written. + unreachable!(); + } + Poll::Ready(Ok(mut n)) => { + *this.flush_pending = true; + while n > 0 { + let first_buf = this.write_buffers.first_mut().unwrap(); + if first_buf.len() <= n { + n -= first_buf.len(); + this.write_buffers.remove(0); + } else { + // TODO: consider keeping the buffer as is but starting the next write at a later offset + first_buf.copy_within(n.., 0); + first_buf.truncate(first_buf.len() - n); + break; + } + } + // Wake up if the write buffers switch from non-empty to empty. + if this.write_buffers.is_empty() { + pending = false; + } + } + Poll::Ready(Err(err)) => { + *this.error = Some(err); + return Poll::Ready(()); + } + Poll::Pending => break, + }; + } else if *this.flush_pending { + match AsyncWrite::poll_flush(this.socket.as_mut(), cx) { + Poll::Ready(Ok(())) => { + *this.flush_pending = false; + } + Poll::Ready(Err(err)) => { + *this.error = Some(err); + return Poll::Ready(()); + } + Poll::Pending => break, + } + } else if *this.close_pending { + match AsyncWrite::poll_close(this.socket.as_mut(), cx) { + Poll::Ready(Ok(())) => { + *this.close_pending = false; + pending = false; + break; + } + Poll::Ready(Err(err)) => { + *this.error = Some(err); + return Poll::Ready(()); + } + Poll::Pending => break, + } + } else { + break; + } + } + + if !pending { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; } - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - Some(ProtocolRef::Ws), - ) => { - format!("ws://{}:{}", addr.to_string(), port) + } + + impl fmt::Debug for WithBuffers { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("WithBuffers").field(&self.socket).finish() } - ( - ProtocolRef::Dns(addr) | ProtocolRef::Dns4(addr) | ProtocolRef::Dns6(addr), - ProtocolRef::Tcp(port), - Some(ProtocolRef::Wss), - ) => { - format!("wss://{}:{}", addr.to_string(), port) + } + + /// See [`WithBuffers::read_write_access`]. + pub struct ReadWriteAccess<'a> { + read_write: read_write::ReadWrite, + + read_buffer_len_before: usize, + write_buffers_len_before: usize, + + // Fields below as references from the content of the `WithBuffers`. + read_buffer: &'a mut Vec, + read_buffer_valid: &'a mut usize, + read_buffer_reasonable_capacity: usize, + write_buffers: &'a mut Vec>, + write_closed: &'a mut bool, + close_pending: &'a mut bool, + read_write_wake_up_after: &'a mut Option, + } + + impl<'a> ops::Deref for ReadWriteAccess<'a> { + type Target = read_write::ReadWrite; + + fn deref(&self) -> &Self::Target { + &self.read_write } - _ => { - return Err(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - }) + } + + impl<'a> ops::DerefMut for ReadWriteAccess<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.read_write } - }; + } - tracing::debug!("Connecting to addr={addr}"); + impl<'a> Drop for ReadWriteAccess<'a> { + fn drop(&mut self) { + *self.read_buffer = mem::take(&mut self.read_write.incoming_buffer); + *self.read_buffer_valid = self.read_buffer.len(); - let socket = WasmSocket::new(addr.as_str()).map_err(|err| ConnectError { - is_bad_addr: false, - message: format!("Failed to reach peer: {err}"), - })?; + // Adjust `read_buffer` to the number of bytes requested by the consumer. + if let Some(expected_incoming_bytes) = self.read_write.expected_incoming_bytes { + if expected_incoming_bytes < self.read_buffer_reasonable_capacity + && self.read_buffer.is_empty() + { + // We use `shrink_to(0)` then `reserve(cap)` rather than just `shrink_to(cap)` + // so that the `Vec` doesn't try to preserve the data in the read buffer. + self.read_buffer.shrink_to(0); + self.read_buffer + .reserve(self.read_buffer_reasonable_capacity); + } else if expected_incoming_bytes > self.read_buffer.len() { + self.read_buffer + .reserve(expected_incoming_bytes - self.read_buffer.len()); + } + debug_assert!(self.read_buffer.capacity() >= expected_incoming_bytes); + } - Ok(PlatformConnection::SingleStreamMultistreamSelectNoiseYamux( - Stream { - socket, - buffers: Some(( - StreamReadBuffer::Open { - buffer: vec![0; 16384], - cursor: 0..0, - }, - StreamWriteBuffer::Open { - buffer: VecDeque::with_capacity(16384), - must_close: false, - must_flush: false, - }, - )), - }, - )) + *self.write_buffers = mem::take(&mut self.read_write.write_buffers); + + if self.read_write.write_bytes_queueable.is_none() && !*self.write_closed { + *self.write_closed = true; + *self.close_pending = true; + } + + *self.read_write_wake_up_after = self.read_write.wake_up_after.take(); + + // If the consumer has advanced its reading or writing sides, we make the next call to + // `read_write_access` return immediately by setting `wake_up_after`. + if (self.read_buffer_len_before != self.read_buffer.len() + && self + .read_write + .expected_incoming_bytes + .map_or(false, |b| b <= self.read_buffer.len())) + || (self.write_buffers_len_before != self.write_buffers.len() + && !*self.write_closed) + { + *self.read_write_wake_up_after = Some(self.read_write.now); + } + } + } } diff --git a/lightclient/src/platform/wasm_platform.rs b/lightclient/src/platform/wasm_platform.rs index 9494d57fe6..306319034f 100644 --- a/lightclient/src/platform/wasm_platform.rs +++ b/lightclient/src/platform/wasm_platform.rs @@ -2,21 +2,22 @@ // This file is dual-licensed as Apache-2.0 or GPL-3.0. // see LICENSE for license details. -use core::time::Duration; -use futures::{prelude::*, task::Poll}; +use super::wasm_socket::WasmSocket; -use smoldot::libp2p::multiaddr::Multiaddr; +use core::time::Duration; +use futures::prelude::*; use smoldot_light::platform::{ - ConnectError, PlatformConnection, PlatformRef, PlatformSubstreamDirection, ReadBuffer, + Address, ConnectError, ConnectionType, IpAddr, MultiStreamAddress, MultiStreamWebRtcConnection, + PlatformRef, SubstreamDirection, }; -use std::{io::IoSlice, pin::Pin}; +use std::{io, net::SocketAddr, pin::Pin}; -use super::wasm_helpers::{StreamReadBuffer, StreamWriteBuffer}; +const LOG_TARGET: &str = "subxt-platform-wasm"; -/// Subxt plaform implementation for wasm. +/// Subxt platform implementation for wasm. /// /// This implementation is a conversion of the implementation from the smoldot: -/// https://github.com/smol-dot/smoldot/blob/f49ce4ea6a325c444ab6ad37d3ab5558edf0d541/light-base/src/platform/default.rs#L52. +/// https://github.com/smol-dot/smoldot/blob/6401d4df90569e23073d646b14a8fbf9f7e6bdd3/light-base/src/platform/default.rs#L83. /// /// This platform will evolve over time and we'll need to keep this code in sync. #[derive(Clone)] @@ -30,17 +31,18 @@ impl SubxtPlatform { impl PlatformRef for SubxtPlatform { type Delay = super::wasm_helpers::Delay; - type Yield = future::Ready<()>; type Instant = super::wasm_helpers::Instant; - type Connection = std::convert::Infallible; + type MultiStream = std::convert::Infallible; type Stream = super::wasm_helpers::Stream; - type ConnectFuture = future::BoxFuture< + type StreamConnectFuture = future::BoxFuture<'static, Result>; + type MultiStreamConnectFuture = future::BoxFuture< 'static, - Result, ConnectError>, + Result, ConnectError>, >; + type ReadWriteAccess<'a> = super::wasm_helpers::with_buffers::ReadWriteAccess<'a>; type StreamUpdateFuture<'a> = future::BoxFuture<'a, ()>; - type NextSubstreamFuture<'a> = - future::Pending>; + type StreamErrorRef<'a> = &'a std::io::Error; + type NextSubstreamFuture<'a> = future::Pending>; fn now_from_unix_epoch(&self) -> Duration { super::wasm_helpers::now_from_unix_epoch() @@ -50,6 +52,13 @@ impl PlatformRef for SubxtPlatform { super::wasm_helpers::now() } + fn fill_random_bytes(&self, buffer: &mut [u8]) { + // This could fail if the system does not have access to a good source of entropy. + // Note: `rand::RngCore::fill_bytes` also panics on errors and `rand::OsCore` calls + // identically into `getrandom::getrandom`. + getrandom::getrandom(buffer).expect("Cannot fill random bytes"); + } + fn sleep(&self, duration: Duration) -> Self::Delay { super::wasm_helpers::sleep(duration) } @@ -58,258 +67,127 @@ impl PlatformRef for SubxtPlatform { self.sleep(when.saturating_duration_since(self.now())) } - fn yield_after_cpu_intensive(&self) -> Self::Yield { - // No-op. - future::ready(()) + fn spawn_task( + &self, + _task_name: std::borrow::Cow, + task: impl future::Future + Send + 'static, + ) { + wasm_bindgen_futures::spawn_local(task); } - fn connect(&self, multiaddr: &str) -> Self::ConnectFuture { - // We simply copy the address to own it. We could be more zero-cost here, but doing so - // would considerably complicate the implementation. - let multiaddr = multiaddr.to_owned(); - - tracing::debug!("Connecting to multiaddress={:?}", multiaddr); - - Box::pin(async move { - let addr = multiaddr.parse::().map_err(|_| ConnectError { - is_bad_addr: true, - message: "Failed to parse address".to_string(), - })?; - - let mut iter = addr.iter().fuse(); - let proto1 = iter.next().ok_or(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - })?; - let proto2 = iter.next().ok_or(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - })?; - let proto3 = iter.next(); - - if iter.next().is_some() { - return Err(ConnectError { - is_bad_addr: true, - message: "Unknown protocols combination".to_string(), - }); - } - - super::wasm_helpers::connect(proto1, proto2, proto3).await - }) - } - - fn open_out_substream(&self, c: &mut Self::Connection) { - // This function can only be called with so-called "multi-stream" connections. We never - // open such connection. - match *c {} + fn client_name(&self) -> std::borrow::Cow { + "subxt-light-client".into() } - fn next_substream<'a>(&self, c: &'a mut Self::Connection) -> Self::NextSubstreamFuture<'a> { - // This function can only be called with so-called "multi-stream" connections. We never - // open such connection. - match *c {} + fn client_version(&self) -> std::borrow::Cow { + env!("CARGO_PKG_VERSION").into() } - fn update_stream<'a>(&self, stream: &'a mut Self::Stream) -> Self::StreamUpdateFuture<'a> { - Box::pin(future::poll_fn(|cx| { - // The `connect` is expected to be called before this method and would populate - // the buffers properly. When the buffers are empty, this future is shortly dropped. - let Some((read_buffer, write_buffer)) = stream.buffers.as_mut() else { - return Poll::Pending; - }; + fn supports_connection_type(&self, connection_type: ConnectionType) -> bool { + let result = matches!( + connection_type, + ConnectionType::WebSocketIpv4 { .. } + | ConnectionType::WebSocketIpv6 { .. } + | ConnectionType::WebSocketDns { .. } + ); - // Whether the future returned by `update_stream` should return `Ready` or `Pending`. - let mut update_stream_future_ready = false; + tracing::trace!( + target: LOG_TARGET, + "Supports connection type={:?} result={}", + connection_type, result + ); - if let StreamReadBuffer::Open { - buffer: ref mut buf, - ref mut cursor, - } = read_buffer - { - // When reading data from the socket, `poll_read` might return "EOF". In that - // situation, we transition to the `Closed` state, which would discard the data - // currently in the buffer. For this reason, we only try to read if there is no - // data left in the buffer. - if cursor.start == cursor.end { - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_read(cx, buf) { - update_stream_future_ready = true; - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(0) => { - // EOF. - *read_buffer = StreamReadBuffer::Closed; - } - Ok(bytes) => { - *cursor = 0..bytes; - } - } - } - } - } - - if let StreamWriteBuffer::Open { - buffer: ref mut buf, - must_flush, - must_close, - } = write_buffer - { - while !buf.is_empty() { - let write_queue_slices = buf.as_slices(); - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_write_vectored( - cx, - &[ - IoSlice::new(write_queue_slices.0), - IoSlice::new(write_queue_slices.1), - ], - ) { - if !*must_close { - // In the situation where the API user wants to close the writing - // side, simply sending the buffered data isn't enough to justify - // making the future ready. - update_stream_future_ready = true; - } + result + } - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(bytes) => { - *must_flush = true; - for _ in 0..bytes { - buf.pop_front(); - } - } - } - } else { - break; - } - } + fn connect_stream(&self, multiaddr: Address) -> Self::StreamConnectFuture { + tracing::trace!(target: LOG_TARGET, "Connect stream to multiaddr={:?}", multiaddr); - if buf.is_empty() && *must_close { - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_close(cx) { - update_stream_future_ready = true; - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(()) => { - *write_buffer = StreamWriteBuffer::Closed; - } - } - } - } else if *must_flush { - if let Poll::Ready(result) = Pin::new(&mut stream.socket).poll_flush(cx) { - update_stream_future_ready = true; - match result { - Err(_) => { - // End the stream. - stream.buffers = None; - return Poll::Ready(()); - } - Ok(()) => { - *must_flush = false; - } - } - } - } + // `PlatformRef` trait guarantees that `connect_stream` is only called with addresses + // stated in `supports_connection_type`. + let addr = match multiaddr { + Address::WebSocketDns { + hostname, + port, + secure: true, + } => { + format!("wss://{}:{}", hostname, port) } - - if update_stream_future_ready { - Poll::Ready(()) - } else { - // Progress cannot be made since poll_read, poll_write, poll_close, poll_flush - // are not ready yet. Smoldot drops this future and calls it again with the - // next processing iteration. - Poll::Pending + Address::WebSocketDns { + hostname, + port, + secure: false, + } => { + format!("ws://{}:{}", hostname, port) } - })) - } - - fn read_buffer<'a>(&self, stream: &'a mut Self::Stream) -> ReadBuffer<'a> { - match stream.buffers.as_ref().map(|(r, _)| r) { - None => ReadBuffer::Reset, - Some(StreamReadBuffer::Closed) => ReadBuffer::Closed, - Some(StreamReadBuffer::Open { buffer, cursor }) => { - ReadBuffer::Open(&buffer[cursor.clone()]) + Address::WebSocketIp { + ip: IpAddr::V4(ip), + port, + } => { + let addr = SocketAddr::from((ip, port)); + format!("ws://{}", addr.to_string()) + } + Address::WebSocketIp { + ip: IpAddr::V6(ip), + port, + } => { + let addr = SocketAddr::from((ip, port)); + format!("ws://{}", addr.to_string()) } - } - } - fn advance_read_cursor(&self, stream: &mut Self::Stream, extra_bytes: usize) { - let Some(StreamReadBuffer::Open { ref mut cursor, .. }) = - stream.buffers.as_mut().map(|(r, _)| r) - else { - assert_eq!(extra_bytes, 0); - return; + // The API user of the `PlatformRef` trait is never supposed to open connections of + // a type that isn't supported. + _ => { + unreachable!("Connecting to an address not supported. This code path indicates a bug in smoldot. Please raise an issue at https://github.com/smol-dot/smoldot/issues") + } }; - assert!(cursor.start + extra_bytes <= cursor.end); - cursor.start += extra_bytes; - } - - fn writable_bytes(&self, stream: &mut Self::Stream) -> usize { - let Some(StreamWriteBuffer::Open { - ref mut buffer, - must_close: false, - .. - }) = stream.buffers.as_mut().map(|(_, w)| w) - else { - return 0; - }; - buffer.capacity() - buffer.len() - } + Box::pin(async move { + tracing::debug!(target: LOG_TARGET, "Connecting to addr={addr}"); - fn send(&self, stream: &mut Self::Stream, data: &[u8]) { - debug_assert!(!data.is_empty()); + let socket = WasmSocket::new(addr.as_str()).map_err(|err| ConnectError { + message: format!("Failed to reach peer: {err}"), + })?; - // Because `writable_bytes` returns 0 if the writing side is closed, and because `data` - // must always have a size inferior or equal to `writable_bytes`, we know for sure that - // the writing side isn't closed. - let Some(StreamWriteBuffer::Open { ref mut buffer, .. }) = - stream.buffers.as_mut().map(|(_, w)| w) - else { - panic!() - }; - buffer.reserve(data.len()); - buffer.extend(data.iter().copied()); + Ok(super::wasm_helpers::Stream( + super::wasm_helpers::with_buffers::WithBuffers::new(socket), + )) + }) } - fn close_send(&self, stream: &mut Self::Stream) { - // It is not illegal to call this on an already-reset stream. - let Some((_, write_buffer)) = stream.buffers.as_mut() else { - return; - }; + fn connect_multistream(&self, _address: MultiStreamAddress) -> Self::MultiStreamConnectFuture { + panic!("Multistreams are not currently supported. This code path indicates a bug in smoldot. Please raise an issue at https://github.com/smol-dot/smoldot/issues") + } - match write_buffer { - StreamWriteBuffer::Open { - must_close: must_close @ false, - .. - } => *must_close = true, - _ => { - // However, it is illegal to call this on a stream that was already close - // attempted. - panic!() - } - } + fn open_out_substream(&self, c: &mut Self::MultiStream) { + // This function can only be called with so-called "multi-stream" connections. We never + // open such connection. + match *c {} } - fn spawn_task(&self, _: std::borrow::Cow, task: future::BoxFuture<'static, ()>) { - super::wasm_helpers::spawn(task); + fn next_substream(&self, c: &'_ mut Self::MultiStream) -> Self::NextSubstreamFuture<'_> { + // This function can only be called with so-called "multi-stream" connections. We never + // open such connection. + match *c {} } - fn client_name(&self) -> std::borrow::Cow { - "subxt-light-client".into() + fn read_write_access<'a>( + &self, + stream: Pin<&'a mut Self::Stream>, + ) -> Result, &'a io::Error> { + let stream = stream.project(); + stream.0.read_write_access(Self::Instant::now()) } - fn client_version(&self) -> std::borrow::Cow { - env!("CARGO_PKG_VERSION").into() + fn wait_read_write_again<'a>( + &self, + stream: Pin<&'a mut Self::Stream>, + ) -> Self::StreamUpdateFuture<'a> { + let stream = stream.project(); + Box::pin(stream.0.wait_read_write_again(|when| async move { + let now = super::wasm_helpers::now(); + let duration = when.saturating_duration_since(now); + super::wasm_helpers::sleep(duration).await; + })) } } diff --git a/testing/wasm-lightclient-tests/Cargo.lock b/testing/wasm-lightclient-tests/Cargo.lock index 5720150450..723dc3b4fb 100644 --- a/testing/wasm-lightclient-tests/Cargo.lock +++ b/testing/wasm-lightclient-tests/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -18,56 +18,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.7.5" +name = "ahash" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "cipher", - "cpufeatures", - "opaque-debug", -] - -[[package]] -name = "aes-gcm" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", + "once_cell", + "version_check", ] [[package]] -name = "ahash" -version = "0.7.6" +name = "allocator-api2" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayref" @@ -90,11 +61,22 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + [[package]] name = "async-lock" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ "event-listener", ] @@ -111,10 +93,10 @@ dependencies = [ ] [[package]] -name = "atomic" -version = "0.5.3" +name = "atomic-take" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" +checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "autocfg" @@ -124,9 +106,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -151,9 +133,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "beef" @@ -218,13 +200,13 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.2.6", + "constant_time_eq 0.3.0", ] [[package]] @@ -256,9 +238,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byte-slice-cast" @@ -268,21 +250,24 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -292,36 +277,32 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "zeroize", ] [[package]] -name = "chacha20poly1305" -version = "0.9.1" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", + "crypto-common", + "inout", ] [[package]] -name = "cipher" -version = "0.3.0" +name = "concurrent-queue" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" dependencies = [ - "generic-array", + "crossbeam-utils", ] [[package]] @@ -342,9 +323,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "constant_time_eq" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "convert_case" @@ -370,9 +351,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -422,40 +403,32 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctr" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" -dependencies = [ - "cipher", -] - [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version", "subtle", "zeroize", ] [[package]] -name = "curve25519-dalek" -version = "4.0.0-rc.1" +name = "curve25519-dalek-derive" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ - "cfg-if", - "fiat-crypto", - "packed_simd_2", - "platforms", - "subtle", - "zeroize", + "proc-macro2", + "quote", + "syn 2.0.38", ] [[package]] @@ -466,7 +439,7 @@ checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core 0.6.4", + "rand_core", "subtle-ng", "zeroize", ] @@ -591,17 +564,27 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + [[package]] name = "ed25519-zebra" -version = "3.1.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ - "curve25519-dalek 3.2.0", - "hashbrown 0.12.3", + "curve25519-dalek", + "ed25519", + "hashbrown 0.14.1", "hex", - "rand_core 0.6.4", - "sha2 0.9.9", + "rand_core", + "sha2 0.10.8", "zeroize", ] @@ -611,6 +594,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "event-listener" version = "2.5.3" @@ -619,9 +608,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fiat-crypto" -version = "0.1.20" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" +checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" [[package]] name = "fixed-hash" @@ -715,6 +704,16 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.28" @@ -789,21 +788,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "ghash" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" -dependencies = [ - "opaque-debug", - "polyval", -] - [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "gloo-net" @@ -853,9 +842,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -863,7 +852,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -875,16 +864,15 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" dependencies = [ + "ahash", + "allocator-api2", "serde", ] @@ -896,12 +884,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -969,15 +954,15 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -1068,12 +1053,31 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown 0.14.1", +] + [[package]] name = "indexmap-nostd" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -1086,26 +1090,20 @@ dependencies = [ "web-sys", ] -[[package]] -name = "intx" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" - [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" @@ -1224,21 +1222,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.146" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" - -[[package]] -name = "libm" -version = "0.1.4" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsecp256k1" @@ -1290,21 +1282,21 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "merlin" @@ -1314,7 +1306,7 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core 0.6.4", + "rand_core", "zeroize", ] @@ -1341,7 +1333,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1368,9 +1360,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -1401,18 +1393,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", @@ -1420,9 +1412,9 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -1445,21 +1437,11 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm 0.1.4", -] - [[package]] name = "parity-scale-codec" -version = "3.6.1" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2287753623c76f953acd29d15d8100bcab84d29db78fb6f352adb3c53e83b967" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -1471,9 +1453,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.1" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b6937b5e67bfba3351b87b040d48352a2fcb6ad72f81855412ce97b45c8f110" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1483,15 +1465,15 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pbkdf2" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", ] @@ -1504,18 +1486,18 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", @@ -1536,28 +1518,16 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "platforms" -version = "3.0.2" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" [[package]] name = "poly1305" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "polyval" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cfg-if", "cpufeatures", "opaque-debug", "universal-hash", @@ -1648,7 +1618,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -1658,15 +1628,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - [[package]] name = "rand_core" version = "0.6.4" @@ -1744,11 +1708,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.4", ] [[package]] @@ -1774,9 +1738,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scale-bits" @@ -1847,9 +1811,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ "bitvec", "cfg-if", @@ -1861,9 +1825,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1893,11 +1857,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -1910,7 +1874,7 @@ dependencies = [ "arrayvec 0.7.4", "curve25519-dalek-ng", "merlin", - "rand_core 0.6.4", + "rand_core", "sha2 0.9.9", "subtle-ng", "zeroize", @@ -1934,9 +1898,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags", "core-foundation", @@ -1947,9 +1911,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -1957,9 +1921,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "send_wrapper" @@ -1975,18 +1939,18 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", @@ -2032,9 +1996,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -2053,56 +2017,62 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" + [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smoldot" -version = "0.8.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cce5e2881b30bad7ef89f383a816ad0b22c45915911f28499026de4a76d20ee" +checksum = "4388a7690d9f76320dedc7f97f213160fbe4fb4a38a8b4cc8bb96e0fd05e0971" dependencies = [ "arrayvec 0.7.4", "async-lock", - "atomic", - "base64 0.21.2", + "atomic-take", + "base64 0.21.4", "bip39", "blake2-rfc", "bs58", + "chacha20", "crossbeam-queue", "derive_more", "ed25519-zebra", "either", "event-listener", "fnv", - "futures-channel", - "futures-util", - "hashbrown 0.14.0", + "futures-lite", + "hashbrown 0.14.1", "hex", "hmac 0.12.1", "itertools", @@ -2114,63 +2084,56 @@ dependencies = [ "num-rational", "num-traits", "pbkdf2", + "poly1305", "rand", "rand_chacha", "ruzstd", "schnorrkel", "serde", "serde_json", - "sha2 0.10.7", + "sha2 0.10.8", + "sha3", "siphasher", "slab", "smallvec", - "snow", - "tiny-keccak", "twox-hash", "wasmi", + "x25519-dalek", + "zeroize", ] [[package]] name = "smoldot-light" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2f7b4687b83ff244ef6137735ed5716ad37dcdf3ee16c4eb1a32fb9808fa47" +checksum = "bea3d21923cbdb1362205ff8b2adb5da67e6b81b34c4bba1baaef9b88cbd83b8" dependencies = [ + "async-channel", "async-lock", + "base64 0.21.4", "blake2-rfc", "derive_more", "either", "event-listener", "fnv", "futures-channel", + "futures-lite", "futures-util", - "hashbrown 0.14.0", + "hashbrown 0.14.1", "hex", "itertools", "log", "lru", + "no-std-net", + "pin-project", "rand", + "rand_chacha", "serde", "serde_json", "siphasher", "slab", "smoldot", -] - -[[package]] -name = "snow" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" -dependencies = [ - "aes-gcm", - "blake2", - "chacha20poly1305", - "curve25519-dalek 4.0.0-rc.1", - "rand_core 0.6.4", - "rustc_version", - "sha2 0.10.7", - "subtle", + "zeroize", ] [[package]] @@ -2190,7 +2153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2217,7 +2180,7 @@ dependencies = [ "blake2b_simd", "byteorder", "digest 0.10.7", - "sha2 0.10.7", + "sha2 0.10.8", "sha3", "sp-std", "twox-hash", @@ -2327,6 +2290,7 @@ dependencies = [ "getrandom", "instant", "js-sys", + "pin-project", "send_wrapper 0.6.0", "serde", "serde_json", @@ -2346,6 +2310,7 @@ name = "subxt-macro" version = "0.32.1" dependencies = [ "darling 0.20.3", + "parity-scale-codec", "proc-macro-error", "subxt-codegen", "syn 2.0.38", @@ -2392,9 +2357,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] @@ -2421,9 +2386,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", @@ -2440,15 +2405,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -2478,7 +2434,7 @@ dependencies = [ "pin-project-lite", "socket2 0.5.4", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2515,9 +2471,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -2530,17 +2486,17 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.0.2", "toml_datetime", "winnow", ] @@ -2574,9 +2530,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", @@ -2645,9 +2601,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uint" @@ -2669,9 +2625,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2684,11 +2640,11 @@ dependencies = [ [[package]] name = "universal-hash" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array", + "crypto-common", "subtle", ] @@ -2835,11 +2791,10 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51fb5c61993e71158abf5bb863df2674ca3ec39ed6471c64f07aeaf751d67b4" +checksum = "1f341edb80021141d4ae6468cbeefc50798716a347d4085c3811900049ea8945" dependencies = [ - "intx", "smallvec", "spin 0.9.8", "wasmi_arena", @@ -2855,12 +2810,12 @@ checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" [[package]] name = "wasmi_core" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" +checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" dependencies = [ "downcast-rs", - "libm 0.2.7", + "libm", "num-traits", "paste", ] @@ -2906,21 +2861,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -2932,108 +2872,66 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" dependencies = [ "memchr", ] @@ -3047,6 +2945,18 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + [[package]] name = "yap" version = "0.11.0" diff --git a/testing/wasm-lightclient-tests/tests/wasm.rs b/testing/wasm-lightclient-tests/tests/wasm.rs index 082fae7a61..c582307288 100644 --- a/testing/wasm-lightclient-tests/tests/wasm.rs +++ b/testing/wasm-lightclient-tests/tests/wasm.rs @@ -19,7 +19,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); // // ```bash // # Polkadot does not accept by default WebSocket connections to the P2P network. -// # Ensure `--listen-addr` is provided with valid ws adddress endpoint. +// # Ensure `--listen-addr` is provided with valid ws address endpoint. // # The `--node-key` provides a deterministic p2p address for the node. // ./polkadot --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws // ``` From cb6520834f0642149d8eba2db0d4a08c963387dc Mon Sep 17 00:00:00 2001 From: Tadeo Hepperle <62739623+tadeohepperle@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:22:48 +0100 Subject: [PATCH 24/27] ChargeAssetTxPayment: support providing u32 or MultiLocation in default impl (#1227) * Asset Id in Config trait * add example configuring the config * fmt * fix Default trait bound * merge examples, fix default again * adjust config in examples * Update subxt/src/config/mod.rs Co-authored-by: James Wilson --------- Co-authored-by: James Wilson --- subxt/examples/setup_config_custom.rs | 4 ++- .../examples/setup_config_signed_extension.rs | 3 +- subxt/src/config/default_extrinsic_params.rs | 6 ++-- subxt/src/config/mod.rs | 3 ++ subxt/src/config/polkadot.rs | 1 + subxt/src/config/signed_extensions.rs | 34 ++++++++++++------- subxt/src/config/substrate.rs | 1 + 7 files changed, 34 insertions(+), 18 deletions(-) diff --git a/subxt/examples/setup_config_custom.rs b/subxt/examples/setup_config_custom.rs index 46a3afc3a2..edc21fcb11 100644 --- a/subxt/examples/setup_config_custom.rs +++ b/subxt/examples/setup_config_custom.rs @@ -3,8 +3,9 @@ use subxt::client::OfflineClientT; use subxt::config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder}; use subxt_signer::sr25519::dev; -#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")] +#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale")] pub mod runtime {} +use runtime::runtime_types::xcm::v2::multilocation::MultiLocation; // We don't need to construct this at runtime, // so an empty enum is appropriate: @@ -18,6 +19,7 @@ impl Config for CustomConfig { type Hasher = subxt::config::substrate::BlakeTwo256; type Header = subxt::config::substrate::SubstrateHeader; type ExtrinsicParams = CustomExtrinsicParams; + type AssetId = MultiLocation; } // This represents some arbitrary (and nonsensical) custom parameters that diff --git a/subxt/examples/setup_config_signed_extension.rs b/subxt/examples/setup_config_signed_extension.rs index 92274924c1..c74e5f655b 100644 --- a/subxt/examples/setup_config_signed_extension.rs +++ b/subxt/examples/setup_config_signed_extension.rs @@ -30,12 +30,13 @@ impl Config for CustomConfig { signed_extensions::CheckNonce, signed_extensions::CheckGenesis, signed_extensions::CheckMortality, - signed_extensions::ChargeAssetTxPayment, + signed_extensions::ChargeAssetTxPayment, signed_extensions::ChargeTransactionPayment, // And add a new one of our own: CustomSignedExtension, ), >; + type AssetId = u32; } // Our custom signed extension doesn't do much: diff --git a/subxt/src/config/default_extrinsic_params.rs b/subxt/src/config/default_extrinsic_params.rs index f044574258..880591e7f0 100644 --- a/subxt/src/config/default_extrinsic_params.rs +++ b/subxt/src/config/default_extrinsic_params.rs @@ -15,7 +15,7 @@ pub type DefaultExtrinsicParams = signed_extensions::AnyOf< signed_extensions::CheckNonce, signed_extensions::CheckGenesis, signed_extensions::CheckMortality, - signed_extensions::ChargeAssetTxPayment, + signed_extensions::ChargeAssetTxPayment, signed_extensions::ChargeTransactionPayment, ), >; @@ -27,7 +27,7 @@ pub struct DefaultExtrinsicParamsBuilder { /// `None` means the tx will be immortal. mortality: Option>, /// `None` means we'll use the native token. - tip_of_asset_id: Option, + tip_of_asset_id: Option, tip: u128, tip_of: u128, } @@ -103,7 +103,7 @@ impl DefaultExtrinsicParamsBuilder { /// Provide a tip to the block auther using the token denominated by the `asset_id` provided. This /// is not applicable on chains which don't use the `ChargeAssetTxPayment` signed extension; in this /// case, no tip will be given. - pub fn tip_of(mut self, tip: u128, asset_id: u32) -> Self { + pub fn tip_of(mut self, tip: u128, asset_id: T::AssetId) -> Self { self.tip = 0; self.tip_of = tip; self.tip_of_asset_id = Some(asset_id); diff --git a/subxt/src/config/mod.rs b/subxt/src/config/mod.rs index 960c58b6d7..c52d1a029a 100644 --- a/subxt/src/config/mod.rs +++ b/subxt/src/config/mod.rs @@ -51,6 +51,9 @@ pub trait Config: Sized + Send + Sync + 'static { /// This type defines the extrinsic extra and additional parameters. type ExtrinsicParams: ExtrinsicParams; + + /// This is used to identify an asset in the `ChargeAssetTxPayment` signed extension. + type AssetId: Debug + Encode; } /// given some [`Config`], this return the other params needed for its `ExtrinsicParams`. diff --git a/subxt/src/config/polkadot.rs b/subxt/src/config/polkadot.rs index 5fb3390483..209c3b8fb6 100644 --- a/subxt/src/config/polkadot.rs +++ b/subxt/src/config/polkadot.rs @@ -21,6 +21,7 @@ impl Config for PolkadotConfig { type Hasher = ::Hasher; type Header = ::Header; type ExtrinsicParams = PolkadotExtrinsicParams; + type AssetId = u32; } /// A struct representing the signed extra and additional parameters required diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index 29f01dd6d6..d0c3fa66c1 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -227,10 +227,10 @@ impl SignedExtension for CheckMortality { } /// The [`ChargeAssetTxPayment`] signed extension. -#[derive(Debug, DecodeAsType)] -pub struct ChargeAssetTxPayment { +#[derive(Debug)] +pub struct ChargeAssetTxPayment { tip: Compact, - asset_id: Option, + asset_id: Option, } impl ChargeAssetTxPayment { @@ -246,13 +246,21 @@ impl ChargeAssetTxPayment { } /// Parameters to configure the [`ChargeAssetTxPayment`] signed extension. -#[derive(Default)] -pub struct ChargeAssetTxPaymentParams { +pub struct ChargeAssetTxPaymentParams { tip: u128, - asset_id: Option, + asset_id: Option, +} + +impl Default for ChargeAssetTxPaymentParams { + fn default() -> Self { + ChargeAssetTxPaymentParams { + tip: Default::default(), + asset_id: Default::default(), + } + } } -impl ChargeAssetTxPaymentParams { +impl ChargeAssetTxPaymentParams { /// Don't provide a tip to the extrinsic author. pub fn no_tip() -> Self { ChargeAssetTxPaymentParams { @@ -268,7 +276,7 @@ impl ChargeAssetTxPaymentParams { } } /// Tip the extrinsic author using the asset ID given. - pub fn tip_of(tip: u128, asset_id: u32) -> Self { + pub fn tip_of(tip: u128, asset_id: T::AssetId) -> Self { ChargeAssetTxPaymentParams { tip, asset_id: Some(asset_id), @@ -276,8 +284,8 @@ impl ChargeAssetTxPaymentParams { } } -impl ExtrinsicParams for ChargeAssetTxPayment { - type OtherParams = ChargeAssetTxPaymentParams; +impl ExtrinsicParams for ChargeAssetTxPayment { + type OtherParams = ChargeAssetTxPaymentParams; type Error = std::convert::Infallible; fn new>( @@ -292,13 +300,13 @@ impl ExtrinsicParams for ChargeAssetTxPayment { } } -impl ExtrinsicParamsEncoder for ChargeAssetTxPayment { +impl ExtrinsicParamsEncoder for ChargeAssetTxPayment { fn encode_extra_to(&self, v: &mut Vec) { - (self.tip, self.asset_id).encode_to(v); + (self.tip, &self.asset_id).encode_to(v); } } -impl SignedExtension for ChargeAssetTxPayment { +impl SignedExtension for ChargeAssetTxPayment { const NAME: &'static str = "ChargeAssetTxPayment"; type Decoded = Self; } diff --git a/subxt/src/config/substrate.rs b/subxt/src/config/substrate.rs index 609b20a778..44cfcf7b73 100644 --- a/subxt/src/config/substrate.rs +++ b/subxt/src/config/substrate.rs @@ -24,6 +24,7 @@ impl Config for SubstrateConfig { type Hasher = BlakeTwo256; type Header = SubstrateHeader; type ExtrinsicParams = SubstrateExtrinsicParams; + type AssetId = u32; } /// A struct representing the signed extra and additional parameters required From d50519d1e20cb47faac8059af437882fbf6bb2c1 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 9 Nov 2023 13:17:32 +0100 Subject: [PATCH 25/27] generic AssetId --- subxt/src/blocks/extrinsic_types.rs | 2 +- subxt/src/config/mod.rs | 3 ++- subxt/src/config/signed_extensions.rs | 12 +++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/subxt/src/blocks/extrinsic_types.rs b/subxt/src/blocks/extrinsic_types.rs index f540cd7ec4..5d7549e739 100644 --- a/subxt/src/blocks/extrinsic_types.rs +++ b/subxt/src/blocks/extrinsic_types.rs @@ -691,7 +691,7 @@ impl<'a, T: Config> ExtrinsicSignedExtensions<'a, T> { .flatten() .map(|e| e.tip()) .or_else(|| { - self.find::() + self.find::>() .ok() .flatten() .map(|e| e.tip()) diff --git a/subxt/src/config/mod.rs b/subxt/src/config/mod.rs index c52d1a029a..542ea9874d 100644 --- a/subxt/src/config/mod.rs +++ b/subxt/src/config/mod.rs @@ -17,6 +17,7 @@ pub mod substrate; use codec::{Decode, Encode}; use core::fmt::Debug; +use scale_decode::DecodeAsType; use serde::{de::DeserializeOwned, Serialize}; pub use default_extrinsic_params::{DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder}; @@ -53,7 +54,7 @@ pub trait Config: Sized + Send + Sync + 'static { type ExtrinsicParams: ExtrinsicParams; /// This is used to identify an asset in the `ChargeAssetTxPayment` signed extension. - type AssetId: Debug + Encode; + type AssetId: Debug + Encode + DecodeAsType; } /// given some [`Config`], this return the other params needed for its `ExtrinsicParams`. diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index d0c3fa66c1..145a6012aa 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -12,8 +12,13 @@ use crate::utils::Era; use crate::{client::OfflineClientT, Config}; use codec::{Compact, Encode}; use core::fmt::Debug; +use scale_decode::visitor::types::Composite; +use scale_decode::visitor::{DecodeAsTypeResult, TypeId}; use scale_decode::DecodeAsType; +use scale_info::PortableRegistry; use std::collections::HashMap; +use std::fmt::Formatter; +use std::marker::PhantomData; /// A single [`SignedExtension`] has a unique name, but is otherwise the /// same as [`ExtrinsicParams`] in describing how to encode the extra and @@ -227,20 +232,21 @@ impl SignedExtension for CheckMortality { } /// The [`ChargeAssetTxPayment`] signed extension. -#[derive(Debug)] +#[derive(Debug, DecodeAsType)] +#[decode_as_type(trait_bounds = "T::AssetId: DecodeAsType")] pub struct ChargeAssetTxPayment { tip: Compact, asset_id: Option, } -impl ChargeAssetTxPayment { +impl ChargeAssetTxPayment { /// Tip to the extrinsic author in the native chain token. pub fn tip(&self) -> u128 { self.tip.0 } /// Tip to the extrinsic author using the asset ID given. - pub fn asset_id(&self) -> Option { + pub fn asset_id(&self) -> Option { self.asset_id } } From 3a79e70f53098a7aae82efebd4e7fd9ad19a5773 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 10 Nov 2023 18:12:23 +0100 Subject: [PATCH 26/27] fix generics --- subxt/src/config/signed_extensions.rs | 14 +++++++------- .../src/full_client/blocks/mod.rs | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index 145a6012aa..29d920d2e0 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -12,13 +12,13 @@ use crate::utils::Era; use crate::{client::OfflineClientT, Config}; use codec::{Compact, Encode}; use core::fmt::Debug; -use scale_decode::visitor::types::Composite; -use scale_decode::visitor::{DecodeAsTypeResult, TypeId}; + + use scale_decode::DecodeAsType; -use scale_info::PortableRegistry; + use std::collections::HashMap; -use std::fmt::Formatter; -use std::marker::PhantomData; + + /// A single [`SignedExtension`] has a unique name, but is otherwise the /// same as [`ExtrinsicParams`] in describing how to encode the extra and @@ -246,8 +246,8 @@ impl ChargeAssetTxPayment { } /// Tip to the extrinsic author using the asset ID given. - pub fn asset_id(&self) -> Option { - self.asset_id + pub fn asset_id(&self) -> Option<&T::AssetId> { + self.asset_id.as_ref() } } diff --git a/testing/integration-tests/src/full_client/blocks/mod.rs b/testing/integration-tests/src/full_client/blocks/mod.rs index 3330c01e72..53c6d4d9a2 100644 --- a/testing/integration-tests/src/full_client/blocks/mod.rs +++ b/testing/integration-tests/src/full_client/blocks/mod.rs @@ -280,7 +280,7 @@ async fn decode_signed_extensions_from_blocks() { let nonce1_static = extensions1.find::().unwrap().unwrap().0; let tip1 = extensions1.tip().unwrap(); let tip1_static: u128 = extensions1 - .find::() + .find::>() .unwrap() .unwrap() .tip(); @@ -291,7 +291,7 @@ async fn decode_signed_extensions_from_blocks() { let nonce2_static = extensions2.find::().unwrap().unwrap().0; let tip2 = extensions2.tip().unwrap(); let tip2_static: u128 = extensions2 - .find::() + .find::>() .unwrap() .unwrap() .tip(); From 0876c28fe29890d02fa7ac46da2af61b2d21b876 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 10 Nov 2023 18:14:57 +0100 Subject: [PATCH 27/27] fmt --- subxt/src/config/signed_extensions.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/subxt/src/config/signed_extensions.rs b/subxt/src/config/signed_extensions.rs index 29d920d2e0..b8a197bca4 100644 --- a/subxt/src/config/signed_extensions.rs +++ b/subxt/src/config/signed_extensions.rs @@ -13,13 +13,10 @@ use crate::{client::OfflineClientT, Config}; use codec::{Compact, Encode}; use core::fmt::Debug; - use scale_decode::DecodeAsType; use std::collections::HashMap; - - /// A single [`SignedExtension`] has a unique name, but is otherwise the /// same as [`ExtrinsicParams`] in describing how to encode the extra and /// additional data.