Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,7 @@ opt-level = 2
opt-level = 2
[profile.test.package.smoldot]
opt-level = 2

[patch.crates-io]
frame-decode = { path = "../frame-decode" }
scale-info-legacy = { path = "../scale-info-legacy" }
2 changes: 1 addition & 1 deletion codegen/src/api/pallet_view_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn generate_pallet_view_function(

// Path to the actual type we'll have generated for this input.
let type_path = type_gen
.resolve_type_path(input.ty)
.resolve_type_path(input.id)
.expect("view function input type is in metadata; qed")
.to_token_stream(type_gen.settings());

Expand Down
2 changes: 1 addition & 1 deletion codegen/src/api/runtime_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fn generate_runtime_api(

// Generate alias for runtime type.
let ty = type_gen
.resolve_type_path(input.ty)
.resolve_type_path(input.id)
.expect("runtime api input type is in metadata; qed")
.to_token_stream(type_gen.settings());
let aliased_param = quote!( pub type #alias_name = #ty; );
Expand Down
76 changes: 15 additions & 61 deletions codegen/src/api/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
use heck::{ToSnakeCase as _, ToUpperCamelCase};
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream};
use quote::{format_ident, quote};
use scale_info::TypeDef;
use scale_typegen::TypeGenerator;
use subxt_metadata::{
PalletMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher,
PalletMetadata, StorageEntryMetadata, StorageHasher,
};

use super::CodegenError;
Expand Down Expand Up @@ -68,7 +67,7 @@ fn generate_storage_entry_fns(
crate_path: &syn::Path,
) -> Result<(TokenStream2, TokenStream2), CodegenError> {
let snake_case_name = storage_entry.name().to_snake_case();
let storage_entry_ty = storage_entry.entry_type().value_ty();
let storage_entry_ty = storage_entry.value_ty();
let storage_entry_value_ty = type_gen
.resolve_type_path(storage_entry_ty)
.expect("storage type is in metadata; qed")
Expand Down Expand Up @@ -105,64 +104,18 @@ fn generate_storage_entry_fns(
}
};

let keys: Vec<MapEntryKey> = match storage_entry.entry_type() {
StorageEntryType::Plain(_) => vec![],
StorageEntryType::Map {
key_ty, hashers, ..
} => {
if hashers.len() == 1 {
// If there's exactly 1 hasher, then we have a plain StorageMap. We can't
// break the key down (even if it's a tuple) because the hasher applies to
// the whole key.
vec![map_entry_key(0, *key_ty, hashers[0])]
} else {
// If there are multiple hashers, then we have a StorageDoubleMap or StorageNMap.
// We expect the key type to be tuple, and we will return a MapEntryKey for each
// key in the tuple.
let hasher_count = hashers.len();
let tuple = match &type_gen
.resolve_type(*key_ty)
.expect("key type should be present")
.type_def
{
TypeDef::Tuple(tuple) => tuple,
_ => {
return Err(CodegenError::InvalidStorageHasherCount {
storage_entry_name: storage_entry.name().to_owned(),
key_count: 1,
hasher_count,
});
}
};

// We should have the same number of hashers and keys.
let key_count = tuple.fields.len();
if hasher_count != key_count {
return Err(CodegenError::InvalidStorageHasherCount {
storage_entry_name: storage_entry.name().to_owned(),
key_count,
hasher_count,
});
}

// Collect them together.
tuple
.fields
.iter()
.zip(hashers)
.enumerate()
.map(|(idx, (field, hasher))| map_entry_key(idx, field.id, *hasher))
.collect()
}
}
};
let keys: Vec<MapEntryKey> = storage_entry
.keys()
.enumerate()
.map(|(idx, key)| map_entry_key(idx, key.key_id, key.hasher))
.collect();

let pallet_name = pallet.name();
let storage_name = storage_entry.name();
let Some(storage_hash) = pallet.storage_hash(storage_name) else {
let entry_name = storage_entry.name();
let Some(storage_hash) = pallet.storage_hash(entry_name) else {
return Err(CodegenError::MissingStorageMetadata(
pallet_name.into(),
storage_name.into(),
entry_name.into(),
));
};

Expand All @@ -173,9 +126,10 @@ fn generate_storage_entry_fns(
.then_some(quote! { #( #[doc = #docs ] )* })
.unwrap_or_default();

let is_defaultable_type = match storage_entry.modifier() {
StorageEntryModifier::Default => quote!(#crate_path::utils::Yes),
StorageEntryModifier::Optional => quote!(()),
let is_defaultable_type = if storage_entry.default_value().is_some() {
quote!(#crate_path::utils::Yes)
} else {
quote!(())
};

// Note: putting `#crate_path::storage::address::StaticStorageKey` into this variable is necessary
Expand Down Expand Up @@ -269,7 +223,7 @@ fn generate_storage_entry_fns(
> {
#crate_path::storage::address::StaticAddress::new_static(
#pallet_name,
#storage_name,
#entry_name,
#keys,
[#(#storage_hash,)*]
)
Expand Down
2 changes: 2 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ std = [
"tracing/std",
"impl-serde/std",
"primitive-types/std",
"sp-core/std",
"sp-keyring/std",
"sp-crypto-hashing/std",
]

Expand Down
25 changes: 18 additions & 7 deletions core/src/blocks/extrinsic_transaction_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use crate::config::transaction_extensions::{
ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce,
};
use crate::dynamic::Value;
use crate::{Metadata, config::Config, error::Error};
use crate::{Metadata, config::Config};
use crate::error::ExtrinsicError;
use frame_decode::extrinsics::ExtrinsicExtensions;
use scale_decode::DecodeAsType;

Expand Down Expand Up @@ -50,7 +51,7 @@ impl<'a, T: Config> ExtrinsicTransactionExtensions<'a, T> {
/// Searches through all signed extensions to find a specific one.
/// If the Signed Extension is not found `Ok(None)` is returned.
/// If the Signed Extension is found but decoding failed `Err(_)` is returned.
pub fn find<S: TransactionExtension<T>>(&self) -> Result<Option<S::Decoded>, Error> {
pub fn find<S: TransactionExtension<T>>(&self) -> Result<Option<S::Decoded>, ExtrinsicError> {
for ext in self.iter() {
match ext.as_signed_extension::<S>() {
// We found a match; return it:
Expand Down Expand Up @@ -117,12 +118,15 @@ impl<'a, T: Config> ExtrinsicTransactionExtension<'a, T> {
}

/// Signed Extension as a [`scale_value::Value`]
pub fn value(&self) -> Result<Value<u32>, Error> {
pub fn value(&self) -> Result<Value<u32>, ExtrinsicError> {
let value = scale_value::scale::decode_as_type(
&mut &self.bytes[..],
self.ty_id,
self.metadata.types(),
)?;
).map_err(|e| ExtrinsicError::CouldNotDecodeTransactionExtension {
name: self.identifier.to_owned(),
error: e.into()
})?;
Ok(value)
}

Expand All @@ -131,15 +135,22 @@ impl<'a, T: Config> ExtrinsicTransactionExtension<'a, T> {
/// decode with.
pub fn as_signed_extension<S: TransactionExtension<T>>(
&self,
) -> Result<Option<S::Decoded>, Error> {
) -> Result<Option<S::Decoded>, ExtrinsicError> {
if !S::matches(self.identifier, self.ty_id, self.metadata.types()) {
return Ok(None);
}
self.as_type::<S::Decoded>().map(Some)
}

fn as_type<E: DecodeAsType>(&self) -> Result<E, Error> {
let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())?;
fn as_type<E: DecodeAsType>(&self) -> Result<E, ExtrinsicError> {
let value = E::decode_as_type(
&mut &self.bytes[..],
self.ty_id,
self.metadata.types()
).map_err(|e| ExtrinsicError::CouldNotDecodeTransactionExtension {
name: self.identifier.to_owned(),
error: e.into()
})?;
Ok(value)
}
}
Loading
Loading