Commit d74fde52 authored by Alexey Kalita's avatar Alexey Kalita
Browse files

get back max-encoded-len

parent 45613d57
Pipeline #2305 failed with stage
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
......@@ -154,6 +156,12 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "arrayvec"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
[[package]]
name = "asn1_der"
version = "0.6.3"
......@@ -1787,7 +1795,7 @@ name = "frame-support-procedural-tools"
version = "3.0.0"
dependencies = [
"frame-support-procedural-tools-derive",
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"syn",
......@@ -2557,9 +2565,9 @@ dependencies = [
[[package]]
name = "impl-codec"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df170efa359aebdd5cb7fe78edcc67107748e4737bdca8a8fb40d15ea7a877ed"
checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443"
dependencies = [
"parity-scale-codec",
]
......@@ -2734,7 +2742,7 @@ version = "15.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99a847f9ec7bb52149b2786a17c9cb260d6effc6b8eeb8c16b343a487a7563a3"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"syn",
......@@ -3510,6 +3518,29 @@ dependencies = [
"rawpointer",
]
[[package]]
name = "max-encoded-len"
version = "3.0.0"
dependencies = [
"frame-support",
"impl-trait-for-tuples",
"max-encoded-len-derive",
"parity-scale-codec",
"primitive-types 0.10.1",
"rustversion",
"trybuild",
]
[[package]]
name = "max-encoded-len-derive"
version = "3.0.0"
dependencies = [
"proc-macro-crate 1.0.0",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "maybe-uninit"
version = "2.0.0"
......@@ -3734,7 +3765,7 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85ee3c48cb9d9b275ad967a0e96715badc13c6029adb92f34fa17b9ff28fd81f"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro-error",
"proc-macro2",
"quote",
......@@ -5176,7 +5207,7 @@ dependencies = [
name = "pallet-staking-reward-curve"
version = "3.0.0"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"sp-runtime",
......@@ -5379,24 +5410,25 @@ dependencies = [
[[package]]
name = "parity-scale-codec"
version = "2.0.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75c823fdae1bb5ff5708ee61a62697e6296175dc671710876871c853f48592b3"
checksum = "8975095a2a03bbbdc70a74ab11a4f76a6d0b84680d87c68d722531b0ac28e8a9"
dependencies = [
"arrayvec 0.5.2",
"arrayvec 0.7.1",
"bitvec",
"byte-slice-cast",
"impl-trait-for-tuples",
"parity-scale-codec-derive",
"serde",
]
[[package]]
name = "parity-scale-codec-derive"
version = "2.0.0"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9029e65297c7fd6d7013f0579e193ec2b34ae78eabca854c9417504ad8a2d214"
checksum = "40dbbfef7f0a1143c5b06e0d76a6278e25dac0bc1af4be51a0fbb73f07e7ad09"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 1.0.0",
"proc-macro2",
"quote",
"syn",
......@@ -5438,7 +5470,7 @@ dependencies = [
"impl-trait-for-tuples",
"parity-util-mem-derive",
"parking_lot 0.11.1",
"primitive-types",
"primitive-types 0.9.0",
"smallvec 1.6.1",
"winapi 0.3.9",
]
......@@ -5877,6 +5909,17 @@ dependencies = [
"uint",
]
[[package]]
name = "primitive-types"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373"
dependencies = [
"fixed-hash",
"impl-codec",
"uint",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
......@@ -5886,6 +5929,16 @@ dependencies = [
"toml",
]
[[package]]
name = "proc-macro-crate"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92"
dependencies = [
"thiserror",
"toml",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
......@@ -6646,7 +6699,7 @@ dependencies = [
name = "sc-chain-spec-derive"
version = "3.0.0"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"syn",
......@@ -7696,7 +7749,7 @@ dependencies = [
name = "sc-tracing-proc-macro"
version = "3.0.0"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"syn",
......@@ -8170,7 +8223,7 @@ name = "sp-api-proc-macro"
version = "3.0.0"
dependencies = [
"blake2-rfc",
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"syn",
......@@ -8226,7 +8279,7 @@ dependencies = [
"integer-sqrt",
"num-traits",
"parity-scale-codec",
"primitive-types",
"primitive-types 0.9.0",
"rand 0.7.3",
"serde",
"serde_json",
......@@ -8241,7 +8294,7 @@ dependencies = [
"honggfuzz",
"num-bigint",
"num-traits",
"primitive-types",
"primitive-types 0.9.0",
"sp-arithmetic",
]
......@@ -8417,7 +8470,7 @@ dependencies = [
"parity-util-mem",
"parking_lot 0.11.1",
"pretty_assertions",
"primitive-types",
"primitive-types 0.9.0",
"rand 0.7.3",
"rand_chacha 0.2.2",
"regex",
......@@ -8576,7 +8629,7 @@ dependencies = [
name = "sp-npos-elections-compact"
version = "3.0.0"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"syn",
......@@ -8648,7 +8701,7 @@ version = "3.0.0"
dependencies = [
"impl-trait-for-tuples",
"parity-scale-codec",
"primitive-types",
"primitive-types 0.9.0",
"rustversion",
"sp-core",
"sp-externalities",
......@@ -8669,7 +8722,7 @@ name = "sp-runtime-interface-proc-macro"
version = "3.0.0"
dependencies = [
"Inflector",
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"proc-macro2",
"quote",
"syn",
......@@ -9247,7 +9300,7 @@ dependencies = [
name = "substrate-test-utils-derive"
version = "0.9.0"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 0.1.5",
"quote",
"syn",
]
......@@ -9362,18 +9415,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.23"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.23"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
dependencies = [
"proc-macro2",
"quote",
......@@ -9899,9 +9952,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "trybuild"
version = "1.0.39"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c9594b802f041389d2baac680663573dde3103bb4a4926d61d6aba689465978"
checksum = "1768998d9a3b179411618e377dbb134c58a88cda284b0aa71c42c40660127d46"
dependencies = [
"dissimilar",
"glob",
......
......@@ -119,6 +119,7 @@ members = [
"frame/tips",
"frame/utility",
"frame/vesting",
"max-encoded-len",
"primitives/allocator",
"primitives/api",
"primitives/api/proc-macro",
......
[package]
name = "max-encoded-len"
version = "3.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/substrate/"
description = "Trait MaxEncodedLen bounds the max encoded length of an item."
[dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
impl-trait-for-tuples = "0.2.1"
max-encoded-len-derive = { package = "max-encoded-len-derive", version = "3.0.0", path = "derive", default-features = false, optional = true }
primitive-types = { version = "0.10.0", default-features = false, features = ["codec"] }
[dev-dependencies]
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive" ] }
frame-support = { path = "../frame/support" }
rustversion = "1.0.4"
trybuild = "1.0.42"
[features]
default = [
"derive",
"std",
]
derive = [
"max-encoded-len-derive",
]
std = [
"codec/std",
"max-encoded-len-derive/std",
"primitive-types/std",
]
[package]
name = "max-encoded-len-derive"
version = "3.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/substrate/"
description = "Derive support for MaxEncodedLen"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "1.0.6"
proc-macro-crate = "1.0.0"
quote = "1.0.3"
syn = { version = "1.0.58", features = ["full"] }
[features]
default = ["std"]
std = []
// This file is part of Substrate.
// Copyright (C) 2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use quote::{quote, quote_spanned};
use syn::{
Data, DeriveInput, Error, Fields, GenericParam, Generics, Meta, TraitBound, Type,
TypeParamBound, parse_quote, spanned::Spanned,
};
use proc_macro_crate::{crate_name, FoundCrate};
use proc_macro2::{Ident, Span};
/// Generate the crate access for the crate using 2018 syntax.
fn generate_crate_access_2018(def_crate: &str) -> Result<syn::Ident, Error> {
match crate_name(def_crate) {
Ok(FoundCrate::Itself) => {
let name = def_crate.to_string().replace("-", "_");
Ok(syn::Ident::new(&name, Span::call_site()))
},
Ok(FoundCrate::Name(name)) => {
Ok(Ident::new(&name, Span::call_site()))
},
Err(e) => {
Err(Error::new(Span::call_site(), e))
}
}
}
/// Derive `MaxEncodedLen`.
#[proc_macro_derive(MaxEncodedLen, attributes(max_encoded_len_crate))]
pub fn derive_max_encoded_len(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input: DeriveInput = match syn::parse(input) {
Ok(input) => input,
Err(e) => return e.to_compile_error().into(),
};
let mel_trait = match max_encoded_len_trait(&input) {
Ok(mel_trait) => mel_trait,
Err(e) => return e.to_compile_error().into(),
};
let name = &input.ident;
let generics = add_trait_bounds(input.generics, mel_trait.clone());
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let data_expr = data_length_expr(&input.data);
quote::quote!(
const _: () = {
impl #impl_generics #mel_trait for #name #ty_generics #where_clause {
fn max_encoded_len() -> usize {
#data_expr
}
}
};
)
.into()
}
fn max_encoded_len_trait(input: &DeriveInput) -> syn::Result<TraitBound> {
let mel = {
const EXPECT_LIST: &str = "expect: #[max_encoded_len_crate(path::to::crate)]";
const EXPECT_PATH: &str = "expect: path::to::crate";
macro_rules! return_err {
($wrong_style:expr, $err:expr) => {
return Err(Error::new($wrong_style.span(), $err))
};
}
let mut mel_crates = Vec::with_capacity(2);
mel_crates.extend(input
.attrs
.iter()
.filter(|attr| attr.path == parse_quote!(max_encoded_len_crate))
.take(2)
.map(|attr| {
let meta_list = match attr.parse_meta()? {
Meta::List(meta_list) => meta_list,
Meta::Path(wrong_style) => return_err!(wrong_style, EXPECT_LIST),
Meta::NameValue(wrong_style) => return_err!(wrong_style, EXPECT_LIST),
};
if meta_list.nested.len() != 1 {
return_err!(meta_list, "expected exactly 1 item");
}
let first_nested =
meta_list.nested.into_iter().next().expect("length checked above");
let meta = match first_nested {
syn::NestedMeta::Lit(l) => {
return_err!(l, "expected a path item, not a literal")
}
syn::NestedMeta::Meta(meta) => meta,
};
let path = match meta {
Meta::Path(path) => path,
Meta::List(ref wrong_style) => return_err!(wrong_style, EXPECT_PATH),
Meta::NameValue(ref wrong_style) => return_err!(wrong_style, EXPECT_PATH),
};
Ok(path)
})
.collect::<Result<Vec<_>, _>>()?);
// we have to return `Result<Ident, Error>` here in order to satisfy the trait
// bounds for `.or_else` for `generate_crate_access_2018`, even though `Option<Ident>`
// would be more natural in this circumstance.
match mel_crates.len() {
0 => Err(Error::new(
input.span(),
"this error is spurious and swallowed by the or_else below",
)),
1 => Ok(mel_crates.into_iter().next().expect("length is checked")),
_ => return_err!(mel_crates[1], "duplicate max_encoded_len_crate definition"),
}
}
.or_else(|_| generate_crate_access_2018("max-encoded-len").map(|ident| ident.into()))?;
Ok(parse_quote!(#mel::MaxEncodedLen))
}
// Add a bound `T: MaxEncodedLen` to every type parameter T.
fn add_trait_bounds(mut generics: Generics, mel_trait: TraitBound) -> Generics {
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(TypeParamBound::Trait(mel_trait.clone()));
}
}
generics
}
/// generate an expression to sum up the max encoded length from several fields
fn fields_length_expr(fields: &Fields) -> proc_macro2::TokenStream {
let type_iter: Box<dyn Iterator<Item = &Type>> = match fields {
Fields::Named(ref fields) => Box::new(fields.named.iter().map(|field| &field.ty)),
Fields::Unnamed(ref fields) => Box::new(fields.unnamed.iter().map(|field| &field.ty)),
Fields::Unit => Box::new(std::iter::empty()),
};
// expands to an expression like
//
// 0
// .saturating_add(<type of first field>::max_encoded_len())
// .saturating_add(<type of second field>::max_encoded_len())
//
// We match the span of each field to the span of the corresponding
// `max_encoded_len` call. This way, if one field's type doesn't implement
// `MaxEncodedLen`, the compiler's error message will underline which field
// caused the issue.
let expansion = type_iter.map(|ty| {
quote_spanned! {
ty.span() => .saturating_add(<#ty>::max_encoded_len())
}
});
quote! {
0_usize #( #expansion )*
}
}
// generate an expression to sum up the max encoded length of each field
fn data_length_expr(data: &Data) -> proc_macro2::TokenStream {
match *data {
Data::Struct(ref data) => fields_length_expr(&data.fields),
Data::Enum(ref data) => {
// We need an expression expanded for each variant like
//
// 0
// .max(<variant expression>)
// .max(<variant expression>)
// .saturating_add(1)
//
// The 1 derives from the discriminant; see
// https://github.com/paritytech/parity-scale-codec/
// blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/derive/src/encode.rs#L211-L216
//
// Each variant expression's sum is computed the way an equivalent struct's would be.
let expansion = data.variants.iter().map(|variant| {
let variant_expression = fields_length_expr(&variant.fields);
quote! {
.max(#variant_expression)
}
});
quote! {
0_usize #( #expansion )* .saturating_add(1)
}
}
Data::Union(ref data) => {
// https://github.com/paritytech/parity-scale-codec/
// blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/derive/src/encode.rs#L290-L293
Error::new(data.union_token.span(), "Union types are not supported").to_compile_error()
}
}
}
// This file is part of Substrate.
// Copyright (C) 2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! `trait MaxEncodedLen` bounds the max encoded length of items.
#![cfg_attr(not(feature = "std"), no_std)]
use codec::{Compact, Encode};
use impl_trait_for_tuples::impl_for_tuples;
use core::{mem, marker::PhantomData};
use primitive_types::{H160, H256, H512};
/// Derive macro for `MaxEncodedLen`.
///
/// ```
/// # use max_encoded_len::MaxEncodedLen;
/// # use codec::Encode;
/// #[derive(Encode, MaxEncodedLen)]
/// struct Example;
/// ```
///
/// Sometimes the `MaxEncodedLen` trait and macro are accessed without explicitly importing its
/// crate, notably via the `frame_support::max_encoded_len` re-binding. In these circumstances,
/// the derive macro needs some help to understand where its crate should be:
///
/// ```
/// # use codec::Encode;
/// use frame_support::max_encoded_len::MaxEncodedLen;
///
/// #[derive(Encode, MaxEncodedLen)]
/// #[max_encoded_len_crate(frame_support::max_encoded_len)]
/// struct Example;
/// ```
#[cfg(feature = "derive")]
pub use max_encoded_len_derive::MaxEncodedLen;
/// Items implementing `MaxEncodedLen` have a statically known maximum encoded size.
///
/// Some containers, such as `BoundedVec`, have enforced size limits and this trait
/// can be implemented accurately. Other containers, such as `StorageMap`, do not have enforced size
/// limits. For those containers, it is necessary to make a documented assumption about the maximum
/// usage, and compute the max encoded length based on that assumption.
pub trait MaxEncodedLen: Encode {
/// Upper bound, in bytes, of the maximum encoded size of this item.
fn max_encoded_len() -> usize;
}
macro_rules! impl_primitives {
( $($t:ty),+ ) => {
$(
impl MaxEncodedLen for $t {
fn max_encoded_len() -> usize {
mem::size_of::<$t>()
}
}