mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 17:31:05 +00:00
Remove codec::Encode and codec::Decode derives from generated APIs by default (#2008)
* Remove codec::Encode and codec::Decode from generated APIs by default * clippy fixes * clippy * More fixes, and CompactAs only if Encode/Decode * revert println in example * fix lightclient test * fix docs * Fix another rust doc comment * Fix failing storage test * Remove now-unnecessary test * clippy * clippy * Remove pointless clone
This commit is contained in:
+4
-5
@@ -100,7 +100,8 @@ impl FileOrUrl {
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
(Some(PathOrStdIn::StdIn), None, None) => {
|
(Some(PathOrStdIn::StdIn), None, None) => {
|
||||||
let res = std::io::stdin().bytes().collect::<Result<Vec<u8>, _>>();
|
let reader = std::io::BufReader::new(std::io::stdin());
|
||||||
|
let res = reader.bytes().collect::<Result<Vec<u8>, _>>();
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(bytes) => Ok(bytes),
|
Ok(bytes) => Ok(bytes),
|
||||||
@@ -191,13 +192,11 @@ fn time_based_seed() -> u64 {
|
|||||||
|
|
||||||
pub fn first_paragraph_of_docs(docs: &[String]) -> String {
|
pub fn first_paragraph_of_docs(docs: &[String]) -> String {
|
||||||
// take at most the first paragraph of documentation, such that it does not get too long.
|
// take at most the first paragraph of documentation, such that it does not get too long.
|
||||||
let docs_str = docs
|
docs.iter()
|
||||||
.iter()
|
|
||||||
.map(|e| e.trim())
|
.map(|e| e.trim())
|
||||||
.take_while(|e| !e.is_empty())
|
.take_while(|e| !e.is_empty())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n");
|
.join("\n")
|
||||||
docs_str
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Indent: ToString {
|
pub trait Indent: ToString {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# result_large_err lint complains if error variant is 128 bytes or more by default.
|
||||||
|
# Our error is. Let's up this limit a bit for now to avoid lots of warnings.
|
||||||
|
large-error-threshold = 256
|
||||||
@@ -6,7 +6,7 @@ use heck::{ToSnakeCase as _, ToUpperCamelCase};
|
|||||||
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream};
|
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use scale_info::TypeDef;
|
use scale_info::TypeDef;
|
||||||
use scale_typegen::{TypeGenerator, typegen::type_path::TypePath};
|
use scale_typegen::TypeGenerator;
|
||||||
use subxt_metadata::{
|
use subxt_metadata::{
|
||||||
PalletMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher,
|
PalletMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher,
|
||||||
};
|
};
|
||||||
@@ -92,7 +92,7 @@ fn generate_storage_entry_fns(
|
|||||||
.expect("type is in metadata; qed");
|
.expect("type is in metadata; qed");
|
||||||
|
|
||||||
let alias_name = format_ident!("Param{}", idx);
|
let alias_name = format_ident!("Param{}", idx);
|
||||||
let alias_type = primitive_type_alias(&ty_path, type_gen.settings());
|
let alias_type = ty_path.to_token_stream(type_gen.settings());
|
||||||
|
|
||||||
let alias_type_def = quote!( pub type #alias_name = #alias_type; );
|
let alias_type_def = quote!( pub type #alias_name = #alias_type; );
|
||||||
let alias_type_path = quote!( types::#alias_module_name::#alias_name );
|
let alias_type_path = quote!( types::#alias_module_name::#alias_name );
|
||||||
@@ -206,7 +206,7 @@ fn generate_storage_entry_fns(
|
|||||||
let key = &keys_slice[0];
|
let key = &keys_slice[0];
|
||||||
if key.hasher.ends_with_key() {
|
if key.hasher.ends_with_key() {
|
||||||
let arg = &key.arg_name;
|
let arg = &key.arg_name;
|
||||||
let keys = quote!(#static_storage_key::new(#arg.borrow()));
|
let keys = quote!(#static_storage_key::new(#arg));
|
||||||
let path = &key.alias_type_path;
|
let path = &key.alias_type_path;
|
||||||
let path = quote!(#static_storage_key<#path>);
|
let path = quote!(#static_storage_key<#path>);
|
||||||
(keys, path)
|
(keys, path)
|
||||||
@@ -220,7 +220,7 @@ fn generate_storage_entry_fns(
|
|||||||
arg_name, hasher, ..
|
arg_name, hasher, ..
|
||||||
}| {
|
}| {
|
||||||
if hasher.ends_with_key() {
|
if hasher.ends_with_key() {
|
||||||
quote!( #static_storage_key::new(#arg_name.borrow()) )
|
quote!( #static_storage_key::new(#arg_name) )
|
||||||
} else {
|
} else {
|
||||||
quote!(())
|
quote!(())
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ fn generate_storage_entry_fns(
|
|||||||
arg_name,
|
arg_name,
|
||||||
alias_type_path,
|
alias_type_path,
|
||||||
..
|
..
|
||||||
}| quote!( #arg_name: impl ::core::borrow::Borrow<#alias_type_path> ),
|
}| quote!( #arg_name: #alias_type_path ),
|
||||||
);
|
);
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
@@ -300,34 +300,14 @@ fn generate_storage_entry_fns(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primitive_type_alias(
|
|
||||||
type_path: &TypePath,
|
|
||||||
settings: &scale_typegen::TypeGeneratorSettings,
|
|
||||||
) -> TokenStream {
|
|
||||||
// Vec<T> is cast to [T]
|
|
||||||
if let Some(ty) = type_path.vec_type_param() {
|
|
||||||
let ty = ty.to_token_stream(settings);
|
|
||||||
return quote!([#ty]);
|
|
||||||
}
|
|
||||||
// String is cast to str
|
|
||||||
if type_path.is_string() {
|
|
||||||
return quote!(::core::primitive::str);
|
|
||||||
}
|
|
||||||
type_path.to_token_stream(settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::RuntimeGenerator;
|
|
||||||
use frame_metadata::v15;
|
use frame_metadata::v15;
|
||||||
use heck::ToUpperCamelCase;
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
use scale_info::{MetaType, meta_type};
|
use scale_info::{MetaType, meta_type};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use subxt_metadata::Metadata;
|
use subxt_metadata::Metadata;
|
||||||
|
|
||||||
|
// TODO: Think about adding tests for storage codegen which can use this sort of function.
|
||||||
|
#[allow(dead_code)]
|
||||||
fn metadata_with_storage_entries(
|
fn metadata_with_storage_entries(
|
||||||
storage_entries: impl IntoIterator<Item = (&'static str, MetaType)>,
|
storage_entries: impl IntoIterator<Item = (&'static str, MetaType)>,
|
||||||
) -> Metadata {
|
) -> Metadata {
|
||||||
@@ -387,68 +367,4 @@ mod tests {
|
|||||||
.expect("can build valid metadata");
|
.expect("can build valid metadata");
|
||||||
metadata
|
metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn borrow_type_replacements() {
|
|
||||||
let storage_entries = [
|
|
||||||
("vector", meta_type::<Vec<u8>>()),
|
|
||||||
("boxed", meta_type::<Box<u16>>()),
|
|
||||||
("string", meta_type::<String>()),
|
|
||||||
("static_string", meta_type::<&'static str>()),
|
|
||||||
("cow_string", meta_type::<Cow<'_, str>>()),
|
|
||||||
];
|
|
||||||
|
|
||||||
let expected_borrowed_types = [
|
|
||||||
quote!([::core::primitive::u8]),
|
|
||||||
quote!(::core::primitive::u16),
|
|
||||||
quote!(::core::primitive::str),
|
|
||||||
quote!(::core::primitive::str),
|
|
||||||
quote!(::core::primitive::str),
|
|
||||||
];
|
|
||||||
|
|
||||||
let metadata = metadata_with_storage_entries(storage_entries);
|
|
||||||
|
|
||||||
let item_mod = syn::parse_quote!(
|
|
||||||
pub mod api {}
|
|
||||||
);
|
|
||||||
let generator = RuntimeGenerator::new(metadata);
|
|
||||||
let generated = generator
|
|
||||||
.generate_runtime(
|
|
||||||
item_mod,
|
|
||||||
Default::default(),
|
|
||||||
Default::default(),
|
|
||||||
syn::parse_str("::subxt_path").unwrap(),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.expect("should be able to generate runtime");
|
|
||||||
let generated_str = generated.to_string();
|
|
||||||
|
|
||||||
for ((name, _), expected_type) in storage_entries
|
|
||||||
.into_iter()
|
|
||||||
.zip(expected_borrowed_types.into_iter())
|
|
||||||
{
|
|
||||||
let name_ident = format_ident!("{}", name);
|
|
||||||
let expected_storage_constructor = quote!(
|
|
||||||
fn #name_ident(
|
|
||||||
&self,
|
|
||||||
_0: impl ::core::borrow::Borrow<types::#name_ident::Param0>,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
dbg!(&generated_str);
|
|
||||||
dbg!(&expected_storage_constructor.to_string());
|
|
||||||
assert!(generated_str.contains(&expected_storage_constructor.to_string()));
|
|
||||||
|
|
||||||
let alias_name = format_ident!("{}", name.to_upper_camel_case());
|
|
||||||
let expected_alias_module = quote!(
|
|
||||||
pub mod #name_ident {
|
|
||||||
use super::runtime_types;
|
|
||||||
|
|
||||||
pub type #alias_name = ::core::primitive::bool;
|
|
||||||
pub type Param0 = #expected_type;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(generated_str.contains(&expected_alias_module.to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-8
@@ -312,15 +312,35 @@ fn subxt_type_gen_settings(
|
|||||||
crate_path: &syn::Path,
|
crate_path: &syn::Path,
|
||||||
should_gen_docs: bool,
|
should_gen_docs: bool,
|
||||||
) -> TypeGeneratorSettings {
|
) -> TypeGeneratorSettings {
|
||||||
|
// If we're using codec::Encode or codec::Decode derives, then we want to
|
||||||
|
// output #[codec(index = N)] and #[codec(compact)] attrs, else we don't.
|
||||||
|
let insert_codec_attributes = derives.default_derives().derives().iter().any(|path| {
|
||||||
|
let mut segments_backwards = path.segments.iter().rev();
|
||||||
|
let ident = segments_backwards.next();
|
||||||
|
let module = segments_backwards.next();
|
||||||
|
|
||||||
|
let is_ident_match = ident.is_some_and(|s| s.ident == "Encode" || s.ident == "Decode");
|
||||||
|
let is_module_match = module.is_some_and(|s| s.ident == "codec");
|
||||||
|
|
||||||
|
is_ident_match && is_module_match
|
||||||
|
});
|
||||||
|
|
||||||
|
// If we're inserting the codec attributes, we also should use `CompactAs` where necessary.
|
||||||
|
let compact_as_type_path = if insert_codec_attributes {
|
||||||
|
Some(parse_quote!(#crate_path::ext::codec::CompactAs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
TypeGeneratorSettings {
|
TypeGeneratorSettings {
|
||||||
types_mod_ident: parse_quote!(runtime_types),
|
types_mod_ident: parse_quote!(runtime_types),
|
||||||
should_gen_docs,
|
should_gen_docs,
|
||||||
derives,
|
derives,
|
||||||
substitutes,
|
substitutes,
|
||||||
decoded_bits_type_path: Some(parse_quote!(#crate_path::utils::bits::DecodedBits)),
|
decoded_bits_type_path: Some(parse_quote!(#crate_path::utils::bits::DecodedBits)),
|
||||||
compact_as_type_path: Some(parse_quote!(#crate_path::ext::codec::CompactAs)),
|
compact_as_type_path,
|
||||||
compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
|
compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
|
||||||
insert_codec_attributes: true,
|
insert_codec_attributes,
|
||||||
alloc_crate_path: AllocCratePath::Custom(parse_quote!(#crate_path::alloc)),
|
alloc_crate_path: AllocCratePath::Custom(parse_quote!(#crate_path::alloc)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,19 +349,15 @@ fn default_derives(crate_path: &syn::Path) -> DerivesRegistry {
|
|||||||
let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
|
let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
|
||||||
let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
|
let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
|
||||||
|
|
||||||
let derives: [syn::Path; 5] = [
|
let derives: [syn::Path; 3] = [
|
||||||
parse_quote!(#crate_path::ext::scale_encode::EncodeAsType),
|
parse_quote!(#crate_path::ext::scale_encode::EncodeAsType),
|
||||||
parse_quote!(#crate_path::ext::scale_decode::DecodeAsType),
|
parse_quote!(#crate_path::ext::scale_decode::DecodeAsType),
|
||||||
parse_quote!(#crate_path::ext::codec::Encode),
|
|
||||||
parse_quote!(#crate_path::ext::codec::Decode),
|
|
||||||
parse_quote!(Debug),
|
parse_quote!(Debug),
|
||||||
];
|
];
|
||||||
|
|
||||||
let attributes: [syn::Attribute; 4] = [
|
let attributes: [syn::Attribute; 2] = [
|
||||||
parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]),
|
parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]),
|
||||||
parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]),
|
parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]),
|
||||||
parse_quote!(#[codec(crate = #crate_path::ext::codec)]),
|
|
||||||
parse_quote!(#[codec(dumb_trait_bound)]),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut derives_registry = DerivesRegistry::new();
|
let mut derives_registry = DerivesRegistry::new();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
//!
|
//!
|
||||||
//! // Build a storage query to access account information.
|
//! // Build a storage query to access account information.
|
||||||
//! let account = dev::alice().public_key().into();
|
//! let account = dev::alice().public_key().into();
|
||||||
//! let address = polkadot::storage().system().account(&account);
|
//! let address = polkadot::storage().system().account(account);
|
||||||
//!
|
//!
|
||||||
//! // We can validate that the address is compatible with the given metadata.
|
//! // We can validate that the address is compatible with the given metadata.
|
||||||
//! storage::validate(&address, &metadata).unwrap();
|
//! storage::validate(&address, &metadata).unwrap();
|
||||||
|
|||||||
@@ -3,14 +3,10 @@
|
|||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use super::utils::hash_bytes;
|
use super::utils::hash_bytes;
|
||||||
use crate::{
|
use crate::error::{Error, MetadataError, StorageAddressError};
|
||||||
error::{Error, MetadataError, StorageAddressError},
|
|
||||||
utils::{Encoded, Static},
|
|
||||||
};
|
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use derive_where::derive_where;
|
use scale_decode::{DecodeAsType, visitor::IgnoreVisitor};
|
||||||
use scale_decode::visitor::IgnoreVisitor;
|
|
||||||
use scale_encode::EncodeAsType;
|
use scale_encode::EncodeAsType;
|
||||||
use scale_info::{PortableRegistry, TypeDef};
|
use scale_info::{PortableRegistry, TypeDef};
|
||||||
use scale_value::Value;
|
use scale_value::Value;
|
||||||
@@ -164,41 +160,27 @@ impl StorageKey for () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A storage key for static encoded values.
|
/// A storage key used as part of the static codegen.
|
||||||
/// The original value is only present at construction, but can be decoded from the contained bytes.
|
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq)]
|
||||||
#[derive_where(Clone, Debug, PartialOrd, PartialEq, Eq)]
|
pub struct StaticStorageKey<K> {
|
||||||
pub struct StaticStorageKey<K: ?Sized> {
|
key: K,
|
||||||
bytes: Static<Encoded>,
|
|
||||||
_marker: core::marker::PhantomData<K>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: codec::Encode + ?Sized> StaticStorageKey<K> {
|
impl<K> StaticStorageKey<K> {
|
||||||
/// Creates a new static storage key
|
/// Creates a new static storage key.
|
||||||
pub fn new(key: &K) -> Self {
|
pub fn new(key: K) -> Self {
|
||||||
StaticStorageKey {
|
StaticStorageKey { key }
|
||||||
bytes: Static(Encoded(key.encode())),
|
|
||||||
_marker: core::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: codec::Decode> StaticStorageKey<K> {
|
impl<K: Clone> StaticStorageKey<K> {
|
||||||
/// Decodes the encoded inner bytes into the type `K`.
|
/// Returns the decoded storage key.
|
||||||
pub fn decoded(&self) -> Result<K, Error> {
|
pub fn into_key(self) -> K {
|
||||||
let decoded = K::decode(&mut self.bytes())?;
|
self.key
|
||||||
Ok(decoded)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: ?Sized> StaticStorageKey<K> {
|
impl<K: EncodeAsType + DecodeAsType> StorageKey for StaticStorageKey<K> {
|
||||||
/// Returns the scale-encoded bytes that make up this key
|
|
||||||
pub fn bytes(&self) -> &[u8] {
|
|
||||||
&self.bytes.0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: The ?Sized bound is necessary to support e.g. `StorageKey<[u8]>`.
|
|
||||||
impl<K: ?Sized> StorageKey for StaticStorageKey<K> {
|
|
||||||
fn encode_storage_key(
|
fn encode_storage_key(
|
||||||
&self,
|
&self,
|
||||||
bytes: &mut Vec<u8>,
|
bytes: &mut Vec<u8>,
|
||||||
@@ -206,7 +188,7 @@ impl<K: ?Sized> StorageKey for StaticStorageKey<K> {
|
|||||||
types: &PortableRegistry,
|
types: &PortableRegistry,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let (hasher, ty_id) = hashers.next_or_err()?;
|
let (hasher, ty_id) = hashers.next_or_err()?;
|
||||||
let encoded_value = self.bytes.encode_as_type(ty_id, types)?;
|
let encoded_value = self.key.encode_as_type(ty_id, types)?;
|
||||||
hash_bytes(&encoded_value, hasher, bytes);
|
hash_bytes(&encoded_value, hasher, bytes);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -227,11 +209,9 @@ impl<K: ?Sized> StorageKey for StaticStorageKey<K> {
|
|||||||
return Err(StorageAddressError::HasherCannotReconstructKey { ty_id, hasher }.into());
|
return Err(StorageAddressError::HasherCannotReconstructKey { ty_id, hasher }.into());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the key bytes.
|
// Decode and return the key.
|
||||||
let key = StaticStorageKey {
|
let key = K::decode_as_type(&mut &*key_bytes, ty_id, types)?;
|
||||||
bytes: Static(Encoded(key_bytes.to_vec())),
|
let key = StaticStorageKey { key };
|
||||||
_marker: core::marker::PhantomData::<K>,
|
|
||||||
};
|
|
||||||
Ok(key)
|
Ok(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,16 +442,16 @@ mod tests {
|
|||||||
T4C::decode_storage_key(&mut &bytes[..], &mut hashers.iter(), &types)
|
T4C::decode_storage_key(&mut &bytes[..], &mut hashers.iter(), &types)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(keys_a.1.decoded().unwrap(), 13);
|
assert_eq!(keys_a.1.into_key(), 13);
|
||||||
assert_eq!(keys_b.1.0.decoded().unwrap(), 13);
|
assert_eq!(keys_b.1.0.into_key(), 13);
|
||||||
assert_eq!(keys_c.0.1.decoded().unwrap(), 13);
|
assert_eq!(keys_c.0.1.into_key(), 13);
|
||||||
|
|
||||||
assert_eq!(keys_a.2.decoded().unwrap(), "Hello");
|
assert_eq!(keys_a.2.into_key(), "Hello");
|
||||||
assert_eq!(keys_b.1.1.decoded().unwrap(), "Hello");
|
assert_eq!(keys_b.1.1.into_key(), "Hello");
|
||||||
assert_eq!(keys_c.1.0.decoded().unwrap(), "Hello");
|
assert_eq!(keys_c.1.0.into_key(), "Hello");
|
||||||
assert_eq!(keys_a.3.decoded().unwrap(), era);
|
assert_eq!(keys_a.3.into_key(), era);
|
||||||
assert_eq!(keys_b.2.decoded().unwrap(), era);
|
assert_eq!(keys_b.2.into_key(), era);
|
||||||
assert_eq!(keys_c.1.1.decoded().unwrap(), era);
|
assert_eq!(keys_c.1.1.into_key(), era);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,8 +149,7 @@ impl PlatformRef for SubxtPlatform {
|
|||||||
|
|
||||||
let socket_future = async move {
|
let socket_future = async move {
|
||||||
tracing::debug!(target: LOG_TARGET, "Connecting to addr={addr}");
|
tracing::debug!(target: LOG_TARGET, "Connecting to addr={addr}");
|
||||||
WasmSocket::new(addr.as_str())
|
WasmSocket::new(addr.as_str()).map_err(|err| std::io::Error::other(err.to_string()))
|
||||||
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
future::ready(super::wasm_helpers::Stream(with_buffers::WithBuffers::new(
|
future::ready(super::wasm_helpers::Stream(with_buffers::WithBuffers::new(
|
||||||
|
|||||||
@@ -176,9 +176,7 @@ impl AsyncRead for WasmSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match inner.state {
|
match inner.state {
|
||||||
ConnectionState::Error => {
|
ConnectionState::Error => Poll::Ready(Err(io::Error::other("Socket error"))),
|
||||||
Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error")))
|
|
||||||
}
|
|
||||||
ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())),
|
ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())),
|
||||||
ConnectionState::Connecting => Poll::Pending,
|
ConnectionState::Connecting => Poll::Pending,
|
||||||
ConnectionState::Opened => {
|
ConnectionState::Opened => {
|
||||||
@@ -206,17 +204,12 @@ impl AsyncWrite for WasmSocket {
|
|||||||
inner.waker = Some(cx.waker().clone());
|
inner.waker = Some(cx.waker().clone());
|
||||||
|
|
||||||
match inner.state {
|
match inner.state {
|
||||||
ConnectionState::Error => {
|
ConnectionState::Error => Poll::Ready(Err(io::Error::other("Socket error"))),
|
||||||
Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, "Socket error")))
|
|
||||||
}
|
|
||||||
ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())),
|
ConnectionState::Closed => Poll::Ready(Err(io::ErrorKind::BrokenPipe.into())),
|
||||||
ConnectionState::Connecting => Poll::Pending,
|
ConnectionState::Connecting => Poll::Pending,
|
||||||
ConnectionState::Opened => match self.socket.send_with_u8_array(buf) {
|
ConnectionState::Opened => match self.socket.send_with_u8_array(buf) {
|
||||||
Ok(()) => Poll::Ready(Ok(buf.len())),
|
Ok(()) => Poll::Ready(Ok(buf.len())),
|
||||||
Err(err) => Poll::Ready(Err(io::Error::new(
|
Err(err) => Poll::Ready(Err(io::Error::other(format!("Write error: {err:?}")))),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("Write error: {err:?}"),
|
|
||||||
))),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
use subxt::ext::codec::Compact;
|
use subxt::ext::codec::{Compact, Decode};
|
||||||
use subxt::ext::frame_metadata::RuntimeMetadataPrefixed;
|
use subxt::ext::frame_metadata::RuntimeMetadataPrefixed;
|
||||||
use subxt::{OnlineClient, PolkadotConfig};
|
use subxt::{OnlineClient, PolkadotConfig};
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let runtime_apis = api.runtime_api().at_latest().await?;
|
let runtime_apis = api.runtime_api().at_latest().await?;
|
||||||
|
|
||||||
// Ask for metadata and decode it:
|
// Ask for metadata and decode it:
|
||||||
let (_, meta): (Compact<u32>, RuntimeMetadataPrefixed) =
|
let result_bytes = runtime_apis.call_raw("Metadata_metadata", None).await?;
|
||||||
runtime_apis.call_raw("Metadata_metadata", None).await?;
|
let (_, meta): (Compact<u32>, RuntimeMetadataPrefixed) = Decode::decode(&mut &*result_bytes)?;
|
||||||
|
|
||||||
println!("{meta:?}");
|
println!("{meta:?}");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use subxt_signer::sr25519::dev;
|
|||||||
runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale",
|
runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale",
|
||||||
derive_for_type(
|
derive_for_type(
|
||||||
path = "staging_xcm::v3::multilocation::MultiLocation",
|
path = "staging_xcm::v3::multilocation::MultiLocation",
|
||||||
derive = "Clone",
|
derive = "Clone, codec::Encode",
|
||||||
recursive
|
recursive
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
// Build a storage query to access account information.
|
// Build a storage query to access account information.
|
||||||
let account = dev::alice().public_key().into();
|
let account = dev::alice().public_key().into();
|
||||||
let storage_query = polkadot::storage().system().account(&account);
|
let storage_query = polkadot::storage().system().account(account);
|
||||||
|
|
||||||
// Use that query to `fetch` a result. This returns an `Option<_>`, which will be
|
// Use that query to `fetch` a result. This returns an `Option<_>`, which will be
|
||||||
// `None` if no value exists at the given address. You can also use `fetch_default`
|
// `None` if no value exists at the given address. You can also use `fetch_default`
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
// Build a storage query to iterate over open multisig extrinsics from
|
// Build a storage query to iterate over open multisig extrinsics from
|
||||||
// new_multisig_1.multisig which is the AccountId of the alice + bob multisig account
|
// new_multisig_1.multisig which is the AccountId of the alice + bob multisig account
|
||||||
let alice_bob_account_id = &new_multisig_1.multisig;
|
let alice_bob_account_id = new_multisig_1.multisig;
|
||||||
let storage_query = polkadot::storage()
|
let storage_query = polkadot::storage()
|
||||||
.multisig()
|
.multisig()
|
||||||
.multisigs_iter1(alice_bob_account_id);
|
.multisigs_iter1(alice_bob_account_id);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
//! pub mod polkadot {}
|
//! pub mod polkadot {}
|
||||||
//!
|
//!
|
||||||
//! let account = dev::alice().public_key().into();
|
//! let account = dev::alice().public_key().into();
|
||||||
//! let storage_query = polkadot::storage().system().account(&account);
|
//! let storage_query = polkadot::storage().system().account(account);
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Alternately, we can dynamically construct a storage query. This will not be type checked or
|
//! Alternately, we can dynamically construct a storage query. This will not be type checked or
|
||||||
|
|||||||
@@ -4,12 +4,11 @@
|
|||||||
|
|
||||||
use super::Payload;
|
use super::Payload;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{BackendExt, BlockRef},
|
backend::BlockRef,
|
||||||
client::OnlineClientT,
|
client::OnlineClientT,
|
||||||
config::{Config, HashFor},
|
config::{Config, HashFor},
|
||||||
error::Error,
|
error::Error,
|
||||||
};
|
};
|
||||||
use codec::Decode;
|
|
||||||
use derive_where::derive_where;
|
use derive_where::derive_where;
|
||||||
use std::{future::Future, marker::PhantomData};
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
@@ -45,20 +44,21 @@ where
|
|||||||
subxt_core::runtime_api::validate(payload, &self.client.metadata()).map_err(Into::into)
|
subxt_core::runtime_api::validate(payload, &self.client.metadata()).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a raw runtime API call.
|
/// Execute a raw runtime API call. This returns the raw bytes representing the result
|
||||||
pub fn call_raw<'a, Res: Decode>(
|
/// of this call. The caller is responsible for decoding the result.
|
||||||
|
pub fn call_raw<'a>(
|
||||||
&self,
|
&self,
|
||||||
function: &'a str,
|
function: &'a str,
|
||||||
call_parameters: Option<&'a [u8]>,
|
call_parameters: Option<&'a [u8]>,
|
||||||
) -> impl Future<Output = Result<Res, Error>> + use<'a, Res, Client, T> {
|
) -> impl Future<Output = Result<Vec<u8>, Error>> + use<'a, Client, T> {
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
let block_hash = self.block_ref.hash();
|
let block_hash = self.block_ref.hash();
|
||||||
// Ensure that the returned future doesn't have a lifetime tied to api.runtime_api(),
|
// Ensure that the returned future doesn't have a lifetime tied to api.runtime_api(),
|
||||||
// which is a temporary thing we'll be throwing away quickly:
|
// which is a temporary thing we'll be throwing away quickly:
|
||||||
async move {
|
async move {
|
||||||
let data: Res = client
|
let data = client
|
||||||
.backend()
|
.backend()
|
||||||
.call_decoding(function, call_parameters, block_hash)
|
.call(function, call_parameters, block_hash)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ where
|
|||||||
/// let api = OnlineClient::<PolkadotConfig>::new().await.unwrap();
|
/// let api = OnlineClient::<PolkadotConfig>::new().await.unwrap();
|
||||||
///
|
///
|
||||||
/// // Address to a storage entry we'd like to access.
|
/// // Address to a storage entry we'd like to access.
|
||||||
/// let address = polkadot::storage().xcm_pallet().queries(&12345);
|
/// let address = polkadot::storage().xcm_pallet().queries(12345);
|
||||||
///
|
///
|
||||||
/// // Fetch just the keys, returning up to 10 keys.
|
/// // Fetch just the keys, returning up to 10 keys.
|
||||||
/// let value = api
|
/// let value = api
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use crate::{subxt_test, test_context, utils::consume_initial_blocks};
|
use crate::{subxt_test, test_context, utils::consume_initial_blocks};
|
||||||
use codec::{Compact, Encode};
|
use codec::{Compact, Decode, Encode};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|
||||||
#[cfg(fullclient)]
|
#[cfg(fullclient)]
|
||||||
@@ -160,13 +160,10 @@ async fn runtime_api_call() -> Result<(), subxt::Error> {
|
|||||||
let block = sub.next().await.unwrap()?;
|
let block = sub.next().await.unwrap()?;
|
||||||
let rt = block.runtime_api().await?;
|
let rt = block.runtime_api().await?;
|
||||||
|
|
||||||
// get metadata via state_call.
|
// get metadata via raw state_call.
|
||||||
let (_, meta1) = rt
|
let meta_bytes = rt.call_raw("Metadata_metadata", None).await?;
|
||||||
.call_raw::<(Compact<u32>, frame_metadata::RuntimeMetadataPrefixed)>(
|
let (_, meta1): (Compact<u32>, frame_metadata::RuntimeMetadataPrefixed) =
|
||||||
"Metadata_metadata",
|
Decode::decode(&mut &*meta_bytes)?;
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// get metadata via `state_getMetadata`.
|
// get metadata via `state_getMetadata`.
|
||||||
let meta2_bytes = rpc.state_get_metadata(Some(block.hash())).await?.into_raw();
|
let meta2_bytes = rpc.state_get_metadata(Some(block.hash())).await?.into_raw();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -220,7 +220,7 @@ async fn tx_call() {
|
|||||||
|
|
||||||
let info_addr = node_runtime::storage()
|
let info_addr = node_runtime::storage()
|
||||||
.contracts()
|
.contracts()
|
||||||
.contract_info_of(&contract);
|
.contract_info_of(contract.clone());
|
||||||
|
|
||||||
let contract_info = cxt
|
let contract_info = cxt
|
||||||
.client()
|
.client()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use crate::{node_runtime, subxt_test, test_context};
|
use crate::{node_runtime, subxt_test, test_context};
|
||||||
use codec::Encode;
|
use codec::{Decode, Encode};
|
||||||
use subxt::utils::AccountId32;
|
use subxt::utils::AccountId32;
|
||||||
use subxt_signer::sr25519::dev;
|
use subxt_signer::sr25519::dev;
|
||||||
|
|
||||||
@@ -81,17 +81,34 @@ async fn unchecked_extrinsic_encoding() -> Result<(), subxt::Error> {
|
|||||||
let mut encoded = tx_bytes.clone();
|
let mut encoded = tx_bytes.clone();
|
||||||
encoded.extend(len.encode());
|
encoded.extend(len.encode());
|
||||||
|
|
||||||
let expected_result: node_runtime::runtime_types::pallet_transaction_payment::types::FeeDetails<
|
// Use the raw API to manually build an expected result.
|
||||||
::core::primitive::u128,
|
let expected_result = {
|
||||||
> = api
|
let expected_result_bytes = api
|
||||||
.runtime_api()
|
.runtime_api()
|
||||||
.at_latest()
|
.at_latest()
|
||||||
.await?
|
.await?
|
||||||
.call_raw(
|
.call_raw(
|
||||||
"TransactionPaymentApi_query_fee_details",
|
"TransactionPaymentApi_query_fee_details",
|
||||||
Some(encoded.as_ref()),
|
Some(encoded.as_ref()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// manually decode, since our runtime types don't impl Decode by default.
|
||||||
|
let (inclusion_fee, tip): (Option<(u128, u128, u128)>, u128) =
|
||||||
|
Decode::decode(&mut &*expected_result_bytes)?;
|
||||||
|
|
||||||
|
// put the values into our generated type.
|
||||||
|
node_runtime::runtime_types::pallet_transaction_payment::types::FeeDetails {
|
||||||
|
inclusion_fee: inclusion_fee.map(|(base_fee, len_fee, adjusted_weight_fee)| {
|
||||||
|
node_runtime::runtime_types::pallet_transaction_payment::types::InclusionFee {
|
||||||
|
base_fee,
|
||||||
|
len_fee,
|
||||||
|
adjusted_weight_fee,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
tip,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Use the generated API to confirm the result with the raw call.
|
// Use the generated API to confirm the result with the raw call.
|
||||||
let runtime_api_call = node_runtime::apis()
|
let runtime_api_call = node_runtime::apis()
|
||||||
|
|||||||
@@ -72,15 +72,16 @@ async fn storage_n_mapish_key_is_properly_created() -> Result<(), subxt::Error>
|
|||||||
// This is what the generated code hashes a `session().key_owner(..)` key into:
|
// This is what the generated code hashes a `session().key_owner(..)` key into:
|
||||||
let actual_key = node_runtime::storage()
|
let actual_key = node_runtime::storage()
|
||||||
.session()
|
.session()
|
||||||
.key_owner(KeyTypeId([1, 2, 3, 4]), [5u8, 6, 7, 8]);
|
.key_owner(KeyTypeId([1, 2, 3, 4]), vec![5, 6, 7, 8]);
|
||||||
let actual_key_bytes = api.storage().address_bytes(&actual_key)?;
|
let actual_key_bytes = api.storage().address_bytes(&actual_key)?;
|
||||||
|
|
||||||
// Let's manually hash to what we assume it should be and compare:
|
// Let's manually hash to what we assume it should be and compare:
|
||||||
let expected_key_bytes = {
|
let expected_key_bytes = {
|
||||||
// Hash the prefix to the storage entry:
|
// Hash the prefix to the storage entry:
|
||||||
let mut bytes = sp_core::twox_128("Session".as_bytes()).to_vec();
|
let mut bytes = sp_core::twox_128("Session".as_bytes()).to_vec();
|
||||||
bytes.extend(&sp_core::twox_128("KeyOwner".as_bytes())[..]);
|
bytes.extend(&sp_core::twox_128("KeyOwner".as_bytes())[..]);
|
||||||
// Both keys, use twox64_concat hashers:
|
// Both keys, use twox64_concat hashers:
|
||||||
let key1 = KeyTypeId([1, 2, 3, 4]).encode();
|
let key1 = [1u8, 2, 3, 4].encode();
|
||||||
let key2 = vec![5u8, 6, 7, 8].encode();
|
let key2 = vec![5u8, 6, 7, 8].encode();
|
||||||
bytes.extend(sp_core::twox_64(&key1));
|
bytes.extend(sp_core::twox_64(&key1));
|
||||||
bytes.extend(&key1);
|
bytes.extend(&key1);
|
||||||
@@ -88,7 +89,6 @@ async fn storage_n_mapish_key_is_properly_created() -> Result<(), subxt::Error>
|
|||||||
bytes.extend(&key2);
|
bytes.extend(&key2);
|
||||||
bytes
|
bytes
|
||||||
};
|
};
|
||||||
dbg!(&expected_key_bytes);
|
|
||||||
|
|
||||||
assert_eq!(actual_key_bytes, expected_key_bytes);
|
assert_eq!(actual_key_bytes, expected_key_bytes);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -196,7 +196,6 @@ async fn storage_partial_lookup() -> Result<(), subxt::Error> {
|
|||||||
let mut approvals = Vec::new();
|
let mut approvals = Vec::new();
|
||||||
while let Some(Ok(kv)) = results.next().await {
|
while let Some(Ok(kv)) = results.next().await {
|
||||||
assert!(kv.key_bytes.starts_with(&addr_bytes));
|
assert!(kv.key_bytes.starts_with(&addr_bytes));
|
||||||
assert!(kv.keys.decoded().is_ok());
|
|
||||||
approvals.push(kv.value);
|
approvals.push(kv.value);
|
||||||
}
|
}
|
||||||
assert_eq!(approvals.len(), 1);
|
assert_eq!(approvals.len(), 1);
|
||||||
|
|||||||
@@ -107,9 +107,8 @@ async fn runtime_api_call(api: &Client) -> Result<(), subxt::Error> {
|
|||||||
let rt = block.runtime_api().await?;
|
let rt = block.runtime_api().await?;
|
||||||
|
|
||||||
// get metadata via state_call. if it decodes ok, it's probably all good.
|
// get metadata via state_call. if it decodes ok, it's probably all good.
|
||||||
let _ = rt
|
let result_bytes = rt.call_raw("Metadata_metadata", None).await?;
|
||||||
.call_raw::<(Compact<u32>, Metadata)>("Metadata_metadata", None)
|
let (_, _meta): (Compact<u32>, Metadata) = codec::Decode::decode(&mut &*result_bytes)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
tracing::trace!("Made runtime API call in {:?}\n", now.elapsed());
|
tracing::trace!("Made runtime API call in {:?}\n", now.elapsed());
|
||||||
|
|
||||||
|
|||||||
@@ -73,10 +73,7 @@ impl SubstrateNodeBuilder {
|
|||||||
pub fn spawn(mut self) -> Result<SubstrateNode, Error> {
|
pub fn spawn(mut self) -> Result<SubstrateNode, Error> {
|
||||||
// Try to spawn the binary at each path, returning the
|
// Try to spawn the binary at each path, returning the
|
||||||
// first "ok" or last error that we encountered.
|
// first "ok" or last error that we encountered.
|
||||||
let mut res = Err(io::Error::new(
|
let mut res = Err(io::Error::other("No binary path provided"));
|
||||||
io::ErrorKind::Other,
|
|
||||||
"No binary path provided",
|
|
||||||
));
|
|
||||||
|
|
||||||
let path = Command::new("mktemp")
|
let path = Command::new("mktemp")
|
||||||
.arg("-d")
|
.arg("-d")
|
||||||
|
|||||||
Reference in New Issue
Block a user