mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-08 03:08:06 +00:00
contracts: Improve contract address derivation (#12883)
* Add prefix to address derivation * Extend benchmark * Fix node test * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Adapt to new benchmark * Update dispatchable benchmarks * ".git/.scripts/bench-bot.sh" pallet dev pallet_contracts * Use benchmark results * Apply suggestions from code review Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * Don't use T::AdressGenerator directly * Rename constructor_args to input_data Co-authored-by: command-bot <> Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
This commit is contained in:
committed by
GitHub
parent
af15848be0
commit
4083b5358a
@@ -654,7 +654,8 @@ fn deploying_wasm_contract_should_work() {
|
||||
let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap();
|
||||
let transfer_ch = <Runtime as frame_system::Config>::Hashing::hash(&transfer_code);
|
||||
|
||||
let addr = pallet_contracts::Pallet::<Runtime>::contract_address(&charlie(), &transfer_ch, &[]);
|
||||
let addr =
|
||||
pallet_contracts::Pallet::<Runtime>::contract_address(&charlie(), &transfer_ch, &[], &[]);
|
||||
|
||||
let time = 42 * 1000;
|
||||
let b = construct_block(
|
||||
|
||||
@@ -404,11 +404,7 @@ fn expand_impls(def: &mut EnvDef) -> TokenStream2 {
|
||||
let dummy_impls = expand_functions(def, false, quote! { () });
|
||||
|
||||
quote! {
|
||||
impl<'a, E> crate::wasm::Environment<crate::wasm::runtime::Runtime<'a, E>> for Env
|
||||
where
|
||||
E: Ext,
|
||||
<E::T as ::frame_system::Config>::AccountId:
|
||||
::sp_core::crypto::UncheckedFrom<<E::T as ::frame_system::Config>::Hash> + ::core::convert::AsRef<[::core::primitive::u8]>,
|
||||
impl<'a, E: Ext> crate::wasm::Environment<crate::wasm::runtime::Runtime<'a, E>> for Env
|
||||
{
|
||||
fn define(store: &mut ::wasmi::Store<crate::wasm::Runtime<E>>, linker: &mut ::wasmi::Linker<crate::wasm::Runtime<E>>, allow_unstable: bool) -> Result<(), ::wasmi::errors::LinkerError> {
|
||||
#impls
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
use crate::{Config, Determinism};
|
||||
use frame_support::traits::Get;
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_runtime::traits::Hash;
|
||||
use sp_std::{borrow::ToOwned, prelude::*};
|
||||
use wasm_instrument::{
|
||||
@@ -105,11 +104,7 @@ pub struct ImportedMemory {
|
||||
}
|
||||
|
||||
impl ImportedMemory {
|
||||
pub fn max<T: Config>() -> Self
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
pub fn max<T: Config>() -> Self {
|
||||
let pages = max_pages::<T>();
|
||||
Self { min_pages: pages, max_pages: pages }
|
||||
}
|
||||
@@ -130,11 +125,7 @@ pub struct WasmModule<T: Config> {
|
||||
pub memory: Option<ImportedMemory>,
|
||||
}
|
||||
|
||||
impl<T: Config> From<ModuleDefinition> for WasmModule<T>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> From<ModuleDefinition> for WasmModule<T> {
|
||||
fn from(def: ModuleDefinition) -> Self {
|
||||
// internal functions start at that offset.
|
||||
let func_offset = u32::try_from(def.imported_functions.len()).unwrap();
|
||||
@@ -259,11 +250,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> WasmModule<T>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> WasmModule<T> {
|
||||
/// Uses the supplied wasm module and instruments it when requested.
|
||||
pub fn instrumented(code: &[u8], inject_gas: bool, inject_stack: bool) -> Self {
|
||||
let module = {
|
||||
@@ -533,11 +520,7 @@ pub mod body {
|
||||
}
|
||||
|
||||
/// The maximum amount of pages any contract is allowed to have according to the current `Schedule`.
|
||||
pub fn max_pages<T: Config>() -> u32
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
pub fn max_pages<T: Config>() -> u32 {
|
||||
T::Schedule::get().limits.memory_pages
|
||||
}
|
||||
|
||||
|
||||
@@ -63,8 +63,6 @@ struct Contract<T: Config> {
|
||||
|
||||
impl<T: Config> Contract<T>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
<BalanceOf<T> as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode,
|
||||
{
|
||||
/// Create new contract and use a default account id as instantiator.
|
||||
@@ -90,7 +88,7 @@ where
|
||||
let value = Pallet::<T>::min_balance();
|
||||
T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
|
||||
let salt = vec![0xff];
|
||||
let addr = Contracts::<T>::contract_address(&caller, &module.hash, &salt);
|
||||
let addr = Contracts::<T>::contract_address(&caller, &module.hash, &data, &salt);
|
||||
|
||||
Contracts::<T>::store_code_raw(module.code, caller.clone())?;
|
||||
Contracts::<T>::instantiate(
|
||||
@@ -203,8 +201,6 @@ macro_rules! load_benchmark {
|
||||
|
||||
benchmarks! {
|
||||
where_clause { where
|
||||
T::AccountId: UncheckedFrom<T::Hash>,
|
||||
T::AccountId: AsRef<[u8]>,
|
||||
<BalanceOf<T> as codec::HasCompact>::Type: Clone + Eq + PartialEq + sp_std::fmt::Debug + scale_info::TypeInfo + codec::Encode,
|
||||
}
|
||||
|
||||
@@ -270,6 +266,7 @@ benchmarks! {
|
||||
// a code of that size into the sandbox.
|
||||
//
|
||||
// `c`: Size of the code in kilobytes.
|
||||
// `i`: Size of the input in kilobytes.
|
||||
// `s`: Size of the salt in kilobytes.
|
||||
//
|
||||
// # Note
|
||||
@@ -278,15 +275,17 @@ benchmarks! {
|
||||
// to be larger than the maximum size **after instrumentation**.
|
||||
instantiate_with_code {
|
||||
let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get());
|
||||
let i in 0 .. code::max_pages::<T>() * 64 * 1024;
|
||||
let s in 0 .. code::max_pages::<T>() * 64 * 1024;
|
||||
let input = vec![42u8; i as usize];
|
||||
let salt = vec![42u8; s as usize];
|
||||
let value = Pallet::<T>::min_balance();
|
||||
let caller = whitelisted_caller();
|
||||
T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
|
||||
let WasmModule { code, hash, .. } = WasmModule::<T>::sized(c, Location::Call);
|
||||
let origin = RawOrigin::Signed(caller.clone());
|
||||
let addr = Contracts::<T>::contract_address(&caller, &hash, &salt);
|
||||
}: _(origin, value, Weight::MAX, None, code, vec![], salt)
|
||||
let addr = Contracts::<T>::contract_address(&caller, &hash, &input, &salt);
|
||||
}: _(origin, value, Weight::MAX, None, code, input, salt)
|
||||
verify {
|
||||
// the contract itself does not trigger any reserves
|
||||
let deposit = T::Currency::reserved_balance(&addr);
|
||||
@@ -303,18 +302,21 @@ benchmarks! {
|
||||
}
|
||||
|
||||
// Instantiate uses a dummy contract constructor to measure the overhead of the instantiate.
|
||||
// `i`: Size of the input in kilobytes.
|
||||
// `s`: Size of the salt in kilobytes.
|
||||
instantiate {
|
||||
let i in 0 .. code::max_pages::<T>() * 64 * 1024;
|
||||
let s in 0 .. code::max_pages::<T>() * 64 * 1024;
|
||||
let input = vec![42u8; i as usize];
|
||||
let salt = vec![42u8; s as usize];
|
||||
let value = Pallet::<T>::min_balance();
|
||||
let caller = whitelisted_caller();
|
||||
T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
|
||||
let WasmModule { code, hash, .. } = WasmModule::<T>::dummy();
|
||||
let origin = RawOrigin::Signed(caller.clone());
|
||||
let addr = Contracts::<T>::contract_address(&caller, &hash, &salt);
|
||||
let addr = Contracts::<T>::contract_address(&caller, &hash, &input, &salt);
|
||||
Contracts::<T>::store_code_raw(code, caller.clone())?;
|
||||
}: _(origin, value, Weight::MAX, None, hash, vec![], salt)
|
||||
}: _(origin, value, Weight::MAX, None, hash, input, salt)
|
||||
verify {
|
||||
// the contract itself does not trigger any reserves
|
||||
let deposit = T::Currency::reserved_balance(&addr);
|
||||
@@ -1779,7 +1781,7 @@ benchmarks! {
|
||||
let addresses = hashes
|
||||
.iter()
|
||||
.map(|hash| Contracts::<T>::contract_address(
|
||||
&instance.account_id, hash, &[],
|
||||
&instance.account_id, hash, &[], &[],
|
||||
))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -1796,8 +1798,9 @@ benchmarks! {
|
||||
}
|
||||
}
|
||||
|
||||
seal_instantiate_per_transfer_salt_kb {
|
||||
seal_instantiate_per_transfer_input_salt_kb {
|
||||
let t in 0 .. 1;
|
||||
let i in 0 .. (code::max_pages::<T>() - 1) * 64;
|
||||
let s in 0 .. (code::max_pages::<T>() - 1) * 64;
|
||||
let callee_code = WasmModule::<T>::dummy();
|
||||
let hash = callee_code.hash;
|
||||
@@ -1865,14 +1868,14 @@ benchmarks! {
|
||||
Regular(Instruction::I64Const(0)), // gas
|
||||
Regular(Instruction::I32Const(value_offset as i32)), // value_ptr
|
||||
Regular(Instruction::I32Const(value_len as i32)), // value_len
|
||||
Regular(Instruction::I32Const(0)), // input_data_ptr
|
||||
Regular(Instruction::I32Const(0)), // input_data_len
|
||||
Counter(salt_offset as u32, salt_len as u32), // input_data_ptr
|
||||
Regular(Instruction::I32Const((i * 1024) as i32)), // input_data_len
|
||||
Regular(Instruction::I32Const((addr_len_offset + addr_len) as i32)), // address_ptr
|
||||
Regular(Instruction::I32Const(addr_len_offset as i32)), // address_len_ptr
|
||||
Regular(Instruction::I32Const(SENTINEL as i32)), // output_ptr
|
||||
Regular(Instruction::I32Const(0)), // output_len_ptr
|
||||
Counter(salt_offset as u32, salt_len as u32), // salt_ptr
|
||||
Regular(Instruction::I32Const((s * 1024).max(salt_len as u32) as i32)), // salt_len
|
||||
Regular(Instruction::I32Const((s * 1024) as i32)), // salt_len
|
||||
Regular(Instruction::Call(0)),
|
||||
Regular(Instruction::I32Eqz),
|
||||
Regular(Instruction::If(BlockType::NoResult)),
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
/// ! environment that provides the seal interface as imported functions.
|
||||
use super::{code::WasmModule, Config};
|
||||
use crate::wasm::{Environment, PrefabWasmModule};
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use wasmi::{errors::LinkerError, Func, Linker, StackLimits, Store};
|
||||
|
||||
/// Minimal execution environment without any imported functions.
|
||||
@@ -36,11 +35,7 @@ impl Sandbox {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> From<&WasmModule<T>> for Sandbox
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> From<&WasmModule<T>> for Sandbox {
|
||||
/// Creates an instance from the supplied module and supplies as much memory
|
||||
/// to the instance as the module declares as imported.
|
||||
fn from(module: &WasmModule<T>) -> Self {
|
||||
|
||||
@@ -83,7 +83,6 @@ use sp_std::{marker::PhantomData, vec::Vec};
|
||||
pub use crate::{exec::Ext, Config};
|
||||
pub use frame_system::Config as SysConfig;
|
||||
pub use pallet_contracts_primitives::ReturnFlags;
|
||||
pub use sp_core::crypto::UncheckedFrom;
|
||||
|
||||
/// Result that returns a [`DispatchError`] on error.
|
||||
pub type Result<T> = sp_std::result::Result<T, DispatchError>;
|
||||
@@ -114,10 +113,7 @@ pub trait ChainExtension<C: Config> {
|
||||
/// In case of `Err` the contract execution is immediately suspended and the passed error
|
||||
/// is returned to the caller. Otherwise the value of [`RetVal`] determines the exit
|
||||
/// behaviour.
|
||||
fn call<E>(&mut self, env: Environment<E, InitState>) -> Result<RetVal>
|
||||
where
|
||||
E: Ext<T = C>,
|
||||
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>;
|
||||
fn call<E: Ext<T = C>>(&mut self, env: Environment<E, InitState>) -> Result<RetVal>;
|
||||
|
||||
/// Determines whether chain extensions are enabled for this chain.
|
||||
///
|
||||
@@ -153,11 +149,7 @@ pub trait RegisteredChainExtension<C: Config>: ChainExtension<C> {
|
||||
#[impl_trait_for_tuples::impl_for_tuples(10)]
|
||||
#[tuple_types_custom_trait_bound(RegisteredChainExtension<C>)]
|
||||
impl<C: Config> ChainExtension<C> for Tuple {
|
||||
fn call<E>(&mut self, mut env: Environment<E, InitState>) -> Result<RetVal>
|
||||
where
|
||||
E: Ext<T = C>,
|
||||
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
fn call<E: Ext<T = C>>(&mut self, mut env: Environment<E, InitState>) -> Result<RetVal> {
|
||||
for_tuples!(
|
||||
#(
|
||||
if (Tuple::ID == env.ext_id()) && Tuple::enabled() {
|
||||
@@ -205,10 +197,7 @@ pub struct Environment<'a, 'b, E: Ext, S: State> {
|
||||
}
|
||||
|
||||
/// Functions that are available in every state of this type.
|
||||
impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S>
|
||||
where
|
||||
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<'a, 'b, E: Ext, S: State> Environment<'a, 'b, E, S> {
|
||||
/// The function id within the `id` passed by a contract.
|
||||
///
|
||||
/// It returns the two least significant bytes of the `id` passed by a contract as the other
|
||||
@@ -326,10 +315,7 @@ impl<'a, 'b, E: Ext, S: PrimOut> Environment<'a, 'b, E, S> {
|
||||
}
|
||||
|
||||
/// Functions to use the input arguments as pointer to a buffer.
|
||||
impl<'a, 'b, E: Ext, S: BufIn> Environment<'a, 'b, E, S>
|
||||
where
|
||||
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<'a, 'b, E: Ext, S: BufIn> Environment<'a, 'b, E, S> {
|
||||
/// Reads `min(max_len, in_len)` from contract memory.
|
||||
///
|
||||
/// This does **not** charge any weight. The caller must make sure that the an
|
||||
@@ -401,10 +387,7 @@ where
|
||||
}
|
||||
|
||||
/// Functions to use the output arguments as pointer to a buffer.
|
||||
impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S>
|
||||
where
|
||||
<E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<'a, 'b, E: Ext, S: BufOut> Environment<'a, 'b, E, S> {
|
||||
/// Write the supplied buffer to contract memory.
|
||||
///
|
||||
/// If the contract supplied buffer is smaller than the passed `buffer` an `Err` is returned.
|
||||
|
||||
@@ -32,7 +32,7 @@ use frame_support::{
|
||||
use frame_system::RawOrigin;
|
||||
use pallet_contracts_primitives::ExecReturnValue;
|
||||
use smallvec::{Array, SmallVec};
|
||||
use sp_core::{crypto::UncheckedFrom, ecdsa::Public as ECDSAPublic};
|
||||
use sp_core::ecdsa::Public as ECDSAPublic;
|
||||
use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
|
||||
use sp_runtime::traits::{Convert, Hash};
|
||||
use sp_std::{marker::PhantomData, mem, prelude::*};
|
||||
@@ -475,6 +475,8 @@ enum FrameArgs<'a, T: Config, E> {
|
||||
executable: E,
|
||||
/// A salt used in the contract address deriviation of the new contract.
|
||||
salt: &'a [u8],
|
||||
/// The input data is used in the contract address deriviation of the new contract.
|
||||
input_data: &'a [u8],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -596,7 +598,6 @@ impl<T: Config> CachedContract<T> {
|
||||
impl<'a, T, E> Stack<'a, T, E>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
E: Executable<T>,
|
||||
{
|
||||
/// Create and run a new call stack by calling into `dest`.
|
||||
@@ -660,6 +661,7 @@ where
|
||||
nonce: <Nonce<T>>::get().wrapping_add(1),
|
||||
executable,
|
||||
salt,
|
||||
input_data: input_data.as_ref(),
|
||||
},
|
||||
origin,
|
||||
gas_meter,
|
||||
@@ -742,9 +744,13 @@ where
|
||||
|
||||
(dest, contract, executable, delegate_caller, ExportedFunction::Call, None)
|
||||
},
|
||||
FrameArgs::Instantiate { sender, nonce, executable, salt } => {
|
||||
let account_id =
|
||||
<Contracts<T>>::contract_address(&sender, executable.code_hash(), salt);
|
||||
FrameArgs::Instantiate { sender, nonce, executable, salt, input_data } => {
|
||||
let account_id = Contracts::<T>::contract_address(
|
||||
&sender,
|
||||
executable.code_hash(),
|
||||
input_data,
|
||||
salt,
|
||||
);
|
||||
let trie_id = Storage::<T>::generate_trie_id(&account_id, nonce);
|
||||
let contract =
|
||||
Storage::<T>::new_contract(&account_id, trie_id, *executable.code_hash())?;
|
||||
@@ -1080,7 +1086,6 @@ where
|
||||
impl<'a, T, E> Ext for Stack<'a, T, E>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
E: Executable<T>,
|
||||
{
|
||||
type T = T;
|
||||
@@ -1167,6 +1172,7 @@ where
|
||||
nonce,
|
||||
executable,
|
||||
salt,
|
||||
input_data: input_data.as_ref(),
|
||||
},
|
||||
value,
|
||||
gas_limit,
|
||||
|
||||
@@ -23,7 +23,6 @@ use frame_support::{
|
||||
weights::Weight,
|
||||
DefaultNoBound,
|
||||
};
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_runtime::traits::Zero;
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
@@ -86,10 +85,7 @@ pub struct GasMeter<T: Config> {
|
||||
tokens: Vec<ErasedToken>,
|
||||
}
|
||||
|
||||
impl<T: Config> GasMeter<T>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<<T as frame_system::Config>::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> GasMeter<T> {
|
||||
pub fn new(gas_limit: Weight) -> Self {
|
||||
GasMeter {
|
||||
gas_limit,
|
||||
|
||||
@@ -105,7 +105,7 @@ use crate::{
|
||||
wasm::{OwnerInfo, PrefabWasmModule, TryInstantiate},
|
||||
weights::WeightInfo,
|
||||
};
|
||||
use codec::{Codec, Encode, HasCompact};
|
||||
use codec::{Codec, Decode, Encode, HasCompact};
|
||||
use frame_support::{
|
||||
dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo},
|
||||
ensure,
|
||||
@@ -123,8 +123,7 @@ use pallet_contracts_primitives::{
|
||||
StorageDeposit,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup};
|
||||
use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup, TrailingZeroInput};
|
||||
use sp_std::{fmt::Debug, marker::PhantomData, prelude::*};
|
||||
|
||||
pub use crate::{
|
||||
@@ -155,7 +154,7 @@ const SENTINEL: u32 = u32::MAX;
|
||||
/// Provides the contract address generation method.
|
||||
///
|
||||
/// See [`DefaultAddressGenerator`] for the default implementation.
|
||||
pub trait AddressGenerator<T: frame_system::Config> {
|
||||
pub trait AddressGenerator<T: Config> {
|
||||
/// Generate the address of a contract based on the given instantiate parameters.
|
||||
///
|
||||
/// # Note for implementors
|
||||
@@ -166,6 +165,7 @@ pub trait AddressGenerator<T: frame_system::Config> {
|
||||
fn generate_address(
|
||||
deploying_address: &T::AccountId,
|
||||
code_hash: &CodeHash<T>,
|
||||
input_data: &[u8],
|
||||
salt: &[u8],
|
||||
) -> T::AccountId;
|
||||
}
|
||||
@@ -176,28 +176,21 @@ pub trait AddressGenerator<T: frame_system::Config> {
|
||||
/// is only dependant on its inputs. It can therefore be used to reliably predict the
|
||||
/// address of a contract. This is akin to the formula of eth's CREATE2 opcode. There
|
||||
/// is no CREATE equivalent because CREATE2 is strictly more powerful.
|
||||
///
|
||||
/// Formula: `hash(deploying_address ++ code_hash ++ salt)`
|
||||
/// Formula:
|
||||
/// `hash("contract_addr_v1" ++ deploying_address ++ code_hash ++ input_data ++ salt)`
|
||||
pub struct DefaultAddressGenerator;
|
||||
|
||||
impl<T> AddressGenerator<T> for DefaultAddressGenerator
|
||||
where
|
||||
T: frame_system::Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> AddressGenerator<T> for DefaultAddressGenerator {
|
||||
fn generate_address(
|
||||
deploying_address: &T::AccountId,
|
||||
code_hash: &CodeHash<T>,
|
||||
input_data: &[u8],
|
||||
salt: &[u8],
|
||||
) -> T::AccountId {
|
||||
let buf: Vec<_> = deploying_address
|
||||
.as_ref()
|
||||
.iter()
|
||||
.chain(code_hash.as_ref())
|
||||
.chain(salt)
|
||||
.cloned()
|
||||
.collect();
|
||||
UncheckedFrom::unchecked_from(T::Hashing::hash(&buf))
|
||||
let entropy = (b"contract_addr_v1", deploying_address, code_hash, input_data, salt)
|
||||
.using_encoded(T::Hashing::hash);
|
||||
Decode::decode(&mut TrailingZeroInput::new(entropy.as_ref()))
|
||||
.expect("infinite length input; no invalid inputs for type; qed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,11 +345,7 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash>,
|
||||
T::AccountId: AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_idle(_block: T::BlockNumber, remaining_weight: Weight) -> Weight {
|
||||
Storage::<T>::process_deletion_queue_batch(remaining_weight)
|
||||
.saturating_add(T::WeightInfo::on_process_deletion_queue_batch())
|
||||
@@ -385,8 +374,6 @@ pub mod pallet {
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash>,
|
||||
T::AccountId: AsRef<[u8]>,
|
||||
<BalanceOf<T> as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode,
|
||||
{
|
||||
/// Deprecated version if [`Self::call`] for use in an in-storage `Call`.
|
||||
@@ -415,7 +402,7 @@ pub mod pallet {
|
||||
/// Deprecated version if [`Self::instantiate_with_code`] for use in an in-storage `Call`.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32)
|
||||
T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32)
|
||||
.saturating_add(<Pallet<T>>::compat_weight(*gas_limit))
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
@@ -445,7 +432,7 @@ pub mod pallet {
|
||||
/// Deprecated version if [`Self::instantiate`] for use in an in-storage `Call`.
|
||||
#[pallet::call_index(2)]
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::instantiate(salt.len() as u32).saturating_add(<Pallet<T>>::compat_weight(*gas_limit))
|
||||
T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(<Pallet<T>>::compat_weight(*gas_limit))
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(note = "1D weight is used in this extrinsic, please migrate to `instantiate`")]
|
||||
@@ -633,7 +620,7 @@ pub mod pallet {
|
||||
/// - The `deploy` function is executed in the context of the newly-created account.
|
||||
#[pallet::call_index(7)]
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32)
|
||||
T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32)
|
||||
.saturating_add(*gas_limit)
|
||||
)]
|
||||
pub fn instantiate_with_code(
|
||||
@@ -647,6 +634,7 @@ pub mod pallet {
|
||||
) -> DispatchResultWithPostInfo {
|
||||
let origin = ensure_signed(origin)?;
|
||||
let code_len = code.len() as u32;
|
||||
let data_len = data.len() as u32;
|
||||
let salt_len = salt.len() as u32;
|
||||
let mut output = Self::internal_instantiate(
|
||||
origin,
|
||||
@@ -665,7 +653,7 @@ pub mod pallet {
|
||||
}
|
||||
output.gas_meter.into_dispatch_result(
|
||||
output.result.map(|(_address, result)| result),
|
||||
T::WeightInfo::instantiate_with_code(code_len, salt_len),
|
||||
T::WeightInfo::instantiate_with_code(code_len, data_len, salt_len),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -676,7 +664,7 @@ pub mod pallet {
|
||||
/// must be supplied.
|
||||
#[pallet::call_index(8)]
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::instantiate(salt.len() as u32).saturating_add(*gas_limit)
|
||||
T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(*gas_limit)
|
||||
)]
|
||||
pub fn instantiate(
|
||||
origin: OriginFor<T>,
|
||||
@@ -688,6 +676,7 @@ pub mod pallet {
|
||||
salt: Vec<u8>,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
let origin = ensure_signed(origin)?;
|
||||
let data_len = data.len() as u32;
|
||||
let salt_len = salt.len() as u32;
|
||||
let mut output = Self::internal_instantiate(
|
||||
origin,
|
||||
@@ -706,7 +695,7 @@ pub mod pallet {
|
||||
}
|
||||
output.gas_meter.into_dispatch_result(
|
||||
output.result.map(|(_address, output)| output),
|
||||
T::WeightInfo::instantiate(salt_len),
|
||||
T::WeightInfo::instantiate(data_len, salt_len),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -943,10 +932,7 @@ struct InternalOutput<T: Config, O> {
|
||||
result: Result<O, ExecError>,
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Perform a call to a specified contract.
|
||||
///
|
||||
/// This function is similar to [`Self::call`], but doesn't perform any address lookups
|
||||
@@ -1081,9 +1067,10 @@ where
|
||||
pub fn contract_address(
|
||||
deploying_address: &T::AccountId,
|
||||
code_hash: &CodeHash<T>,
|
||||
input_data: &[u8],
|
||||
salt: &[u8],
|
||||
) -> T::AccountId {
|
||||
T::AddressGenerator::generate_address(deploying_address, code_hash, salt)
|
||||
T::AddressGenerator::generate_address(deploying_address, code_hash, input_data, salt)
|
||||
}
|
||||
|
||||
/// Returns the code hash of the contract specified by `account` ID.
|
||||
|
||||
@@ -397,6 +397,9 @@ pub struct HostFnWeights<T: Config> {
|
||||
/// Weight surcharge that is claimed if `seal_instantiate` does a balance transfer.
|
||||
pub instantiate_transfer_surcharge: u64,
|
||||
|
||||
/// Weight per input byte supplied to `seal_instantiate`.
|
||||
pub instantiate_per_input_byte: u64,
|
||||
|
||||
/// Weight per salt byte supplied to `seal_instantiate`.
|
||||
pub instantiate_per_salt_byte: u64,
|
||||
|
||||
@@ -658,12 +661,20 @@ impl<T: Config> Default for HostFnWeights<T> {
|
||||
call_per_cloned_byte: cost_batched_args!(seal_call_per_transfer_clone_kb, 0, 1),
|
||||
instantiate: cost_batched!(seal_instantiate),
|
||||
instantiate_transfer_surcharge: cost_byte_batched_args!(
|
||||
seal_instantiate_per_transfer_salt_kb,
|
||||
seal_instantiate_per_transfer_input_salt_kb,
|
||||
1,
|
||||
0,
|
||||
0
|
||||
),
|
||||
instantiate_per_input_byte: cost_byte_batched_args!(
|
||||
seal_instantiate_per_transfer_input_salt_kb,
|
||||
0,
|
||||
1,
|
||||
0
|
||||
),
|
||||
instantiate_per_salt_byte: cost_byte_batched_args!(
|
||||
seal_instantiate_per_transfer_salt_kb,
|
||||
seal_instantiate_per_transfer_input_salt_kb,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
),
|
||||
|
||||
@@ -31,7 +31,6 @@ use frame_support::{
|
||||
weights::Weight,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_io::KillStorageResult;
|
||||
use sp_runtime::{
|
||||
traits::{Hash, Saturating, Zero},
|
||||
@@ -135,11 +134,7 @@ impl WriteOutcome {
|
||||
|
||||
pub struct Storage<T>(PhantomData<T>);
|
||||
|
||||
impl<T> Storage<T>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> Storage<T> {
|
||||
/// Reads a storage kv pair of a contract.
|
||||
///
|
||||
/// The read is performed from the `trie_id` only. The `address` is not necessary. If the
|
||||
@@ -317,11 +312,10 @@ where
|
||||
Weight::from_ref_time(ref_time_weight)
|
||||
}
|
||||
|
||||
/// Generates a unique trie id by returning `hash(account_id ++ nonce)`.
|
||||
/// Generates a unique trie id by returning `hash(account_id ++ nonce)`.
|
||||
pub fn generate_trie_id(account_id: &AccountIdOf<T>, nonce: u64) -> TrieId {
|
||||
let buf: Vec<_> = account_id.as_ref().iter().chain(&nonce.to_le_bytes()).cloned().collect();
|
||||
T::Hashing::hash(&buf)
|
||||
.as_ref()
|
||||
let buf = (account_id, nonce).using_encoded(T::Hashing::hash);
|
||||
buf.as_ref()
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.expect("Runtime uses a reasonable hash size. Hence sizeof(T::Hash) <= 128; qed")
|
||||
|
||||
@@ -29,7 +29,6 @@ use frame_support::{
|
||||
DefaultNoBound, RuntimeDebugNoBound,
|
||||
};
|
||||
use pallet_contracts_primitives::StorageDeposit as Deposit;
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_runtime::{
|
||||
traits::{Saturating, Zero},
|
||||
FixedPointNumber, FixedU128,
|
||||
@@ -255,7 +254,6 @@ impl<T: Config> Default for Contribution<T> {
|
||||
impl<T, E, S> RawMeter<T, E, S>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
E: Ext<T>,
|
||||
S: State,
|
||||
{
|
||||
@@ -325,7 +323,6 @@ where
|
||||
impl<T, E> RawMeter<T, E, Root>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
E: Ext<T>,
|
||||
{
|
||||
/// Create new storage meter for the specified `origin` and `limit`.
|
||||
@@ -361,7 +358,6 @@ where
|
||||
impl<T, E> RawMeter<T, E, Nested>
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
E: Ext<T>,
|
||||
{
|
||||
/// Try to charge the `diff` from the meter. Fails if this would exceed the original limit.
|
||||
@@ -441,11 +437,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Ext<T> for ReservingExt
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> Ext<T> for ReservingExt {
|
||||
fn check_limit(
|
||||
origin: &T::AccountId,
|
||||
limit: Option<BalanceOf<T>>,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,6 @@ use frame_support::{
|
||||
traits::{Get, ReservableCurrency},
|
||||
WeakBoundedVec,
|
||||
};
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_runtime::traits::BadOrigin;
|
||||
use sp_std::vec;
|
||||
|
||||
@@ -49,10 +48,7 @@ use sp_std::vec;
|
||||
///
|
||||
/// Increments the refcount of the in-storage `prefab_module` if it already exists in storage
|
||||
/// under the specified `code_hash`.
|
||||
pub fn store<T: Config>(mut module: PrefabWasmModule<T>, instantiated: bool) -> DispatchResult
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
pub fn store<T: Config>(mut module: PrefabWasmModule<T>, instantiated: bool) -> DispatchResult {
|
||||
let code_hash = sp_std::mem::take(&mut module.code_hash);
|
||||
<CodeStorage<T>>::mutate(&code_hash, |existing| match existing {
|
||||
Some(existing) => {
|
||||
@@ -135,10 +131,7 @@ pub fn increment_refcount<T: Config>(code_hash: CodeHash<T>) -> Result<(), Dispa
|
||||
}
|
||||
|
||||
/// Try to remove code together with all associated information.
|
||||
pub fn try_remove<T: Config>(origin: &T::AccountId, code_hash: CodeHash<T>) -> DispatchResult
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
pub fn try_remove<T: Config>(origin: &T::AccountId, code_hash: CodeHash<T>) -> DispatchResult {
|
||||
<OwnerInfoOf<T>>::try_mutate_exists(&code_hash, |existing| {
|
||||
if let Some(owner_info) = existing {
|
||||
ensure!(owner_info.refcount == 0, <Error<T>>::CodeInUse);
|
||||
@@ -164,10 +157,7 @@ pub fn load<T: Config>(
|
||||
code_hash: CodeHash<T>,
|
||||
schedule: &Schedule<T>,
|
||||
gas_meter: &mut GasMeter<T>,
|
||||
) -> Result<PrefabWasmModule<T>, DispatchError>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
) -> Result<PrefabWasmModule<T>, DispatchError> {
|
||||
let max_code_len = T::MaxCodeLen::get();
|
||||
let charged = gas_meter.charge(CodeToken::Load(max_code_len))?;
|
||||
|
||||
@@ -192,10 +182,7 @@ where
|
||||
pub fn reinstrument<T: Config>(
|
||||
prefab_module: &mut PrefabWasmModule<T>,
|
||||
schedule: &Schedule<T>,
|
||||
) -> Result<u32, DispatchError>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
) -> Result<u32, DispatchError> {
|
||||
let original_code =
|
||||
<PristineCode<T>>::get(&prefab_module.code_hash).ok_or(Error::<T>::CodeNotFound)?;
|
||||
let original_code_len = original_code.len();
|
||||
|
||||
@@ -36,7 +36,7 @@ use crate::{
|
||||
};
|
||||
use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use frame_support::dispatch::{DispatchError, DispatchResult};
|
||||
use sp_core::{crypto::UncheckedFrom, Get};
|
||||
use sp_core::Get;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::prelude::*;
|
||||
#[cfg(test)]
|
||||
@@ -140,10 +140,7 @@ impl ExportedFunction {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> PrefabWasmModule<T>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> PrefabWasmModule<T> {
|
||||
/// Create the module by checking and instrumenting `original_code`.
|
||||
///
|
||||
/// This does **not** store the module. For this one need to either call [`Self::store`]
|
||||
@@ -263,10 +260,7 @@ impl<T: Config> OwnerInfo<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Executable<T> for PrefabWasmModule<T>
|
||||
where
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> Executable<T> for PrefabWasmModule<T> {
|
||||
fn from_storage(
|
||||
code_hash: CodeHash<T>,
|
||||
schedule: &Schedule<T>,
|
||||
@@ -476,7 +470,7 @@ mod tests {
|
||||
salt: salt.to_vec(),
|
||||
});
|
||||
Ok((
|
||||
Contracts::<Test>::contract_address(&ALICE, &code_hash, salt),
|
||||
Contracts::<Test>::contract_address(&ALICE, &code_hash, &data, salt),
|
||||
ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() },
|
||||
))
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ use crate::{
|
||||
AccountIdOf, CodeVec, Config, Error, Schedule,
|
||||
};
|
||||
use codec::{Encode, MaxEncodedLen};
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_runtime::{traits::Hash, DispatchError};
|
||||
use sp_std::prelude::*;
|
||||
use wasm_instrument::{
|
||||
@@ -396,7 +395,6 @@ fn instrument<E, T>(
|
||||
where
|
||||
E: Environment<()>,
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
// Do not enable any features here. Any additional feature needs to be carefully
|
||||
// checked for potential security issues. For example, enabling multi value could lead
|
||||
@@ -500,7 +498,6 @@ pub fn prepare<E, T>(
|
||||
where
|
||||
E: Environment<()>,
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
let (code, (initial, maximum)) =
|
||||
instrument::<E, T>(original_code.as_ref(), schedule, determinism, try_instantiate)?;
|
||||
@@ -547,7 +544,6 @@ pub fn reinstrument<E, T>(
|
||||
where
|
||||
E: Environment<()>,
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
instrument::<E, T>(original_code, schedule, determinism, TryInstantiate::Skip)
|
||||
.map_err(|(err, msg)| {
|
||||
|
||||
@@ -29,7 +29,6 @@ use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
|
||||
use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight, RuntimeDebug};
|
||||
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags};
|
||||
use pallet_contracts_proc_macro::define_env;
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256};
|
||||
use sp_runtime::traits::{Bounded, Zero};
|
||||
use sp_std::{fmt, prelude::*};
|
||||
@@ -270,11 +269,7 @@ pub enum RuntimeCosts {
|
||||
}
|
||||
|
||||
impl RuntimeCosts {
|
||||
fn token<T>(&self, s: &HostFnWeights<T>) -> RuntimeToken
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
fn token<T: Config>(&self, s: &HostFnWeights<T>) -> RuntimeToken {
|
||||
use self::RuntimeCosts::*;
|
||||
let weight = match *self {
|
||||
MeteringBlock(amount) => s.gas.saturating_add(amount),
|
||||
@@ -324,7 +319,7 @@ impl RuntimeCosts {
|
||||
CallInputCloned(len) => s.call_per_cloned_byte.saturating_mul(len.into()),
|
||||
InstantiateBase { input_data_len, salt_len } => s
|
||||
.instantiate
|
||||
.saturating_add(s.return_per_byte.saturating_mul(input_data_len.into()))
|
||||
.saturating_add(s.instantiate_per_input_byte.saturating_mul(input_data_len.into()))
|
||||
.saturating_add(s.instantiate_per_salt_byte.saturating_mul(salt_len.into())),
|
||||
InstantiateSurchargeTransfer => s.instantiate_transfer_surcharge,
|
||||
HashSha256(len) => s
|
||||
@@ -375,11 +370,7 @@ struct RuntimeToken {
|
||||
weight: Weight,
|
||||
}
|
||||
|
||||
impl<T> Token<T> for RuntimeToken
|
||||
where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<T: Config> Token<T> for RuntimeToken {
|
||||
fn weight(&self) -> Weight {
|
||||
self.weight
|
||||
}
|
||||
@@ -463,12 +454,7 @@ pub struct Runtime<'a, E: Ext + 'a> {
|
||||
chain_extension: Option<Box<<E::T as Config>::ChainExtension>>,
|
||||
}
|
||||
|
||||
impl<'a, E> Runtime<'a, E>
|
||||
where
|
||||
E: Ext + 'a,
|
||||
<E::T as frame_system::Config>::AccountId:
|
||||
UncheckedFrom<<E::T as frame_system::Config>::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
impl<'a, E: Ext + 'a> Runtime<'a, E> {
|
||||
pub fn new(ext: &'a mut E, input_data: Vec<u8>) -> Self {
|
||||
Runtime {
|
||||
ext,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user