--- a/crates/evm-coder-macros/src/lib.rs +++ b/crates/evm-coder-macros/src/lib.rs @@ -211,6 +211,10 @@ pub fn solidity(_args: TokenStream, stream: TokenStream) -> TokenStream { stream } +#[proc_macro_attribute] +pub fn weight(_args: TokenStream, stream: TokenStream) -> TokenStream { + stream +} #[proc_macro_derive(ToLog, attributes(indexed))] pub fn to_log(value: TokenStream) -> TokenStream { --- a/crates/evm-coder-macros/src/solidity_interface.rs +++ b/crates/evm-coder-macros/src/solidity_interface.rs @@ -30,11 +30,11 @@ }) } - fn expand_call_def(&self) -> proc_macro2::TokenStream { + fn expand_call_def(&self, gen_ref: &proc_macro2::TokenStream) -> proc_macro2::TokenStream { let name = &self.name; let pascal_call_name = &self.pascal_call_name; quote! { - #name(#pascal_call_name) + #name(#pascal_call_name #gen_ref) } } @@ -45,18 +45,32 @@ } } - fn expand_supports_interface(&self) -> proc_macro2::TokenStream { + fn expand_supports_interface( + &self, + generics: &proc_macro2::TokenStream, + ) -> proc_macro2::TokenStream { let pascal_call_name = &self.pascal_call_name; quote! { - #pascal_call_name::supports_interface(interface_id) + <#pascal_call_name #generics>::supports_interface(interface_id) + } + } + + fn expand_variant_weight(&self) -> proc_macro2::TokenStream { + let name = &self.name; + quote! { + Self::#name(call) => call.weight() } } - fn expand_variant_call(&self) -> proc_macro2::TokenStream { + fn expand_variant_call( + &self, + call_name: &proc_macro2::Ident, + generics: &proc_macro2::TokenStream, + ) -> proc_macro2::TokenStream { let name = &self.name; let pascal_call_name = &self.pascal_call_name; quote! { - InternalCall::#name(call) => return >::call(self, Msg { + #call_name::#name(call) => return >::call(self, Msg { call, caller: c.caller, value: c.value, @@ -64,20 +78,20 @@ } } - fn expand_parse(&self) -> proc_macro2::TokenStream { + fn expand_parse(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream { let name = &self.name; let pascal_call_name = &self.pascal_call_name; quote! { - if let Some(parsed_call) = #pascal_call_name::parse(method_id, reader)? { + if let Some(parsed_call) = <#pascal_call_name #generics>::parse(method_id, reader)? { return Ok(Some(Self::#name(parsed_call))) } } } - fn expand_generator(&self) -> proc_macro2::TokenStream { + fn expand_generator(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream { let pascal_call_name = &self.pascal_call_name; quote! { - #pascal_call_name::generate_solidity_interface(tc, is_impl); + <#pascal_call_name #generics>::generate_solidity_interface(tc, is_impl); } } @@ -351,6 +365,25 @@ Pure, } +pub struct WeightAttr(syn::Expr); + +mod keyword { + syn::custom_keyword!(weight); +} + +impl syn::parse::Parse for WeightAttr { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + let content; + syn::bracketed!(content in input); + content.parse::()?; + + let weight_content; + syn::parenthesized!(weight_content in content); + Ok(WeightAttr(weight_content.parse::()?)) + } +} + struct Method { name: Ident, camel_name: String, @@ -362,6 +395,7 @@ has_normal_args: bool, mutability: Mutability, result: Type, + weight: Option, docs: Vec, } impl Method { @@ -370,6 +404,7 @@ rename_selector: None, }; let mut docs = Vec::new(); + let mut weight = None; for attr in &value.attrs { let ident = parse_ident_from_path(&attr.path, false)?; if ident == "solidity" { @@ -384,6 +419,8 @@ _ => unreachable!(), }; docs.push(value); + } else if ident == "weight" { + weight = Some(syn::parse2::(attr.to_token_stream())?.0); } } let ident = &value.sig.ident; @@ -466,6 +503,7 @@ has_normal_args, mutability, result: result.clone(), + weight, docs, }) } @@ -528,7 +566,7 @@ } } - fn expand_variant_call(&self) -> proc_macro2::TokenStream { + fn expand_variant_call(&self, call_name: &proc_macro2::Ident) -> proc_macro2::TokenStream { let pascal_name = &self.pascal_name; let name = &self.name; @@ -555,17 +593,50 @@ let args = self.args.iter().map(|a| a.expand_call_arg()); quote! { - InternalCall::#pascal_name #matcher => { + #call_name::#pascal_name #matcher => { let result = #receiver #name( #( #args, )* )?; - (&result).abi_write(&mut writer); + (&result).into_result() } } } + fn expand_variant_weight(&self) -> proc_macro2::TokenStream { + let pascal_name = &self.pascal_name; + if let Some(weight) = &self.weight { + let matcher = if self.has_normal_args { + let names = self + .args + .iter() + .filter(|a| !a.is_special()) + .map(|a| &a.name); + + quote! {{ + #( + #names, + )* + }} + } else { + quote! {} + }; + quote! { + Self::#pascal_name #matcher => (#weight).into() + } + } else { + let matcher = if self.has_normal_args { + quote! {{..}} + } else { + quote! {} + }; + quote! { + Self::#pascal_name #matcher => ().into() + } + } + } + fn expand_solidity_function(&self) -> proc_macro2::TokenStream { let camel_name = &self.camel_name; let mutability = match self.mutability { @@ -600,6 +671,42 @@ } } +fn generics_list(gen: &Generics) -> proc_macro2::TokenStream { + if gen.params.is_empty() { + return quote! {}; + } + let params = gen.params.iter().map(|p| match p { + syn::GenericParam::Type(id) => { + let v = &id.ident; + quote! {#v} + } + syn::GenericParam::Lifetime(lt) => { + let v = <.lifetime; + quote! {#v} + } + syn::GenericParam::Const(c) => { + let i = &c.ident; + quote! {#i} + } + }); + quote! { #(#params),* } +} +fn generics_reference(gen: &Generics) -> proc_macro2::TokenStream { + if gen.params.is_empty() { + return quote! {}; + } + let list = generics_list(gen); + quote! { <#list> } +} +fn generics_data(gen: &Generics) -> proc_macro2::TokenStream { + let list = generics_list(gen); + if gen.params.len() == 1 { + quote! {#list} + } else { + quote! { (#list) } + } +} + pub struct SolidityInterface { generics: Generics, name: Box, @@ -628,6 +735,8 @@ let solidity_name = self.info.name.to_string(); let call_name = pascal_ident_to_call(&self.info.name); let generics = self.generics; + let gen_ref = generics_reference(&generics); + let gen_data = generics_data(&generics); let call_sub = self .info @@ -635,30 +744,46 @@ .0 .iter() .chain(self.info.is.0.iter()) - .map(Is::expand_call_def); + .map(|c| Is::expand_call_def(c, &gen_ref)); let call_parse = self .info .inline_is .0 .iter() .chain(self.info.is.0.iter()) - .map(Is::expand_parse); + .map(|is| Is::expand_parse(is, &gen_ref)); let call_variants = self .info .inline_is .0 .iter() .chain(self.info.is.0.iter()) - .map(Is::expand_variant_call); + .map(|c| Is::expand_variant_call(c, &call_name, &gen_ref)); + let weight_variants = self + .info + .inline_is + .0 + .iter() + .chain(self.info.is.0.iter()) + .map(Is::expand_variant_weight); let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id); - let supports_interface = self.info.is.0.iter().map(Is::expand_supports_interface); + let supports_interface = self + .info + .is + .0 + .iter() + .map(|is| Is::expand_supports_interface(is, &gen_ref)); let calls = self.methods.iter().map(Method::expand_call_def); let consts = self.methods.iter().map(Method::expand_const); let interface_id = self.methods.iter().map(Method::expand_interface_id); let parsers = self.methods.iter().map(Method::expand_parse); - let call_variants_this = self.methods.iter().map(Method::expand_variant_call); + let call_variants_this = self + .methods + .iter() + .map(|m| Method::expand_variant_call(m, &call_name)); + let weight_variants_this = self.methods.iter().map(Method::expand_variant_weight); let solidity_functions = self.methods.iter().map(Method::expand_solidity_function); // TODO: Inline inline_is @@ -676,15 +801,15 @@ .0 .iter() .chain(self.info.inline_is.0.iter()) - .map(Is::expand_generator); + .map(|is| Is::expand_generator(is, &gen_ref)); let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator); // let methods = self.methods.iter().map(Method::solidity_def); quote! { #[derive(Debug)] - pub enum #call_name { - ERC165Call(::evm_coder::ERC165Call), + pub enum #call_name #gen_ref { + ERC165Call(::evm_coder::ERC165Call, ::core::marker::PhantomData<#gen_data>), #( #calls, )* @@ -692,11 +817,11 @@ #call_sub, )* } - impl #call_name { + impl #gen_ref #call_name #gen_ref { #( #consts )* - pub const fn interface_id() -> u32 { + pub fn interface_id() -> u32 { let mut interface_id = 0; #(#interface_id)* #(#inline_interface_id)* @@ -748,11 +873,14 @@ tc.collect(out); } } - impl ::evm_coder::Call for #call_name { + impl #gen_ref ::evm_coder::Call for #call_name #gen_ref { fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result> { use ::evm_coder::abi::AbiRead; match method_id { - ::evm_coder::ERC165Call::INTERFACE_ID => return Ok(::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)), + ::evm_coder::ERC165Call::INTERFACE_ID => return Ok( + ::evm_coder::ERC165Call::parse(method_id, reader)? + .map(|c| Self::ERC165Call(c, ::core::marker::PhantomData)) + ), #( #parsers, )* @@ -764,19 +892,33 @@ return Ok(None); } } - impl #generics ::evm_coder::Callable<#call_name> for #name { + impl #generics ::evm_coder::Weighted for #call_name #gen_ref { + #[allow(unused_variables)] + fn weight(&self) -> ::evm_coder::execution::DispatchInfo { + match self { + #( + #weight_variants, + )* + // TODO: It should be very cheap, but not free + Self::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {..}, _) => 100u64.into(), + #( + #weight_variants_this, + )* + } + } + } + impl #generics ::evm_coder::Callable<#call_name #gen_ref> for #name { #[allow(unreachable_code)] // In case of no inner calls - fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> { + fn call(&mut self, c: Msg<#call_name #gen_ref>) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> { use ::evm_coder::abi::AbiWrite; - type InternalCall = #call_name; match c.call { #( #call_variants, )* - InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}) => { + #call_name::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}, _) => { let mut writer = ::evm_coder::abi::AbiWriter::default(); - writer.bool(&InternalCall::supports_interface(interface_id)); - return Ok(writer); + writer.bool(&<#call_name #gen_ref>::supports_interface(interface_id)); + return Ok(writer.into()); } _ => {}, } @@ -787,7 +929,6 @@ )* _ => unreachable!() } - Ok(writer) } } } --- a/crates/evm-coder/src/abi.rs +++ b/crates/evm-coder/src/abi.rs @@ -11,7 +11,10 @@ use evm_core::ExitError; use primitive_types::{H160, U256}; -use crate::{execution::Error, types::string}; +use crate::{ + execution::{Error, ResultWithPostInfo, WithPostDispatchInfo}, + types::string, +}; use crate::execution::Result; const ABI_ALIGNMENT: usize = 32; @@ -244,6 +247,7 @@ } impl_abi_readable!(u32, uint32); +impl_abi_readable!(u64, uint64); impl_abi_readable!(u128, uint128); impl_abi_readable!(U256, uint256); impl_abi_readable!(H160, address); @@ -306,6 +310,36 @@ pub trait AbiWrite { fn abi_write(&self, writer: &mut AbiWriter); + fn into_result(&self) -> ResultWithPostInfo { + let mut writer = AbiWriter::new(); + self.abi_write(&mut writer); + Ok(writer.into()) + } +} + +impl AbiWrite for ResultWithPostInfo { + // this particular AbiWrite implementation should be split to another trait, + // which only implements [`into_result`] + // + // But due to lack of specialization feature in stable Rust, we can't have + // blanket impl of this trait `for T where T: AbiWrite`, so here we abusing + // default trait methods for it + fn abi_write(&self, _writer: &mut AbiWriter) { + debug_assert!(false, "shouldn't be called, see comment") + } + fn into_result(&self) -> ResultWithPostInfo { + match self { + Ok(v) => Ok(WithPostDispatchInfo { + post_info: v.post_info.clone(), + data: { + let mut out = AbiWriter::new(); + v.data.abi_write(&mut out); + out + }, + }), + Err(e) => Err(e.clone()), + } + } } macro_rules! impl_abi_writeable { --- a/crates/evm-coder/src/execution.rs +++ b/crates/evm-coder/src/execution.rs @@ -4,7 +4,9 @@ #[cfg(feature = "std")] use std::string::{String, ToString}; -#[derive(Debug)] +use crate::Weight; + +#[derive(Debug, Clone)] pub enum Error { Revert(String), Fatal(ExitFatal), @@ -21,3 +23,55 @@ } pub type Result = core::result::Result; + +pub struct DispatchInfo { + pub weight: Weight, +} + +impl From for DispatchInfo { + fn from(weight: Weight) -> Self { + Self { weight } + } +} +impl From<()> for DispatchInfo { + fn from(_: ()) -> Self { + Self { weight: 0 } + } +} + +#[derive(Default, Clone)] +pub struct PostDispatchInfo { + actual_weight: Option, +} + +impl PostDispatchInfo { + pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight { + info.weight - self.calc_actual_weight(info) + } + + pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight { + if let Some(actual_weight) = self.actual_weight { + actual_weight.min(info.weight) + } else { + info.weight + } + } +} + +#[derive(Clone)] +pub struct WithPostDispatchInfo { + pub data: T, + pub post_info: PostDispatchInfo, +} + +impl From for WithPostDispatchInfo { + fn from(data: T) -> Self { + Self { + data, + post_info: Default::default(), + } + } +} + +pub type ResultWithPostInfo = + core::result::Result, WithPostDispatchInfo>; --- a/crates/evm-coder/src/lib.rs +++ b/crates/evm-coder/src/lib.rs @@ -3,10 +3,11 @@ extern crate alloc; use abi::{AbiRead, AbiReader, AbiWriter}; -pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, ToLog}; +pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, weight, ToLog}; pub mod abi; pub mod events; pub use events::ToLog; +use execution::DispatchInfo; pub mod execution; pub mod solidity; @@ -57,8 +58,14 @@ fn parse(selector: u32, input: &mut AbiReader) -> execution::Result>; } +pub type Weight = u64; + +pub trait Weighted: Call { + fn weight(&self) -> DispatchInfo; +} + pub trait Callable { - fn call(&mut self, call: types::Msg) -> execution::Result; + fn call(&mut self, call: types::Msg) -> execution::ResultWithPostInfo; } /// Implementation is implicitly provided for all interfaces @@ -84,15 +91,20 @@ } } +/// Generate "tests", which will generate solidity code on execution and print it to stdout +/// Script at .maintain/scripts/generate_api.sh can split this output from test runtime +/// +/// This macro receives type usage as second argument, but you can use anything as generics, +/// because no bounds are implied #[macro_export] macro_rules! generate_stubgen { - ($name:ident, $decl:ident, $is_impl:literal) => { + ($name:ident, $decl:ty, $is_impl:literal) => { #[test] #[ignore] fn $name() { use evm_coder::solidity::TypeCollector; let mut out = TypeCollector::new(); - $decl::generate_solidity_interface(&mut out, $is_impl); + <$decl>::generate_solidity_interface(&mut out, $is_impl); println!("=== SNIP START ==="); println!("// SPDX-License-Identifier: OTHER"); println!("// This code is automatically generated"); --- a/crates/evm-coder/tests/a.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![allow(dead_code)] // This test only checks that macros is not panicking - -use evm_coder::{solidity_interface, types::*, ToLog, execution::Result}; -use evm_coder_macros::solidity; - -struct Impls; - -#[solidity_interface(name = "OurInterface")] -impl Impls { - fn fn_a(&self, _input: uint256) -> Result { - todo!() - } -} - -#[solidity_interface(name = "OurInterface1")] -impl Impls { - fn fn_b(&self, _input: uint128) -> Result { - todo!() - } -} - -#[solidity_interface( - name = "OurInterface2", - is(OurInterface), - inline_is(OurInterface1), - events(ERC721Log) -)] -impl Impls { - #[solidity(rename_selector = "fnK")] - fn fn_c(&self, _input: uint32) -> Result { - todo!() - } - fn fn_d(&self, _value: uint32) -> Result { - todo!() - } - - fn caller_sensitive(&self, _caller: caller) -> Result { - todo!() - } - fn payable(&mut self, _value: value) -> Result { - todo!() - } -} - -#[derive(ToLog)] -enum ERC721Log { - Transfer { - #[indexed] - from: address, - #[indexed] - to: address, - value: uint256, - }, - Eee { - #[indexed] - aaa: address, - bbb: uint256, - }, -} - -struct ERC20; - -#[solidity_interface(name = "ERC20")] -impl ERC20 { - fn decimals(&self) -> Result { - todo!() - } - fn balance_of(&self, _owner: address) -> Result { - todo!() - } - fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result { - todo!() - } - fn transfer_from( - &mut self, - _caller: caller, - _from: address, - _to: address, - _value: uint256, - ) -> Result { - todo!() - } - fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result { - todo!() - } - fn allowance(&self, _owner: address, _spender: address) -> Result { - todo!() - } -} --- /dev/null +++ b/crates/evm-coder/tests/generics.rs @@ -0,0 +1,20 @@ +use std::marker::PhantomData; +use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*}; + +struct Generic(PhantomData); + +#[solidity_interface(name = "GenericIs")] +impl Generic { + fn test_1(&self) -> Result { + todo!() + } +} + +#[solidity_interface(name = "Generic", is(GenericIs))] +impl> Generic { + fn test_2(&self) -> Result { + todo!() + } +} + +generate_stubgen!(gen_iface, GenericCall<()>, false); --- /dev/null +++ b/crates/evm-coder/tests/log.rs @@ -0,0 +1,17 @@ +use evm_coder::{ToLog, types::*}; + +#[derive(ToLog)] +enum ERC721Log { + Transfer { + #[indexed] + from: address, + #[indexed] + to: address, + value: uint256, + }, + Eee { + #[indexed] + aaa: address, + bbb: uint256, + }, +} --- /dev/null +++ b/crates/evm-coder/tests/random.rs @@ -0,0 +1,65 @@ +#![allow(dead_code)] // This test only checks that macros is not panicking + +use evm_coder::{ToLog, execution::Result, solidity_interface, types::*}; +use evm_coder_macros::{solidity, weight}; + +struct Impls; + +#[solidity_interface(name = "OurInterface")] +impl Impls { + fn fn_a(&self, _input: uint256) -> Result { + todo!() + } +} + +#[solidity_interface(name = "OurInterface1")] +impl Impls { + fn fn_b(&self, _input: uint128) -> Result { + todo!() + } +} + +#[derive(ToLog)] +enum OurEvents { + Event1 { + field1: uint32, + }, + Event2 { + field1: uint32, + #[indexed] + field2: uint32, + }, +} + +#[solidity_interface( + name = "OurInterface2", + is(OurInterface), + inline_is(OurInterface1), + events(OurEvents) +)] +impl Impls { + #[solidity(rename_selector = "fnK")] + fn fn_c(&self, _input: uint32) -> Result { + todo!() + } + fn fn_d(&self, _value: uint32) -> Result { + todo!() + } + + fn caller_sensitive(&self, _caller: caller) -> Result { + todo!() + } + fn payable(&mut self, _value: value) -> Result { + todo!() + } + + #[weight(*_weight)] + fn with_weight(&self, _weight: uint64) -> Result { + todo!() + } + + /// Doccoment example + fn with_doc(&self) -> Result { + todo!() + } +} --- /dev/null +++ b/crates/evm-coder/tests/solidity_generation.rs @@ -0,0 +1,35 @@ +use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*}; + +struct ERC20; + +#[solidity_interface(name = "ERC20")] +impl ERC20 { + fn decimals(&self) -> Result { + todo!() + } + /// Get balance of specified owner + fn balance_of(&self, _owner: address) -> Result { + todo!() + } + fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result { + todo!() + } + fn transfer_from( + &mut self, + _caller: caller, + _from: address, + _to: address, + _value: uint256, + ) -> Result { + todo!() + } + fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result { + todo!() + } + fn allowance(&self, _owner: address, _spender: address) -> Result { + todo!() + } +} + +generate_stubgen!(gen_impl, ERC20Call, true); +generate_stubgen!(gen_iface, ERC20Call, false); --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -268,13 +268,13 @@ jsonrpc-core = '18.0.0' jsonrpc-pubsub = "18.0.0" -fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } nft-rpc = { path = "../rpc" } --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -41,12 +41,12 @@ substrate-frame-rpc-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } tokio = { version = "0.2.25", features = ["macros", "sync"] } -pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } pallet-nft = { path = "../../pallets/nft" } uc-rpc = { path = "../../client/rpc" } --- a/pallets/common/Cargo.toml +++ b/pallets/common/Cargo.toml @@ -19,7 +19,7 @@ pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } evm-coder = { default-features = false, path = '../../crates/evm-coder' } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } serde = { version = "1.0.130", default-features = false } scale-info = { version = "1.0.0", default-features = false, features = [ "derive", --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use core::ops::{Deref, DerefMut}; +use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; use sp_std::vec::Vec; use account::CrossAccountId; use frame_support::{ @@ -8,6 +9,7 @@ ensure, fail, traits::{Imbalance, Get, Currency}, }; +use pallet_evm::GasWeightMapping; use nft_data_structs::{ COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_COLLECTION_NAME_LENGTH, MAX_TOKEN_PREFIX_LENGTH, @@ -27,17 +29,22 @@ pub struct CollectionHandle { pub id: CollectionId, collection: Collection, - pub recorder: pallet_evm_coder_substrate::SubstrateRecorder, + pub recorder: SubstrateRecorder, } +impl WithRecorder for CollectionHandle { + fn recorder(&self) -> &SubstrateRecorder { + &self.recorder + } + fn into_recorder(self) -> SubstrateRecorder { + self.recorder + } +} impl CollectionHandle { pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option { >::get(id).map(|collection| Self { id, collection, - recorder: pallet_evm_coder_substrate::SubstrateRecorder::new( - eth::collection_id_to_address(id), - gas_limit, - ), + recorder: SubstrateRecorder::new(eth::collection_id_to_address(id), gas_limit), }) } pub fn new(id: CollectionId) -> Option { @@ -46,33 +53,30 @@ pub fn try_get(id: CollectionId) -> Result { Ok(Self::new(id).ok_or_else(|| >::CollectionNotFound)?) } - pub fn log(&self, log: impl evm_coder::ToLog) -> DispatchResult { - self.recorder.log_sub(log) + pub fn log(&self, log: impl evm_coder::ToLog) { + self.recorder.log(log) } - pub fn log_infallible(&self, log: impl evm_coder::ToLog) { - self.recorder.log_infallible(log) + pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> { + self.recorder + .consume_gas(T::GasWeightMapping::weight_to_gas( + ::DbWeight::get() + .read + .saturating_mul(reads), + )) } - #[allow(dead_code)] - fn consume_gas(&self, gas: u64) -> DispatchResult { - self.recorder.consume_gas_sub(gas) - } - pub fn consume_sload(&self) -> DispatchResult { - self.recorder.consume_sload_sub() + pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> { + self.recorder + .consume_gas(T::GasWeightMapping::weight_to_gas( + ::DbWeight::get() + .write + .saturating_mul(writes), + )) } - pub fn consume_sstores(&self, amount: usize) -> DispatchResult { - self.recorder.consume_sstores_sub(amount) - } - pub fn consume_sstore(&self) -> DispatchResult { - self.recorder.consume_sstore_sub() - } - pub fn consume_log(&self, topics: usize, data: usize) -> DispatchResult { - self.recorder.consume_log_sub(topics, data) - } - pub fn submit_logs(self) -> DispatchResult { + pub fn submit_logs(self) { self.recorder.submit_logs() } pub fn save(self) -> DispatchResult { - self.recorder.submit_logs()?; + self.recorder.submit_logs(); >::insert(self.id, self.collection); Ok(()) } @@ -96,24 +100,20 @@ ensure!(*subject.as_sub() == self.owner, >::NoPermission); Ok(()) } - pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> Result { - self.consume_sload()?; - - Ok(*subject.as_sub() == self.owner || >::get((self.id, subject))) + pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool { + *subject.as_sub() == self.owner || >::get((self.id, subject)) } pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult { - ensure!(self.is_owner_or_admin(subject)?, >::NoPermission); + ensure!(self.is_owner_or_admin(subject), >::NoPermission); Ok(()) } - pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> Result { - Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?) + pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool { + self.limits.owner_can_transfer() && self.is_owner_or_admin(user) } - pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> Result { - Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?) + pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool { + self.limits.owner_can_transfer() && self.is_owner_or_admin(user) } pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult { - self.consume_sload()?; - ensure!( >::get((self.id, user)), >::AddressNotInAllowlist --- a/pallets/evm-coder-substrate/Cargo.toml +++ b/pallets/evm-coder-substrate/Cargo.toml @@ -4,15 +4,18 @@ edition = "2018" [dependencies] -scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0.0", default-features = false, features = [ + "derive", +] } sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } ethereum = { version = "0.9", git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false } evm-coder = { default-features = false, path = "../../crates/evm-coder" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } +frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } [dependencies.codec] default-features = false @@ -31,4 +34,6 @@ "pallet-evm/std", "frame-support/std", "frame-system/std", + 'frame-benchmarking/std', ] +runtime-benchmarks = ['frame-benchmarking'] --- /dev/null +++ b/pallets/evm-coder-substrate/src/benchmarking.rs @@ -0,0 +1,8 @@ +use super::*; + +use frame_benchmarking::benchmarks; + +benchmarks! { + // gas_per_second { + // }: (pallet_evm::) +} --- a/pallets/evm-coder-substrate/src/lib.rs +++ b/pallets/evm-coder-substrate/src/lib.rs @@ -2,6 +2,8 @@ #[cfg(not(feature = "std"))] extern crate alloc; +// #[cfg(feature = "runtime-benchmarks")] +// pub mod benchmarking; pub use pallet::*; @@ -17,7 +19,10 @@ types::{Msg, value}, }; use frame_support::{ensure}; - use pallet_evm::{ExitError, ExitReason, ExitRevert, ExitSucceed, PrecompileOutput}; + use pallet_evm::{ + ExitError, ExitReason, ExitRevert, ExitSucceed, PrecompileOutput, GasWeightMapping, + }; + use frame_system::ensure_signed; pub use frame_support::dispatch::DispatchResult; use pallet_ethereum::EthereumTransactionSender; use sp_std::cell::RefCell; @@ -25,6 +30,7 @@ use sp_core::{H160, H256}; use ethereum::Log; use frame_support::{pallet_prelude::*, traits::PalletInfo}; + use frame_system::pallet_prelude::*; /// DispatchError is opaque, but we need to somehow extract correct error in case of OutOfGas failure /// So we have this pallet, which defines OutOfGas error, and knews its own id to check if DispatchError @@ -40,25 +46,24 @@ #[pallet::config] pub trait Config: frame_system::Config { type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender; + type GasWeightMapping: pallet_evm::GasWeightMapping; } #[pallet::pallet] pub struct Pallet(_); - // FIXME: those items are defined as private in evm_gasometer::consts, and we can't directly use it - pub const G_LOG: u64 = 375; - pub const G_LOGDATA: u64 = 8; - pub const G_LOGTOPIC: u64 = 375; + #[pallet::call] + impl Pallet { + #[pallet::weight(0)] + pub fn empty_call(origin: OriginFor) -> DispatchResult { + let _sender = ensure_signed(origin)?; + Ok(()) + } + } // From instabul hardfork configuration: https://github.com/rust-blockchain/evm/blob/fd4fd6acc0ca3208d6770fdb3ba407c94cdf97c6/runtime/src/lib.rs#L284 pub const G_SLOAD_WORD: u64 = 800; pub const G_SSTORE_WORD: u64 = 20000; - - fn log_price(data: usize, topics: usize) -> u64 { - G_LOG - .saturating_add((data as u64).saturating_mul(G_LOGDATA)) - .saturating_add((topics as u64).saturating_mul(G_LOGTOPIC)) - } pub fn generate_transaction() -> ethereum::TransactionV0 { use ethereum::{TransactionV0, TransactionAction, TransactionSignature}; @@ -98,16 +103,10 @@ pub fn is_empty(&self) -> bool { self.logs.borrow().is_empty() } - pub fn log_sub(&self, log: impl ToLog) -> DispatchResult { - self.log_raw_sub(log.to_log(self.contract)) - } - pub fn log_raw_sub(&self, log: Log) -> DispatchResult { - self.consume_gas_sub(log_price(log.data.len(), log.topics.len()))?; - self.logs.borrow_mut().push(log); - Ok(()) - } + // TODO: Replace with real storage in pallet-ethereum, + // same way as it is done with frame_system's Events /// Doesn't consumes any gas, should be used after consume_log_sub - pub fn log_infallible(&self, log: impl ToLog) { + pub fn log(&self, log: impl ToLog) { self.logs.borrow_mut().push(log.to_log(self.contract)); } pub fn retrieve_logs(self) -> Vec { @@ -125,9 +124,6 @@ } pub fn consume_sstore_sub(&self) -> DispatchResult { self.consume_gas_sub(G_SSTORE_WORD) - } - pub fn consume_log_sub(&self, topics: usize, data: usize) -> DispatchResult { - self.consume_gas_sub(log_price(data, topics)) } pub fn consume_gas_sub(&self, gas: u64) -> DispatchResult { ensure!(gas != u64::MAX, Error::::OutOfGas); @@ -154,6 +150,10 @@ *gas_limit -= gas; Ok(()) } + pub fn return_gas(&self, gas: u64) { + let mut gas_limit = self.gas_limit.borrow_mut(); + *gas_limit += gas; + } pub fn evm_to_precompile_output( self, @@ -181,12 +181,16 @@ }) } - pub fn submit_logs(self) -> DispatchResult { + pub fn submit_logs(self) { let logs = self.retrieve_logs(); if logs.is_empty() { - return Ok(()); + return; } - T::EthereumTransactionSender::submit_logs_transaction(generate_transaction(), logs) + T::EthereumTransactionSender::submit_logs_transaction( + Default::default(), + generate_transaction(), + logs, + ) } } @@ -215,7 +219,31 @@ } } - pub fn call_internal>( + pub trait WithRecorder { + fn recorder(&self) -> &SubstrateRecorder; + fn into_recorder(self) -> SubstrateRecorder; + } + + /// Helper to simplify implementing bridge between evm-coder definitions and pallet-evm + pub fn call< + T: Config, + C: evm_coder::Call + evm_coder::Weighted, + E: evm_coder::Callable + WithRecorder, + >( + caller: H160, + mut e: E, + value: value, + input: &[u8], + ) -> Option { + let result = call_internal(caller, &mut e, value, input); + e.into_recorder().evm_to_precompile_output(result) + } + + fn call_internal< + T: Config, + C: evm_coder::Call + evm_coder::Weighted, + E: evm_coder::Callable + WithRecorder, + >( caller: H160, e: &mut E, value: value, @@ -227,11 +255,28 @@ return Ok(None); } let call = call.unwrap(); - e.call(Msg { + + let dispatch_info = call.weight(); + e.recorder() + .consume_gas(T::GasWeightMapping::weight_to_gas(dispatch_info.weight))?; + + match e.call(Msg { call, caller, value, - }) - .map(Some) + }) { + Ok(v) => { + let unspent = v.post_info.calc_unspent(&dispatch_info); + e.recorder() + .return_gas(T::GasWeightMapping::weight_to_gas(unspent)); + Ok(Some(v.data)) + } + Err(v) => { + let unspent = v.post_info.calc_unspent(&dispatch_info); + e.recorder() + .return_gas(T::GasWeightMapping::weight_to_gas(unspent)); + Err(v.data) + } + } } } --- a/pallets/evm-contract-helpers/Cargo.toml +++ b/pallets/evm-contract-helpers/Cargo.toml @@ -4,7 +4,9 @@ edition = "2018" [dependencies] -scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0.0", default-features = false, features = [ + "derive", +] } frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } @@ -12,7 +14,7 @@ sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } evm-coder = { default-features = false, path = '../../crates/evm-coder' } pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' } log = "0.4.14" --- /dev/null +++ b/pallets/evm-contract-helpers/exp.rs @@ -0,0 +1,1474 @@ +#![feature(prelude_import)] +#[prelude_import] +use std::prelude::rust_2018::*; +#[macro_use] +extern crate std; +pub use pallet::*; +pub use eth::*; +pub mod eth { + use core::marker::PhantomData; + use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*}; + use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; + use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput}; + use sp_core::H160; + use crate::{ + AllowlistEnabled, Config, Owner, Pallet, SelfSponsoring, SponsorBasket, SponsoringRateLimit, + }; + use frame_support::traits::Get; + use up_sponsorship::SponsorshipHandler; + use sp_std::{convert::TryInto, vec::Vec}; + struct ContractHelpers(SubstrateRecorder); + impl WithRecorder for ContractHelpers { + fn recorder(&self) -> &SubstrateRecorder { + &self.0 + } + fn into_recorder(self) -> SubstrateRecorder { + self.0 + } + } + impl ContractHelpers { + fn contract_owner(&self, contract_address: address) -> Result
{ + Ok(>::get(contract_address)) + } + fn sponsoring_enabled(&self, contract_address: address) -> Result { + Ok(>::get(contract_address)) + } + fn toggle_sponsoring( + &mut self, + caller: caller, + contract_address: address, + enabled: bool, + ) -> Result { + >::ensure_owner(contract_address, caller)?; + >::toggle_sponsoring(contract_address, enabled); + Ok(()) + } + fn set_sponsoring_rate_limit( + &mut self, + caller: caller, + contract_address: address, + rate_limit: uint32, + ) -> Result { + >::ensure_owner(contract_address, caller)?; + >::set_sponsoring_rate_limit(contract_address, rate_limit.into()); + Ok(()) + } + fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result { + Ok(>::get(contract_address) + .try_into() + .map_err(|_| "rate limit > u32::MAX")?) + } + fn allowed(&self, contract_address: address, user: address) -> Result { + Ok(>::allowed(contract_address, user, true)) + } + fn allowlist_enabled(&self, contract_address: address) -> Result { + Ok(>::get(contract_address)) + } + fn toggle_allowlist( + &mut self, + caller: caller, + contract_address: address, + enabled: bool, + ) -> Result { + >::ensure_owner(contract_address, caller)?; + >::toggle_allowlist(contract_address, enabled); + Ok(()) + } + fn toggle_allowed( + &mut self, + caller: caller, + contract_address: address, + user: address, + allowed: bool, + ) -> Result { + >::ensure_owner(contract_address, caller)?; + >::toggle_allowed(contract_address, user, allowed); + Ok(()) + } + } + pub enum ContractHelpersCall { + ERC165Call(::evm_coder::ERC165Call, PhantomData<(T)>), + ContractOwner { + contract_address: address, + }, + SponsoringEnabled { + contract_address: address, + }, + ToggleSponsoring { + contract_address: address, + enabled: bool, + }, + SetSponsoringRateLimit { + contract_address: address, + rate_limit: uint32, + }, + GetSponsoringRateLimit { + contract_address: address, + }, + Allowed { + contract_address: address, + user: address, + }, + AllowlistEnabled { + contract_address: address, + }, + ToggleAllowlist { + contract_address: address, + enabled: bool, + }, + ToggleAllowed { + contract_address: address, + user: address, + allowed: bool, + }, + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::fmt::Debug for ContractHelpersCall { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match (&*self,) { + (&ContractHelpersCall::ERC165Call(ref __self_0, ref __self_1),) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_tuple(f, "ERC165Call"); + let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &&(*__self_0)); + let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &&(*__self_1)); + ::core::fmt::DebugTuple::finish(debug_trait_builder) + } + (&ContractHelpersCall::ContractOwner { + contract_address: ref __self_0, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "ContractOwner"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::SponsoringEnabled { + contract_address: ref __self_0, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "SponsoringEnabled"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::ToggleSponsoring { + contract_address: ref __self_0, + enabled: ref __self_1, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "ToggleSponsoring"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "enabled", + &&(*__self_1), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::SetSponsoringRateLimit { + contract_address: ref __self_0, + rate_limit: ref __self_1, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "SetSponsoringRateLimit"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "rate_limit", + &&(*__self_1), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::GetSponsoringRateLimit { + contract_address: ref __self_0, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "GetSponsoringRateLimit"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::Allowed { + contract_address: ref __self_0, + user: ref __self_1, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "Allowed"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + let _ = + ::core::fmt::DebugStruct::field(debug_trait_builder, "user", &&(*__self_1)); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::AllowlistEnabled { + contract_address: ref __self_0, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "AllowlistEnabled"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::ToggleAllowlist { + contract_address: ref __self_0, + enabled: ref __self_1, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "ToggleAllowlist"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "enabled", + &&(*__self_1), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + (&ContractHelpersCall::ToggleAllowed { + contract_address: ref __self_0, + user: ref __self_1, + allowed: ref __self_2, + },) => { + let debug_trait_builder = + &mut ::core::fmt::Formatter::debug_struct(f, "ToggleAllowed"); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "contract_address", + &&(*__self_0), + ); + let _ = + ::core::fmt::DebugStruct::field(debug_trait_builder, "user", &&(*__self_1)); + let _ = ::core::fmt::DebugStruct::field( + debug_trait_builder, + "allowed", + &&(*__self_2), + ); + ::core::fmt::DebugStruct::finish(debug_trait_builder) + } + } + } + } + impl ContractHelpersCall { + #[doc = "contractOwner(address)"] + const CONTRACT_OWNER: u32 = 1364373836u32; + #[doc = "sponsoringEnabled(address)"] + const SPONSORING_ENABLED: u32 = 1613225057u32; + #[doc = "toggleSponsoring(address,bool)"] + const TOGGLE_SPONSORING: u32 = 4239158662u32; + #[doc = "setSponsoringRateLimit(address,uint32)"] + const SET_SPONSORING_RATE_LIMIT: u32 = 2008467720u32; + #[doc = "getSponsoringRateLimit(address)"] + const GET_SPONSORING_RATE_LIMIT: u32 = 1628240573u32; + #[doc = "allowed(address,address)"] + const ALLOWED: u32 = 1550156133u32; + #[doc = "allowlistEnabled(address)"] + const ALLOWLIST_ENABLED: u32 = 3346198380u32; + #[doc = "toggleAllowlist(address,bool)"] + const TOGGLE_ALLOWLIST: u32 = 920527093u32; + #[doc = "toggleAllowed(address,address,bool)"] + const TOGGLE_ALLOWED: u32 = 1191627804u32; + pub const fn interface_id() -> u32 { + let mut interface_id = 0; + interface_id ^= Self::CONTRACT_OWNER; + interface_id ^= Self::SPONSORING_ENABLED; + interface_id ^= Self::TOGGLE_SPONSORING; + interface_id ^= Self::SET_SPONSORING_RATE_LIMIT; + interface_id ^= Self::GET_SPONSORING_RATE_LIMIT; + interface_id ^= Self::ALLOWED; + interface_id ^= Self::ALLOWLIST_ENABLED; + interface_id ^= Self::TOGGLE_ALLOWLIST; + interface_id ^= Self::TOGGLE_ALLOWED; + interface_id + } + pub fn supports_interface(interface_id: u32) -> bool { + interface_id != 0xffffff + && (interface_id == ::evm_coder::ERC165Call::INTERFACE_ID + || interface_id == Self::interface_id()) + } + pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) { + use evm_coder::solidity::*; + use core::fmt::Write; + let interface = SolidityInterface { + name: "ContractHelpers", + selector: Self::interface_id(), + is: &["Dummy", "ERC165"], + functions: ( + SolidityFunction { + docs: &[], + selector: "contractOwner(address) 5152b14c", + name: "contractOwner", + mutability: SolidityMutability::View, + args: (>::new("contractAddress"),), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "sponsoringEnabled(address) 6027dc61", + name: "sponsoringEnabled", + mutability: SolidityMutability::View, + args: (>::new("contractAddress"),), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "toggleSponsoring(address,bool) fcac6d86", + name: "toggleSponsoring", + mutability: SolidityMutability::Mutable, + args: ( + >::new("contractAddress"), + >::new("enabled"), + ), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "setSponsoringRateLimit(address,uint32) 77b6c908", + name: "setSponsoringRateLimit", + mutability: SolidityMutability::Mutable, + args: ( + >::new("contractAddress"), + >::new("rateLimit"), + ), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "getSponsoringRateLimit(address) 610cfabd", + name: "getSponsoringRateLimit", + mutability: SolidityMutability::View, + args: (>::new("contractAddress"),), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "allowed(address,address) 5c658165", + name: "allowed", + mutability: SolidityMutability::View, + args: ( + >::new("contractAddress"), + >::new("user"), + ), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "allowlistEnabled(address) c772ef6c", + name: "allowlistEnabled", + mutability: SolidityMutability::View, + args: (>::new("contractAddress"),), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "toggleAllowlist(address,bool) 36de20f5", + name: "toggleAllowlist", + mutability: SolidityMutability::Mutable, + args: ( + >::new("contractAddress"), + >::new("enabled"), + ), + result: >::default(), + }, + SolidityFunction { + docs: &[], + selector: "toggleAllowed(address,address,bool) 4706cc1c", + name: "toggleAllowed", + mutability: SolidityMutability::Mutable, + args: ( + >::new("contractAddress"), + >::new("user"), + >::new("allowed"), + ), + result: >::default(), + }, + ), + }; + if is_impl { + tc . collect ("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n" . into ()) ; + } else { + tc . collect ("// Common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" . into ()) ; + } + let mut out = string::new(); + if "ContractHelpers".starts_with("Inline") { + out.push_str("// Inline\n"); + } + let _ = interface.format(is_impl, &mut out, tc); + tc.collect(out); + } + } + impl ::evm_coder::Call for ContractHelpersCall { + fn parse( + method_id: u32, + reader: &mut ::evm_coder::abi::AbiReader, + ) -> ::evm_coder::execution::Result> { + use ::evm_coder::abi::AbiRead; + match method_id { + ::evm_coder::ERC165Call::INTERFACE_ID => { + return Ok( + ::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call) + ) + } + Self::CONTRACT_OWNER => { + return Ok(Some(Self::ContractOwner { + contract_address: reader.abi_read()?, + })) + } + Self::SPONSORING_ENABLED => { + return Ok(Some(Self::SponsoringEnabled { + contract_address: reader.abi_read()?, + })) + } + Self::TOGGLE_SPONSORING => { + return Ok(Some(Self::ToggleSponsoring { + contract_address: reader.abi_read()?, + enabled: reader.abi_read()?, + })) + } + Self::SET_SPONSORING_RATE_LIMIT => { + return Ok(Some(Self::SetSponsoringRateLimit { + contract_address: reader.abi_read()?, + rate_limit: reader.abi_read()?, + })) + } + Self::GET_SPONSORING_RATE_LIMIT => { + return Ok(Some(Self::GetSponsoringRateLimit { + contract_address: reader.abi_read()?, + })) + } + Self::ALLOWED => { + return Ok(Some(Self::Allowed { + contract_address: reader.abi_read()?, + user: reader.abi_read()?, + })) + } + Self::ALLOWLIST_ENABLED => { + return Ok(Some(Self::AllowlistEnabled { + contract_address: reader.abi_read()?, + })) + } + Self::TOGGLE_ALLOWLIST => { + return Ok(Some(Self::ToggleAllowlist { + contract_address: reader.abi_read()?, + enabled: reader.abi_read()?, + })) + } + Self::TOGGLE_ALLOWED => { + return Ok(Some(Self::ToggleAllowed { + contract_address: reader.abi_read()?, + user: reader.abi_read()?, + allowed: reader.abi_read()?, + })) + } + _ => {} + } + return Ok(None); + } + } + impl ::evm_coder::Weighted for ContractHelpersCall { + fn weight(&self) -> ::evm_coder::execution::DispatchInfo { + type InternalCall = ContractHelpersCall; + match self { + InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface { .. }) => { + 100u64.into() + } + InternalCall::ContractOwner { .. } => ().into(), + InternalCall::SponsoringEnabled { .. } => ().into(), + InternalCall::ToggleSponsoring { .. } => ().into(), + InternalCall::SetSponsoringRateLimit { .. } => ().into(), + InternalCall::GetSponsoringRateLimit { .. } => ().into(), + InternalCall::Allowed { .. } => ().into(), + InternalCall::AllowlistEnabled { .. } => ().into(), + InternalCall::ToggleAllowlist { .. } => ().into(), + InternalCall::ToggleAllowed { .. } => ().into(), + } + } + } + impl ::evm_coder::Callable> for ContractHelpers { + #[allow(unreachable_code)] + fn call( + &mut self, + c: Msg, + ) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> { + use ::evm_coder::abi::AbiWrite; + type InternalCall = ContractHelpersCall; + match c.call { + InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface { + interface_id, + }) => { + let mut writer = ::evm_coder::abi::AbiWriter::default(); + writer.bool(&InternalCall::supports_interface(interface_id)); + return Ok(writer.into()); + } + _ => {} + } + let mut writer = ::evm_coder::abi::AbiWriter::default(); + match c.call { + InternalCall::ContractOwner { contract_address } => { + let result = self.contract_owner(contract_address)?; + (&result).into_result() + } + InternalCall::SponsoringEnabled { contract_address } => { + let result = self.sponsoring_enabled(contract_address)?; + (&result).into_result() + } + InternalCall::ToggleSponsoring { + contract_address, + enabled, + } => { + let result = + self.toggle_sponsoring(c.caller.clone(), contract_address, enabled)?; + (&result).into_result() + } + InternalCall::SetSponsoringRateLimit { + contract_address, + rate_limit, + } => { + let result = self.set_sponsoring_rate_limit( + c.caller.clone(), + contract_address, + rate_limit, + )?; + (&result).into_result() + } + InternalCall::GetSponsoringRateLimit { contract_address } => { + let result = self.get_sponsoring_rate_limit(contract_address)?; + (&result).into_result() + } + InternalCall::Allowed { + contract_address, + user, + } => { + let result = self.allowed(contract_address, user)?; + (&result).into_result() + } + InternalCall::AllowlistEnabled { contract_address } => { + let result = self.allowlist_enabled(contract_address)?; + (&result).into_result() + } + InternalCall::ToggleAllowlist { + contract_address, + enabled, + } => { + let result = + self.toggle_allowlist(c.caller.clone(), contract_address, enabled)?; + (&result).into_result() + } + InternalCall::ToggleAllowed { + contract_address, + user, + allowed, + } => { + let result = + self.toggle_allowed(c.caller.clone(), contract_address, user, allowed)?; + (&result).into_result() + } + _ => ::core::panicking::panic("internal error: entered unreachable code"), + } + } + } + pub struct HelpersOnMethodCall(PhantomData<*const T>); + impl OnMethodCall for HelpersOnMethodCall { + fn is_reserved(contract: &sp_core::H160) -> bool { + contract == &T::ContractAddress::get() + } + fn is_used(contract: &sp_core::H160) -> bool { + contract == &T::ContractAddress::get() + } + fn call( + source: &sp_core::H160, + target: &sp_core::H160, + gas_left: u64, + input: &[u8], + value: sp_core::U256, + ) -> Option { + if !>::allowed(*target, *source, true) { + return Some(PrecompileOutput { + exit_status: ExitReason::Revert(ExitRevert::Reverted), + cost: 0, + output: { + let mut writer = AbiWriter::new_call(147028384u32); + writer.string("Target contract is allowlisted"); + writer.finish() + }, + logs: ::alloc::vec::Vec::new(), + }); + } + if target != &T::ContractAddress::get() { + return None; + } + let helpers = ContractHelpers::(SubstrateRecorder::::new(*target, gas_left)); + pallet_evm_coder_substrate::call(*source, helpers, value, input) + } + fn get_code(contract: &sp_core::H160) -> Option> { + (contract == & T :: ContractAddress :: get ()) . then (| | b"`\xe0`@R`&`\x80\x81\x81R\x90a\x04\xf4`\xa09\x80Qa\x00&\x91`\x01\x91` \x90\x91\x01\x90a\x009V[P4\x80\x15a\x003W`\x00\x80\xfd[Pa\x01\rV[\x82\x80Ta\x00E\x90a\x00\xd2V[\x90`\x00R` `\x00 \x90`\x1f\x01` \x90\x04\x81\x01\x92\x82a\x00gW`\x00\x85Ua\x00\xadV[\x82`\x1f\x10a\x00\x80W\x80Q`\xff\x19\x16\x83\x80\x01\x17\x85Ua\x00\xadV[\x82\x80\x01`\x01\x01\x85U\x82\x15a\x00\xadW\x91\x82\x01[\x82\x81\x11\x15a\x00\xadW\x82Q\x82U\x91` \x01\x91\x90`\x01\x01\x90a\x00\x92V[Pa\x00\xb9\x92\x91Pa\x00\xbdV[P\x90V[[\x80\x82\x11\x15a\x00\xb9W`\x00\x81U`\x01\x01a\x00\xbeV[`\x01\x81\x81\x1c\x90\x82\x16\x80a\x00\xe6W`\x7f\x82\x16\x91P[` \x82\x10\x81\x14\x15a\x01\x07WcNH{q`\xe0\x1b`\x00R`\"`\x04R`$`\x00\xfd[P\x91\x90PV[a\x03\xd8\x80a\x01\x1c`\x009`\x00\xf3\xfe`\x80`@R4\x80\x15a\x00\x10W`\x00\x80\xfd[P`\x046\x10a\x00\x9eW`\x005`\xe0\x1c\x80c`\'\xdca\x11a\x00fW\x80c`\'\xdca\x14a\x01\"W\x80ca\x0c\xfa\xbd\x14a\x010W\x80cw\xb6\xc9\x08\x14a\x01SW\x80c\xc7r\xefl\x14a\x01\"W\x80c\xfc\xacm\x86\x14a\x00\xcbW`\x00\x80\xfd[\x80c\x01\xff\xc9\xa7\x14a\x00\xa3W\x80c6\xde \xf5\x14a\x00\xcbW\x80cG\x06\xcc\x1c\x14a\x00\xe0W\x80cQR\xb1L\x14a\x00\xeeW\x80c\\e\x81e\x14a\x01\x14W[`\x00\x80\xfd[a\x00\xb6a\x00\xb16`\x04a\x01\xa2V[a\x01aV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xf3[a\x00\xdea\x00\xd96`\x04a\x01\xffV[a\x01\x87V[\x00[a\x00\xdea\x00\xd96`\x04a\x022V[a\x00\xfca\x00\xb16`\x04a\x02uV[`@Q`\x01`\x01`\xa0\x1b\x03\x90\x91\x16\x81R` \x01a\x00\xc2V[a\x00\xb6a\x00\xb16`\x04a\x02\x90V[a\x00\xb6a\x00\xb16`\x04a\x02uV[a\x01>a\x00\xb16`\x04a\x02uV[`@Qc\xff\xff\xff\xff\x90\x91\x16\x81R` \x01a\x00\xc2V[a\x00\xdea\x00\xd96`\x04a\x02\xbaV[`\x00`\x01`@QbF\x1b\xcd`\xe5\x1b\x81R`\x04\x01a\x01~\x91\x90a\x02\xfaV[`@Q\x80\x91\x03\x90\xfd[`\x01`@QbF\x1b\xcd`\xe5\x1b\x81R`\x04\x01a\x01~\x91\x90a\x02\xfaV[`\x00` \x82\x84\x03\x12\x15a\x01\xb4W`\x00\x80\xfd[\x815`\x01`\x01`\xe0\x1b\x03\x19\x81\x16\x81\x14a\x01\xccW`\x00\x80\xfd[\x93\x92PPPV[\x805`\x01`\x01`\xa0\x1b\x03\x81\x16\x81\x14a\x01\xeaW`\x00\x80\xfd[\x91\x90PV[\x805\x80\x15\x15\x81\x14a\x01\xeaW`\x00\x80\xfd[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\x12W`\x00\x80\xfd[a\x02\x1b\x83a\x01\xd3V[\x91Pa\x02)` \x84\x01a\x01\xefV[\x90P\x92P\x92\x90PV[`\x00\x80`\x00``\x84\x86\x03\x12\x15a\x02GW`\x00\x80\xfd[a\x02P\x84a\x01\xd3V[\x92Pa\x02^` \x85\x01a\x01\xd3V[\x91Pa\x02l`@\x85\x01a\x01\xefV[\x90P\x92P\x92P\x92V[`\x00` \x82\x84\x03\x12\x15a\x02\x87W`\x00\x80\xfd[a\x01\xcc\x82a\x01\xd3V[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\xa3W`\x00\x80\xfd[a\x02\xac\x83a\x01\xd3V[\x91Pa\x02)` \x84\x01a\x01\xd3V[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\xcdW`\x00\x80\xfd[a\x02\xd6\x83a\x01\xd3V[\x91P` \x83\x015c\xff\xff\xff\xff\x81\x16\x81\x14a\x02\xefW`\x00\x80\xfd[\x80\x91PP\x92P\x92\x90PV[`\x00` \x80\x83R`\x00\x84T\x81`\x01\x82\x81\x1c\x91P\x80\x83\x16\x80a\x03\x1cW`\x7f\x83\x16\x92P[\x85\x83\x10\x81\x14\x15a\x03:WcNH{q`\xe0\x1b\x85R`\"`\x04R`$\x85\xfd[\x87\x86\x01\x83\x81R` \x01\x81\x80\x15a\x03WW`\x01\x81\x14a\x03hWa\x03\x93V[`\xff\x19\x86\x16\x82R\x87\x82\x01\x96Pa\x03\x93V[`\x00\x8b\x81R` \x90 `\x00[\x86\x81\x10\x15a\x03\x8dW\x81T\x84\x82\x01R\x90\x85\x01\x90\x89\x01a\x03tV[\x83\x01\x97PP[P\x94\x99\x98PPPPPPPPPV\xfe\xa2dipfsX\"\x12 \xde\xe1\xb0gnP\xa0\xbb\xa7\xaf\xbek+\xe6S6\n\xcd?\x0c+\x81\xebEq\x8c\xe3\xab\xaaC6UdsolcC\x00\x08\t\x003this contract is implemented in native" . to_vec ()) + } + } + pub struct HelpersOnCreate(PhantomData<*const T>); + impl OnCreate for HelpersOnCreate { + fn on_create(owner: H160, contract: H160) { + >::insert(contract, owner); + } + } + pub struct HelpersContractSponsoring(PhantomData<*const T>); + impl SponsorshipHandler)> for HelpersContractSponsoring { + fn get_sponsor(who: &H160, call: &(H160, Vec)) -> Option { + if >::get(&call.0) && >::allowed(call.0, *who, false) { + let block_number = >::block_number() as T::BlockNumber; + if let Some(last_tx_block) = >::get(&call.0, who) { + let rate_limit = >::get(&call.0); + let limit_time = last_tx_block + rate_limit; + if block_number > limit_time { + >::insert(&call.0, who, block_number); + return Some(call.0); + } + } else { + >::insert(&call.0, who, block_number); + return Some(call.0); + } + } + None + } + } +} +#[doc = r" + The module that hosts all the + [FRAME](https://docs.substrate.io/v3/runtime/frame) + types needed to add this pallet to a + runtime. + "] +pub mod pallet { + use evm_coder::execution::Result; + use frame_support::pallet_prelude::*; + use sp_core::H160; + #[doc = r" + Configuration trait of this pallet. + + Implement this type for a runtime in order to customize this pallet. + "] + pub trait Config: frame_system::Config + pallet_evm_coder_substrate::Config { + type ContractAddress: Get; + type DefaultSponsoringRateLimit: Get; + } + #[scale_info(skip_type_params(T), capture_docs = "always")] + #[doc = r" + Custom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors) + of this pallet. + "] + pub enum Error { + #[doc(hidden)] + #[codec(skip)] + __Ignore( + frame_support::sp_std::marker::PhantomData<(T)>, + frame_support::Never, + ), + #[doc = " This method is only executable by owner"] + NoPermission, + } + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const _: () = { + impl ::scale_info::TypeInfo for Error + where + frame_support::sp_std::marker::PhantomData<(T)>: ::scale_info::TypeInfo + 'static, + T: 'static, + { + type Identity = Self; + fn type_info() -> ::scale_info::Type { + :: scale_info :: Type :: builder () . path (:: scale_info :: Path :: new ("Error" , "pallet_evm_contract_helpers::pallet")) . type_params (< [_] > :: into_vec (box [:: scale_info :: TypeParameter :: new ("T" , :: core :: option :: Option :: None)])) . docs_always (& ["\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors)\n\t\t\tof this pallet.\n\t\t\t"]) . variant (:: scale_info :: build :: Variants :: new () . variant ("NoPermission" , | v | v . index (0usize as :: core :: primitive :: u8) . docs_always (& ["This method is only executable by owner"]))) + } + }; + }; + #[doc = r" + The [pallet](https://docs.substrate.io/v3/runtime/frame#pallets) implementing + the on-chain logic. + "] + pub struct Pallet(frame_support::sp_std::marker::PhantomData<(T)>); + const _: () = { + impl core::clone::Clone for Pallet { + fn clone(&self) -> Self { + Self(core::clone::Clone::clone(&self.0)) + } + } + }; + const _: () = { + impl core::cmp::Eq for Pallet {} + }; + const _: () = { + impl core::cmp::PartialEq for Pallet { + fn eq(&self, other: &Self) -> bool { + true && self.0 == other.0 + } + } + }; + const _: () = { + impl core::fmt::Debug for Pallet { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("Pallet").field(&self.0).finish() + } + } + }; + #[allow(type_alias_bounds)] + pub(super) type Owner = StorageMap< + _GeneratedPrefixForStorageOwner, + Twox128, + H160, + H160, + ValueQuery, + frame_support::traits::GetDefault, + frame_support::traits::GetDefault, + >; + #[allow(type_alias_bounds)] + pub(super) type SelfSponsoring = StorageMap< + _GeneratedPrefixForStorageSelfSponsoring, + Twox128, + H160, + bool, + ValueQuery, + frame_support::traits::GetDefault, + frame_support::traits::GetDefault, + >; + #[allow(type_alias_bounds)] + pub(super) type SponsoringRateLimit = StorageMap< + _GeneratedPrefixForStorageSponsoringRateLimit, + Twox128, + H160, + T::BlockNumber, + ValueQuery, + T::DefaultSponsoringRateLimit, + frame_support::traits::GetDefault, + >; + #[allow(type_alias_bounds)] + pub(super) type SponsorBasket = StorageDoubleMap< + _GeneratedPrefixForStorageSponsorBasket, + Twox128, + H160, + Twox128, + H160, + T::BlockNumber, + OptionQuery, + frame_support::traits::GetDefault, + frame_support::traits::GetDefault, + >; + #[allow(type_alias_bounds)] + pub(super) type AllowlistEnabled = StorageMap< + _GeneratedPrefixForStorageAllowlistEnabled, + Twox128, + H160, + bool, + ValueQuery, + frame_support::traits::GetDefault, + frame_support::traits::GetDefault, + >; + #[allow(type_alias_bounds)] + pub(super) type Allowlist = StorageDoubleMap< + _GeneratedPrefixForStorageAllowlist, + Twox128, + H160, + Twox128, + H160, + bool, + ValueQuery, + frame_support::traits::GetDefault, + frame_support::traits::GetDefault, + >; + impl Pallet { + pub fn toggle_sponsoring(contract: H160, enabled: bool) { + >::insert(contract, enabled); + } + pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) { + >::insert(contract, rate_limit); + } + #[doc = " Default is returned if allowlist is disabled"] + pub fn allowed(contract: H160, user: H160, default: bool) -> bool { + if !>::get(contract) { + return default; + } + >::get(&contract, &user) || >::get(&contract) == user + } + pub fn toggle_allowlist(contract: H160, enabled: bool) { + >::insert(contract, enabled) + } + pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) { + >::insert(contract, user, allowed); + } + pub fn ensure_owner(contract: H160, user: H160) -> Result<()> { + { + if !(>::get(&contract) == user) { + { + return Err("no permission".into()); + }; + } + }; + Ok(()) + } + } + impl Pallet { + #[doc(hidden)] + pub fn pallet_constants_metadata( + ) -> frame_support::sp_std::vec::Vec + { + ::alloc::vec::Vec::new() + } + } + impl Pallet { + pub fn error_metadata() -> Option { + Some(frame_support::metadata::PalletErrorMetadata { + ty: frame_support::scale_info::meta_type::>(), + }) + } + } + #[doc = r" Type alias to `Pallet`, to be used by `construct_runtime`."] + #[doc = r""] + #[doc = r" Generated by `pallet` attribute macro."] + #[deprecated(note = "use `Pallet` instead")] + #[allow(dead_code)] + pub type Module = Pallet; + impl frame_support::traits::GetStorageVersion for Pallet { + fn current_storage_version() -> frame_support::traits::StorageVersion { + frame_support::traits::StorageVersion::default() + } + fn on_chain_storage_version() -> frame_support::traits::StorageVersion { + frame_support::traits::StorageVersion::get::() + } + } + impl frame_support::traits::OnGenesis for Pallet { + fn on_genesis() { + let storage_version = frame_support::traits::StorageVersion::default(); + storage_version.put::(); + } + } + impl frame_support::traits::PalletInfoAccess for Pallet { + fn index() -> usize { + <::PalletInfo as frame_support::traits::PalletInfo>::index::< + Self, + >() + .expect( + "Pallet is part of the runtime because pallet `Config` trait is \ + implemented by the runtime", + ) + } + fn name() -> &'static str { + <::PalletInfo as frame_support::traits::PalletInfo>::name::< + Self, + >() + .expect( + "Pallet is part of the runtime because pallet `Config` trait is \ + implemented by the runtime", + ) + } + fn module_name() -> &'static str { + < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: module_name :: < Self > () . expect ("Pallet is part of the runtime because pallet `Config` trait is \ + implemented by the runtime") + } + fn crate_version() -> frame_support::traits::CrateVersion { + frame_support::traits::CrateVersion { + major: 0u16, + minor: 1u8, + patch: 0u8, + } + } + } + impl frame_support::traits::StorageInfoTrait for Pallet { + fn storage_info() -> frame_support::sp_std::vec::Vec { + #[allow(unused_mut)] + let mut res = ::alloc::vec::Vec::new(); + { + let mut storage_info = < Owner < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ; + res.append(&mut storage_info); + } + { + let mut storage_info = < SelfSponsoring < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ; + res.append(&mut storage_info); + } + { + let mut storage_info = < SponsoringRateLimit < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ; + res.append(&mut storage_info); + } + { + let mut storage_info = < SponsorBasket < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ; + res.append(&mut storage_info); + } + { + let mut storage_info = < AllowlistEnabled < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ; + res.append(&mut storage_info); + } + { + let mut storage_info = < Allowlist < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ; + res.append(&mut storage_info); + } + res + } + } + #[doc(hidden)] + pub mod __substrate_call_check { + #[doc(hidden)] + pub use __is_call_part_defined_0 as is_call_part_defined; + } + #[doc = r"Contains one variant per dispatchable that can be called by an extrinsic."] + #[codec(encode_bound())] + #[codec(decode_bound())] + #[scale_info(skip_type_params(T), capture_docs = "always")] + #[allow(non_camel_case_types)] + pub enum Call { + #[doc(hidden)] + #[codec(skip)] + __Ignore( + frame_support::sp_std::marker::PhantomData<(T,)>, + frame_support::Never, + ), + } + const _: () = { + impl core::fmt::Debug for Call { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match *self { + Self::__Ignore(ref _0, ref _1) => fmt + .debug_tuple("Call::__Ignore") + .field(&_0) + .field(&_1) + .finish(), + } + } + } + }; + const _: () = { + impl core::clone::Clone for Call { + fn clone(&self) -> Self { + match self { + Self::__Ignore(ref _0, ref _1) => { + Self::__Ignore(core::clone::Clone::clone(_0), core::clone::Clone::clone(_1)) + } + } + } + } + }; + const _: () = { + impl core::cmp::Eq for Call {} + }; + const _: () = { + impl core::cmp::PartialEq for Call { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::__Ignore(_0, _1), Self::__Ignore(_0_other, _1_other)) => { + true && _0 == _0_other && _1 == _1_other + } + } + } + } + }; + const _: () = { + #[allow(non_camel_case_types)] + impl ::codec::Encode for Call {} + impl ::codec::EncodeLike for Call {} + }; + const _: () = { + #[allow(non_camel_case_types)] + impl ::codec::Decode for Call { + fn decode<__CodecInputEdqy: ::codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, + ) -> ::core::result::Result { + match __codec_input_edqy + .read_byte() + .map_err(|e| e.chain("Could not decode `Call`, failed to read variant byte"))? + { + _ => ::core::result::Result::Err(<_ as ::core::convert::Into<_>>::into( + "Could not decode `Call`, variant doesn\'t exist", + )), + } + } + } + }; + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const _: () = { + impl ::scale_info::TypeInfo for Call + where + frame_support::sp_std::marker::PhantomData<(T,)>: ::scale_info::TypeInfo + 'static, + T: Config + 'static, + { + type Identity = Self; + fn type_info() -> ::scale_info::Type { + ::scale_info::Type::builder() + .path(::scale_info::Path::new( + "Call", + "pallet_evm_contract_helpers::pallet", + )) + .type_params(<[_]>::into_vec(box [::scale_info::TypeParameter::new( + "T", + ::core::option::Option::None, + )])) + .docs_always(&[ + "Contains one variant per dispatchable that can be called by an extrinsic.", + ]) + .variant(::scale_info::build::Variants::new()) + } + }; + }; + impl Call {} + impl frame_support::dispatch::GetDispatchInfo for Call { + fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo { + match *self { + Self::__Ignore(_, _) => { + ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__Ignore cannot be used",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + } + impl frame_support::dispatch::GetCallName for Call { + fn get_call_name(&self) -> &'static str { + match *self { + Self::__Ignore(_, _) => { + ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem cannot be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + fn get_call_names() -> &'static [&'static str] { + &[] + } + } + impl frame_support::traits::UnfilteredDispatchable for Call { + type Origin = frame_system::pallet_prelude::OriginFor; + fn dispatch_bypass_filter( + self, + origin: Self::Origin, + ) -> frame_support::dispatch::DispatchResultWithPostInfo { + match self { + Self::__Ignore(_, _) => { + let _ = origin; + { + { + ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem cannot be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + }; + } + } + } + } + impl frame_support::dispatch::Callable for Pallet { + type Call = Call; + } + impl Pallet { + #[doc(hidden)] + pub fn call_functions() -> frame_support::metadata::PalletCallMetadata { + frame_support::scale_info::meta_type::>().into() + } + } + impl frame_support::sp_std::fmt::Debug for Error { + fn fmt( + &self, + f: &mut frame_support::sp_std::fmt::Formatter<'_>, + ) -> frame_support::sp_std::fmt::Result { + f.write_str(self.as_str()) + } + } + impl Error { + pub fn as_u8(&self) -> u8 { + match &self { + Self::__Ignore(_, _) => { + ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + Self::NoPermission => 0usize as u8, + } + } + pub fn as_str(&self) -> &'static str { + match &self { + Self::__Ignore(_, _) => { + ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + Self::NoPermission => "NoPermission", + } + } + } + impl From> for &'static str { + fn from(err: Error) -> &'static str { + err.as_str() + } + } + impl From> for frame_support::sp_runtime::DispatchError { + fn from(err: Error) -> Self { + let index = < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: index :: < Pallet < T > > () . expect ("Every active module has an index in the runtime; qed") as u8 ; + frame_support::sp_runtime::DispatchError::Module { + index, + error: err.as_u8(), + message: Some(err.as_str()), + } + } + } + #[doc(hidden)] + pub mod __substrate_event_check { + #[doc(hidden)] + pub use __is_event_part_defined_1 as is_event_part_defined; + } + impl Pallet { + #[doc(hidden)] + pub fn storage_metadata() -> frame_support::metadata::PalletStorageMetadata { + frame_support :: metadata :: PalletStorageMetadata { prefix : < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: name :: < Pallet < T > > () . expect ("Every active pallet has a name in the runtime; qed") , entries : { # [allow (unused_mut)] let mut entries = :: alloc :: vec :: Vec :: new () ; { < Owner < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SelfSponsoring < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SponsoringRateLimit < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SponsorBasket < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < AllowlistEnabled < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < Allowlist < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } entries } , } + } + } + pub(super) struct _GeneratedPrefixForStorageOwner(core::marker::PhantomData<(T,)>); + impl frame_support::traits::StorageInstance for _GeneratedPrefixForStorageOwner { + fn pallet_prefix() -> &'static str { + <::PalletInfo as frame_support::traits::PalletInfo>::name::< + Pallet, + >() + .expect("Every active pallet has a name in the runtime; qed") + } + const STORAGE_PREFIX: &'static str = "Owner"; + } + pub(super) struct _GeneratedPrefixForStorageSelfSponsoring(core::marker::PhantomData<(T,)>); + impl frame_support::traits::StorageInstance + for _GeneratedPrefixForStorageSelfSponsoring + { + fn pallet_prefix() -> &'static str { + <::PalletInfo as frame_support::traits::PalletInfo>::name::< + Pallet, + >() + .expect("Every active pallet has a name in the runtime; qed") + } + const STORAGE_PREFIX: &'static str = "SelfSponsoring"; + } + pub(super) struct _GeneratedPrefixForStorageSponsoringRateLimit( + core::marker::PhantomData<(T,)>, + ); + impl frame_support::traits::StorageInstance + for _GeneratedPrefixForStorageSponsoringRateLimit + { + fn pallet_prefix() -> &'static str { + <::PalletInfo as frame_support::traits::PalletInfo>::name::< + Pallet, + >() + .expect("Every active pallet has a name in the runtime; qed") + } + const STORAGE_PREFIX: &'static str = "SponsoringRateLimit"; + } + pub(super) struct _GeneratedPrefixForStorageSponsorBasket(core::marker::PhantomData<(T,)>); + impl frame_support::traits::StorageInstance + for _GeneratedPrefixForStorageSponsorBasket + { + fn pallet_prefix() -> &'static str { + <::PalletInfo as frame_support::traits::PalletInfo>::name::< + Pallet, + >() + .expect("Every active pallet has a name in the runtime; qed") + } + const STORAGE_PREFIX: &'static str = "SponsorBasket"; + } + pub(super) struct _GeneratedPrefixForStorageAllowlistEnabled( + core::marker::PhantomData<(T,)>, + ); + impl frame_support::traits::StorageInstance + for _GeneratedPrefixForStorageAllowlistEnabled + { + fn pallet_prefix() -> &'static str { + <::PalletInfo as frame_support::traits::PalletInfo>::name::< + Pallet, + >() + .expect("Every active pallet has a name in the runtime; qed") + } + const STORAGE_PREFIX: &'static str = "AllowlistEnabled"; + } + pub(super) struct _GeneratedPrefixForStorageAllowlist(core::marker::PhantomData<(T,)>); + impl frame_support::traits::StorageInstance for _GeneratedPrefixForStorageAllowlist { + fn pallet_prefix() -> &'static str { + <::PalletInfo as frame_support::traits::PalletInfo>::name::< + Pallet, + >() + .expect("Every active pallet has a name in the runtime; qed") + } + const STORAGE_PREFIX: &'static str = "Allowlist"; + } + #[doc(hidden)] + pub mod __substrate_inherent_check { + #[doc(hidden)] + pub use __is_inherent_part_defined_2 as is_inherent_part_defined; + } + #[doc = r" Hidden instance generated to be internally used when module is used without"] + #[doc = r" instance."] + #[doc(hidden)] + pub type __InherentHiddenInstance = (); + pub(super) trait Store { + type Owner; + type SelfSponsoring; + type SponsoringRateLimit; + type SponsorBasket; + type AllowlistEnabled; + type Allowlist; + } + impl Store for Pallet { + type Owner = Owner; + type SelfSponsoring = SelfSponsoring; + type SponsoringRateLimit = SponsoringRateLimit; + type SponsorBasket = SponsorBasket; + type AllowlistEnabled = AllowlistEnabled; + type Allowlist = Allowlist; + } + impl frame_support::traits::Hooks<::BlockNumber> + for Pallet + { + } + impl frame_support::traits::OnFinalize<::BlockNumber> + for Pallet + { + fn on_finalize(n: ::BlockNumber) { + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_finalize", + "pallet_evm_contract_helpers::pallet", + ::tracing::Level::TRACE, + Some("pallets/evm-contract-helpers/src/lib.rs"), + Some(7u32), + Some("pallet_evm_contract_helpers::pallet"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } + && CALLSITE.is_enabled(interest) + { + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + let span = CALLSITE.disabled_span(); + {}; + span + } + }; + let __tracing_guard__ = __within_span__.enter(); + < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_finalize (n) + } + } + impl frame_support::traits::OnIdle<::BlockNumber> + for Pallet + { + fn on_idle( + n: ::BlockNumber, + remaining_weight: frame_support::weights::Weight, + ) -> frame_support::weights::Weight { + < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_idle (n , remaining_weight) + } + } + impl frame_support::traits::OnInitialize<::BlockNumber> + for Pallet + { + fn on_initialize( + n: ::BlockNumber, + ) -> frame_support::weights::Weight { + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_initialize", + "pallet_evm_contract_helpers::pallet", + ::tracing::Level::TRACE, + Some("pallets/evm-contract-helpers/src/lib.rs"), + Some(7u32), + Some("pallet_evm_contract_helpers::pallet"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } + && CALLSITE.is_enabled(interest) + { + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + let span = CALLSITE.disabled_span(); + {}; + span + } + }; + let __tracing_guard__ = __within_span__.enter(); + < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_initialize (n) + } + } + impl frame_support::traits::OnRuntimeUpgrade for Pallet { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_runtime_update", + "pallet_evm_contract_helpers::pallet", + ::tracing::Level::TRACE, + Some("pallets/evm-contract-helpers/src/lib.rs"), + Some(7u32), + Some("pallet_evm_contract_helpers::pallet"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } + && CALLSITE.is_enabled(interest) + { + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + let span = CALLSITE.disabled_span(); + {}; + span + } + }; + let __tracing_guard__ = __within_span__.enter(); + let pallet_name = < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: name :: < Self > () . unwrap_or ("") ; + { + let lvl = ::log::Level::Info; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["\u{2705} no migration for "], + &match (&pallet_name,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + ), + lvl, + &( + frame_support::LOG_TARGET, + "pallet_evm_contract_helpers::pallet", + "pallets/evm-contract-helpers/src/lib.rs", + 7u32, + ), + ); + } + }; + < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_runtime_upgrade () + } + } + impl frame_support::traits::OffchainWorker<::BlockNumber> + for Pallet + { + fn offchain_worker(n: ::BlockNumber) { + < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: offchain_worker (n) + } + } + impl frame_support::traits::IntegrityTest for Pallet { + fn integrity_test() { + < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: integrity_test () + } + } + #[doc(hidden)] + pub mod __substrate_genesis_config_check { + #[doc(hidden)] + pub use __is_genesis_config_defined_3 as is_genesis_config_defined; + #[doc(hidden)] + pub use __is_std_enabled_for_genesis_3 as is_std_enabled_for_genesis; + } + #[doc(hidden)] + pub mod __substrate_origin_check { + #[doc(hidden)] + pub use __is_origin_part_defined_4 as is_origin_part_defined; + } + #[doc(hidden)] + pub mod __substrate_validate_unsigned_check { + #[doc(hidden)] + pub use __is_validate_unsigned_part_defined_5 as is_validate_unsigned_part_defined; + } +} --- a/pallets/evm-contract-helpers/src/eth.rs +++ b/pallets/evm-contract-helpers/src/eth.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*}; -use pallet_evm_coder_substrate::SubstrateRecorder; +use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput}; use sp_core::H160; use crate::{ @@ -11,16 +11,23 @@ use sp_std::{convert::TryInto, vec::Vec}; struct ContractHelpers(SubstrateRecorder); +impl WithRecorder for ContractHelpers { + fn recorder(&self) -> &SubstrateRecorder { + &self.0 + } + fn into_recorder(self) -> SubstrateRecorder { + self.0 + } +} + #[solidity_interface(name = "ContractHelpers")] impl ContractHelpers { fn contract_owner(&self, contract_address: address) -> Result
{ - self.0.consume_sload()?; Ok(>::get(contract_address)) } fn sponsoring_enabled(&self, contract_address: address) -> Result { - self.0.consume_sload()?; Ok(>::get(contract_address)) } @@ -30,9 +37,7 @@ contract_address: address, enabled: bool, ) -> Result { - self.0.consume_sload()?; >::ensure_owner(contract_address, caller)?; - self.0.consume_sstore()?; >::toggle_sponsoring(contract_address, enabled); Ok(()) } @@ -43,27 +48,22 @@ contract_address: address, rate_limit: uint32, ) -> Result { - self.0.consume_sload()?; >::ensure_owner(contract_address, caller)?; - self.0.consume_sstore()?; >::set_sponsoring_rate_limit(contract_address, rate_limit.into()); Ok(()) } fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result { - self.0.consume_sload()?; Ok(>::get(contract_address) .try_into() .map_err(|_| "rate limit > u32::MAX")?) } fn allowed(&self, contract_address: address, user: address) -> Result { - self.0.consume_sload()?; Ok(>::allowed(contract_address, user, true)) } fn allowlist_enabled(&self, contract_address: address) -> Result { - self.0.consume_sload()?; Ok(>::get(contract_address)) } @@ -73,9 +73,7 @@ contract_address: address, enabled: bool, ) -> Result { - self.0.consume_sload()?; >::ensure_owner(contract_address, caller)?; - self.0.consume_sstore()?; >::toggle_allowlist(contract_address, enabled); Ok(()) } @@ -87,9 +85,7 @@ user: address, allowed: bool, ) -> Result { - self.0.consume_sload()?; >::ensure_owner(contract_address, caller)?; - self.0.consume_sstore()?; >::toggle_allowed(contract_address, user, allowed); Ok(()) } @@ -130,9 +126,8 @@ return None; } - let mut helpers = ContractHelpers::(SubstrateRecorder::::new(*target, gas_left)); - let result = pallet_evm_coder_substrate::call_internal(*source, &mut helpers, value, input); - helpers.0.evm_to_precompile_output(result) + let helpers = ContractHelpers::(SubstrateRecorder::::new(*target, gas_left)); + pallet_evm_coder_substrate::call(*source, helpers, value, input) } fn get_code(contract: &sp_core::H160) -> Option> { @@ -170,5 +165,5 @@ } } -generate_stubgen!(contract_helpers_impl, ContractHelpersCall, true); -generate_stubgen!(contract_helpers_iface, ContractHelpersCall, false); +generate_stubgen!(contract_helpers_impl, ContractHelpersCall<()>, true); +generate_stubgen!(contract_helpers_iface, ContractHelpersCall<()>, false); --- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol +++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol @@ -21,6 +21,7 @@ } } +// Selector: 31acb1fe contract ContractHelpers is Dummy, ERC165 { // Selector: contractOwner(address) 5152b14c function contractOwner(address contractAddress) --- a/pallets/evm-migration/Cargo.toml +++ b/pallets/evm-migration/Cargo.toml @@ -4,7 +4,9 @@ edition = "2018" [dependencies] -scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0.0", default-features = false, features = [ + "derive", +] } frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } @@ -12,8 +14,8 @@ sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } [dependencies.codec] default-features = false --- a/pallets/evm-transaction-payment/Cargo.toml +++ b/pallets/evm-transaction-payment/Cargo.toml @@ -4,16 +4,18 @@ edition = "2018" [dependencies] -scale-info = { version = "1.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "1.0.0", default-features = false, features = [ + "derive", +] } frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } up-sponsorship = { default-features = false, path = '../../primitives/sponsorship' } [dependencies.codec] --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -1,15 +1,18 @@ use core::char::{REPLACEMENT_CHARACTER, decode_utf16}; use core::convert::TryInto; -use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*}; +use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight}; use nft_data_structs::CollectionMode; use pallet_common::erc::CommonEvmHandler; use sp_core::{H160, U256}; use sp_std::vec::Vec; use pallet_common::account::CrossAccountId; use pallet_common::erc::PrecompileOutput; -use pallet_evm_coder_substrate::{call_internal, dispatch_to_evm}; +use pallet_evm_coder_substrate::{call, dispatch_to_evm}; -use crate::{Allowance, Balance, Config, FungibleHandle, Pallet, TotalSupply}; +use crate::{ + Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply, + weights::WeightInfo, +}; #[derive(ToLog)] pub enum ERC20Events { @@ -40,6 +43,7 @@ Ok(string::from_utf8_lossy(&self.token_prefix).into()) } fn total_supply(&self) -> Result { + self.consume_store_reads(1)?; Ok(>::get(self.id).into()) } @@ -51,10 +55,12 @@ }) } fn balance_of(&self, owner: address) -> Result { + self.consume_store_reads(1)?; let owner = T::CrossAccountId::from_eth(owner); let balance = >::get((self.id, owner)); Ok(balance.into()) } + #[weight(>::transfer())] fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); @@ -63,6 +69,7 @@ >::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?; Ok(true) } + #[weight(>::transfer_from())] fn transfer_from( &mut self, caller: caller, @@ -79,6 +86,7 @@ .map_err(dispatch_to_evm::)?; Ok(true) } + #[weight(>::approve())] fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); let spender = T::CrossAccountId::from_eth(spender); @@ -89,6 +97,7 @@ Ok(true) } fn allowance(&self, owner: address, spender: address) -> Result { + self.consume_store_reads(1)?; let owner = T::CrossAccountId::from_eth(owner); let spender = T::CrossAccountId::from_eth(spender); @@ -98,6 +107,7 @@ #[solidity_interface(name = "ERC20UniqueExtensions")] impl FungibleHandle { + #[weight(>::burn_from())] fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); let from = T::CrossAccountId::from_eth(from); @@ -111,14 +121,13 @@ #[solidity_interface(name = "UniqueFungible", is(ERC20))] impl FungibleHandle {} -generate_stubgen!(gen_impl, UniqueFungibleCall, true); -generate_stubgen!(gen_iface, UniqueFungibleCall, false); +generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true); +generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false); impl CommonEvmHandler for FungibleHandle { const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw"); - fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option { - let result = call_internal::(*source, &mut self, value, input); - self.0.recorder.evm_to_precompile_output(result) + fn call(self, source: &H160, input: &[u8], value: U256) -> Option { + call::, _>(*source, self, value, input) } } --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -6,6 +6,7 @@ use pallet_common::{ Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId, }; +use pallet_evm_coder_substrate::WithRecorder; use sp_core::H160; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult}; use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap}; @@ -82,6 +83,14 @@ self.0 } } +impl WithRecorder for FungibleHandle { + fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder { + self.0.recorder() + } + fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder { + self.0.into_recorder() + } +} impl Deref for FungibleHandle { type Target = pallet_common::CollectionHandle; @@ -136,7 +145,7 @@ } >::insert(collection.id, total_supply); - collection.log_infallible(ERC20Events::Transfer { + collection.log(ERC20Events::Transfer { from: *owner.as_eth(), to: H160::default(), value: amount.into(), @@ -179,11 +188,6 @@ } else { None }; - - collection.consume_sstore()?; - collection.consume_sstore()?; - collection.consume_log(2, 32)?; - collection.consume_sstore()?; // ========= @@ -197,7 +201,7 @@ >::insert((collection.id, to), balance_to); } - collection.log_infallible(ERC20Events::Transfer { + collection.log(ERC20Events::Transfer { from: *from.as_eth(), to: *to.as_eth(), value: amount.into(), @@ -217,8 +221,7 @@ sender: &T::CrossAccountId, data: Vec>, ) -> DispatchResult { - let unrestricted_minting = collection.is_owner_or_admin(sender)?; - if !unrestricted_minting { + if !collection.is_owner_or_admin(sender) { ensure!( collection.mint_mode, >::PublicMintingNotAllowed @@ -241,20 +244,12 @@ .ok_or(ArithmeticError::Overflow)?; for (user, amount) in data.into_iter() { - collection.consume_sload()?; let balance = balances .entry(user.clone()) .or_insert_with(|| >::get((collection.id, user))); *balance = (*balance) .checked_add(amount) .ok_or(ArithmeticError::Overflow)?; - } - - collection.consume_sstore()?; - for _ in &balances { - collection.consume_sstore()?; - collection.consume_log(2, 32)?; - collection.consume_sstore()?; } // ========= @@ -263,7 +258,7 @@ for (user, amount) in balances { >::insert((collection.id, &user), amount); - collection.log_infallible(ERC20Events::Transfer { + collection.log(ERC20Events::Transfer { from: H160::default(), to: *user.as_eth(), value: amount.into(), @@ -287,7 +282,7 @@ ) { >::insert((collection.id, owner, spender), amount); - collection.log_infallible(ERC20Events::Approval { + collection.log(ERC20Events::Approval { owner: *owner.as_eth(), spender: *spender.as_eth(), value: amount.into(), @@ -314,7 +309,7 @@ if >::get((collection.id, owner)) < amount { ensure!( - collection.ignores_owned_amount(owner)?, + collection.ignores_owned_amount(owner), >::CantApproveMoreThanOwned ); } @@ -343,7 +338,7 @@ let allowance = >::get((collection.id, from, spender)).checked_sub(amount); if allowance.is_none() { ensure!( - collection.ignores_allowance(spender)?, + collection.ignores_allowance(spender), >::TokenValueNotEnough ); } @@ -374,7 +369,7 @@ let allowance = >::get((collection.id, from, spender)).checked_sub(amount); if allowance.is_none() { ensure!( - collection.ignores_allowance(spender)?, + collection.ignores_allowance(spender), >::TokenValueNotEnough ); } --- a/pallets/nft/Cargo.toml +++ b/pallets/nft/Cargo.toml @@ -146,9 +146,9 @@ "serde_no_std", ] } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } hex-literal = "0.3.3" pallet-common = { default-features = false, path = "../common" } --- a/pallets/nft/src/benchmarking.rs +++ b/pallets/nft/src/benchmarking.rs @@ -155,12 +155,13 @@ let cl = CollectionLimits { account_token_ownership_limit: Some(0), - sponsored_data_size: 0, - token_limit: 1, - sponsor_transfer_timeout: 0, - owner_can_destroy: true, - owner_can_transfer: true, + sponsored_data_size: Some(0), + token_limit: Some(1), + sponsor_transfer_timeout: Some(0), + owner_can_destroy: Some(true), + owner_can_transfer: Some(true), sponsored_data_rate_limit: None, + transfers_enabled: Some(true), }; }: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl) --- a/pallets/nft/src/dispatch.rs +++ b/pallets/nft/src/dispatch.rs @@ -83,10 +83,6 @@ _ => {} } - // TODO: Make submit_logs infallible, but it shouldn't fail here anyway - dispatched - .into_inner() - .submit_logs() - .expect("should succeed"); + dispatched.into_inner().submit_logs(); result } --- a/pallets/nft/src/eth/sponsoring.rs +++ b/pallets/nft/src/eth/sponsoring.rs @@ -31,7 +31,7 @@ let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?; match &collection.mode { crate::CollectionMode::NFT => { - let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader) + let call = >::parse(method_id, &mut reader) .map_err(|_| AnyError)? .ok_or(AnyError)?; match call { @@ -63,7 +63,7 @@ } } crate::CollectionMode::Fungible(_) => { - let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader) + let call = >::parse(method_id, &mut reader) .map_err(|_| AnyError)? .ok_or(AnyError)?; #[allow(clippy::single_match)] --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -2,18 +2,19 @@ char::{REPLACEMENT_CHARACTER, decode_utf16}, convert::TryInto, }; -use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*}; +use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight}; use frame_support::BoundedVec; use nft_data_structs::TokenId; use pallet_evm_coder_substrate::dispatch_to_evm; use sp_core::{H160, U256}; use sp_std::{vec::Vec, vec}; use pallet_common::{account::CrossAccountId, erc::CommonEvmHandler}; -use pallet_evm_coder_substrate::call_internal; +use pallet_evm_coder_substrate::call; use pallet_common::erc::PrecompileOutput; use crate::{ AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted, + SelfWeightOf, weights::WeightInfo, }; #[derive(ToLog)] @@ -64,6 +65,7 @@ /// Returns token's const_metadata #[solidity(rename_selector = "tokenURI")] fn token_uri(&self, token_id: uint256) -> Result { + self.consume_store_reads(1)?; let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; Ok(string::from_utf8_lossy( &>::get((self.id, token_id)) @@ -87,6 +89,7 @@ } fn total_supply(&self) -> Result { + self.consume_store_reads(1)?; Ok(>::total_supply(self).into()) } } @@ -94,11 +97,13 @@ #[solidity_interface(name = "ERC721", events(ERC721Events))] impl NonfungibleHandle { fn balance_of(&self, owner: address) -> Result { + self.consume_store_reads(1)?; let owner = T::CrossAccountId::from_eth(owner); let balance = >::get((self.id, owner)); Ok(balance.into()) } fn owner_of(&self, token_id: uint256) -> Result
{ + self.consume_store_reads(1)?; let token: TokenId = token_id.try_into()?; Ok(*>::get((self.id, token)) .ok_or("token not found")? @@ -129,6 +134,7 @@ Err("not implemented".into()) } + #[weight(>::transfer_from())] fn transfer_from( &mut self, caller: caller, @@ -147,6 +153,7 @@ Ok(()) } + #[weight(>::approve())] fn approve( &mut self, caller: caller, @@ -189,6 +196,7 @@ #[solidity_interface(name = "ERC721Burnable")] impl NonfungibleHandle { + #[weight(>::burn_item())] fn burn(&mut self, caller: caller, token_id: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); let token = token_id.try_into()?; @@ -206,6 +214,7 @@ /// `token_id` should be obtained with `next_token_id` method, /// unlike standard, you can't specify it manually + #[weight(>::create_item())] fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); @@ -235,6 +244,7 @@ /// `token_id` should be obtained with `next_token_id` method, /// unlike standard, you can't specify it manually #[solidity(rename_selector = "mintWithTokenURI")] + #[weight(>::create_item())] fn mint_with_token_uri( &mut self, caller: caller, @@ -276,6 +286,7 @@ #[solidity_interface(name = "ERC721UniqueExtensions")] impl NonfungibleHandle { + #[weight(>::transfer())] fn transfer( &mut self, caller: caller, @@ -291,6 +302,7 @@ Ok(()) } + #[weight(>::burn_from())] fn burn_from( &mut self, caller: caller, @@ -307,12 +319,14 @@ } fn next_token_id(&self) -> Result { + self.consume_store_reads(1)?; Ok(>::get(self.id) .checked_add(1) .ok_or("item id overflow")? .into()) } + #[weight(>::set_variable_metadata(data.len() as u32))] fn set_variable_metadata( &mut self, caller: caller, @@ -328,6 +342,7 @@ } fn get_variable_metadata(&self, token_id: uint256) -> Result { + self.consume_store_reads(1)?; let token: TokenId = token_id.try_into()?; Ok(>::get((self.id, token)) @@ -335,6 +350,7 @@ .variable_data) } + #[weight(>::create_multiple_items(token_ids.len() as u32))] fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec) -> Result { let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); @@ -363,6 +379,7 @@ } #[solidity(rename_selector = "mintBulkWithTokenURI")] + #[weight(>::create_multiple_items(tokens.len() as u32))] fn mint_bulk_with_token_uri( &mut self, caller: caller, @@ -411,16 +428,13 @@ impl NonfungibleHandle {} // Not a tests, but code generators -generate_stubgen!(gen_impl, UniqueNFTCall, true); -generate_stubgen!(gen_iface, UniqueNFTCall, false); - -pub const CODE: &[u8] = include_bytes!("./stubs/UniqueNFT.raw"); +generate_stubgen!(gen_impl, UniqueNFTCall<()>, true); +generate_stubgen!(gen_iface, UniqueNFTCall<()>, false); impl CommonEvmHandler for NonfungibleHandle { const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw"); - fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option { - let result = call_internal::(*source, &mut self, value, input); - self.0.recorder.evm_to_precompile_output(result) + fn call(self, source: &H160, input: &[u8], value: U256) -> Option { + call::, _>(*source, self, value, input) } } --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -8,6 +8,7 @@ use pallet_common::{ Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId, }; +use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; use sp_core::H160; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult}; use sp_std::{vec::Vec, vec}; @@ -114,6 +115,14 @@ self.0 } } +impl WithRecorder for NonfungibleHandle { + fn recorder(&self) -> &SubstrateRecorder { + self.0.recorder() + } + fn into_recorder(self) -> SubstrateRecorder { + self.0.into_recorder() + } +} impl Deref for NonfungibleHandle { type Target = pallet_common::CollectionHandle; @@ -164,8 +173,7 @@ .ok_or_else(|| >::TokenNotFound)?; ensure!( &token_data.owner == sender - || (collection.limits.owner_can_transfer() - && collection.is_owner_or_admin(sender)?), + || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(sender)), >::NoPermission ); @@ -194,7 +202,7 @@ )); } - collection.log_infallible(ERC721Events::Transfer { + collection.log(ERC721Events::Transfer { from: *token_data.owner.as_eth(), to: H160::default(), token_id: token.into(), @@ -223,8 +231,7 @@ .ok_or_else(|| >::TokenNotFound)?; ensure!( &token_data.owner == from - || (collection.limits.owner_can_transfer() - && collection.is_owner_or_admin(from)?), + || (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(from)), >::NoPermission ); @@ -251,9 +258,6 @@ } else { None }; - - collection.consume_sstores(4)?; - collection.consume_log(3, 0)?; // ========= @@ -278,7 +282,7 @@ } Self::set_allowance_unchecked(collection, from, token, None, true); - collection.log_infallible(ERC721Events::Transfer { + collection.log(ERC721Events::Transfer { from: *from.as_eth(), to: *to.as_eth(), token_id: token.into(), @@ -298,8 +302,7 @@ sender: &T::CrossAccountId, data: Vec>, ) -> DispatchResult { - let unrestricted_minting = collection.is_owner_or_admin(sender)?; - if !unrestricted_minting { + if !collection.is_owner_or_admin(sender) { ensure!( collection.mint_mode, >::PublicMintingNotAllowed @@ -313,14 +316,6 @@ for data in data.iter() { >::ensure_correct_receiver(&data.owner)?; - if !data.const_data.is_empty() { - collection.consume_sstore()?; - } - if !data.variable_data.is_empty() { - collection.consume_sstore()?; - } - collection.consume_sstore()?; - collection.consume_log(3, 0)?; } let first_token = >::get(collection.id); @@ -331,7 +326,6 @@ tokens_minted < collection.limits.token_limit(), >::CollectionTokenLimitExceeded ); - collection.consume_sstore()?; let mut balances = BTreeMap::new(); for data in &data { @@ -345,7 +339,6 @@ >::AccountTokenLimitExceeded, ); } - collection.consume_sstores(balances.len())?; // ========= @@ -366,7 +359,7 @@ ); >::insert((collection.id, &data.owner, token), true); - collection.log_infallible(ERC721Events::Transfer { + collection.log(ERC721Events::Transfer { from: H160::default(), to: *data.owner.as_eth(), token_id: token.into(), @@ -393,7 +386,7 @@ >::insert((collection.id, token), spender); // In ERC721 there is only one possible approved user of token, so we set // approved user to spender - collection.log_infallible(ERC721Events::Approval { + collection.log(ERC721Events::Approval { owner: *sender.as_eth(), approved: *spender.as_eth(), token_id: token.into(), @@ -423,7 +416,7 @@ if !assume_implicit_eth { // In ERC721 there is only one possible approved user of token, so we set // approved user to zero address - collection.log_infallible(ERC721Events::Approval { + collection.log(ERC721Events::Approval { owner: *sender.as_eth(), approved: H160::default(), token_id: token.into(), @@ -463,7 +456,7 @@ >::get((collection.id, token)).ok_or(>::TokenNotFound)?; if &token_data.owner != sender { ensure!( - collection.ignores_owned_amount(sender)?, + collection.ignores_owned_amount(sender), >::CantApproveMoreThanOwned ); } @@ -491,7 +484,7 @@ if >::get((collection.id, token)).as_ref() != Some(spender) { ensure!( - collection.ignores_allowance(spender)?, + collection.ignores_allowance(spender), >::TokenValueNotEnough ); } @@ -519,7 +512,7 @@ if >::get((collection.id, token)).as_ref() != Some(spender) { ensure!( - collection.ignores_allowance(spender)?, + collection.ignores_allowance(spender), >::TokenValueNotEnough ); } @@ -542,8 +535,6 @@ let token_data = >::get((collection.id, token)).ok_or(>::TokenNotFound)?; collection.check_can_update_meta(sender, &token_data.owner)?; - - collection.consume_sstore()?; // ========= --- a/pallets/refungible/src/common.rs +++ b/pallets/refungible/src/common.rs @@ -58,7 +58,7 @@ } fn burn_from() -> Weight { - 0 + >::burn_from() } fn set_variable_metadata(bytes: u32) -> Weight { --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -359,8 +359,7 @@ sender: &T::CrossAccountId, data: Vec>, ) -> DispatchResult { - let unrestricted_minting = collection.is_owner_or_admin(sender)?; - if !unrestricted_minting { + if !collection.is_owner_or_admin(sender) { ensure!( collection.mint_mode, >::PublicMintingNotAllowed @@ -492,7 +491,7 @@ if >::get((collection.id, token, sender)) < amount { ensure!( - collection.ignores_owned_amount(sender)? && Self::token_exists(collection, token), + collection.ignores_owned_amount(sender) && Self::token_exists(collection, token), >::CantApproveMoreThanOwned ); } @@ -523,7 +522,7 @@ >::get((collection.id, token, from, &spender)).checked_sub(amount); if allowance.is_none() { ensure!( - collection.ignores_allowance(spender)?, + collection.ignores_allowance(spender), >::TokenValueNotEnough ); } @@ -556,7 +555,7 @@ >::get((collection.id, token, from, &spender)).checked_sub(amount); if allowance.is_none() { ensure!( - collection.ignores_allowance(spender)?, + collection.ignores_allowance(spender), >::TokenValueNotEnough ); } @@ -585,7 +584,6 @@ &T::CrossAccountId::from_sub(collection.owner.clone()), )?; - collection.consume_sstore()?; let token_data = >::get((collection.id, token)); // ========= --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -387,10 +387,10 @@ pallet-evm-transaction-payment = { path = '../pallets/evm-transaction-payment', default-features = false } pallet-evm-coder-substrate = { default-features = false, path = "../pallets/evm-coder-substrate" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } -fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } +fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" } ################################################################################ # Build Dependencies --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -66,7 +66,7 @@ }; use smallvec::smallvec; use codec::{Encode, Decode}; -use pallet_evm::{Account as EVMAccount, FeeCalculator, OnMethodCall}; +use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall}; use fp_rpc::TransactionStatus; use sp_core::crypto::Public; use sp_runtime::{ @@ -247,10 +247,37 @@ } } +// Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case +// (contract, which only writes a lot of data), +// approximating on top of our real store write weight +parameter_types! { + pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND / ::DbWeight::get().write; + pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000; + pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get(); +} + +/// Limiting EVM execution to 50% of block for substrate users and management tasks +/// EVM transaction consumes more weight than substrate's, so we can't rely on them being +/// scheduled fairly +const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50); +parameter_types! { + pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get()); +} + +pub enum FixedGasWeightMapping {} +impl GasWeightMapping for FixedGasWeightMapping { + fn gas_to_weight(gas: u64) -> Weight { + gas.saturating_mul(WeightPerGas::get()) + } + fn weight_to_gas(weight: Weight) -> u64 { + weight / WeightPerGas::get() + } +} + impl pallet_evm::Config for Runtime { type BlockGasLimit = BlockGasLimit; type FeeCalculator = FixedFee; - type GasWeightMapping = (); + type GasWeightMapping = FixedGasWeightMapping; type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = EnsureAddressTruncated; type WithdrawOrigin = EnsureAddressTruncated; @@ -289,14 +316,9 @@ } } -parameter_types! { - pub BlockGasLimit: U256 = U256::from(u32::max_value()); -} - impl pallet_ethereum::Config for Runtime { type Event = Event; type StateRoot = pallet_ethereum::IntermediateStateRoot; - type EvmSubmitLog = pallet_evm::Pallet; } impl pallet_randomness_collective_flip::Config for Runtime {} @@ -671,6 +693,7 @@ impl pallet_evm_coder_substrate::Config for Runtime { type EthereumTransactionSender = pallet_ethereum::Pallet; + type GasWeightMapping = FixedGasWeightMapping; } impl pallet_xcm::Config for Runtime {