mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 07:01:05 +00:00
contracts: Move Schedule from Storage to Config (#8773)
* Move `Schedule` from Storage to Config * Updated CHANGELOG * Fix nits from review * Fix migration * Print the debug buffer as tracing message * Use `debug` instead of `trace` and update README * Add additional assert to test * Rename `schedule_version` to `instruction_weights_version` * Fixed typo * Added more comments to wat fixtures * Add clarification for the `debug_message` field
This commit is contained in:
committed by
GitHub
parent
3c0270fe57
commit
1ac95b6ba6
@@ -59,9 +59,6 @@
|
||||
//!
|
||||
//! ### Dispatchable functions
|
||||
//!
|
||||
//! * [`Pallet::update_schedule`] -
|
||||
//! ([Root Origin](https://substrate.dev/docs/en/knowledgebase/runtime/origin) Only) -
|
||||
//! Set a new [`Schedule`].
|
||||
//! * [`Pallet::instantiate_with_code`] - Deploys a new contract from the supplied wasm binary,
|
||||
//! optionally transferring
|
||||
//! some balance. This instantiates a new smart contract account with the supplied code and
|
||||
@@ -160,6 +157,21 @@ pub mod pallet {
|
||||
/// Handler for rent payments.
|
||||
type RentPayment: OnUnbalanced<NegativeImbalanceOf<Self>>;
|
||||
|
||||
/// Used to answer contracts' queries regarding the current weight price. This is **not**
|
||||
/// used to calculate the actual fee and is only for informational purposes.
|
||||
type WeightPrice: Convert<Weight, BalanceOf<Self>>;
|
||||
|
||||
/// Describes the weights of the dispatchables of this module and is also used to
|
||||
/// construct a default cost schedule.
|
||||
type WeightInfo: WeightInfo;
|
||||
|
||||
/// Type that allows the runtime authors to add new host functions for a contract to call.
|
||||
type ChainExtension: chain_extension::ChainExtension<Self>;
|
||||
|
||||
/// Cost schedule and limits.
|
||||
#[pallet::constant]
|
||||
type Schedule: Get<Schedule<Self>>;
|
||||
|
||||
/// Number of block delay an extrinsic claim surcharge has.
|
||||
///
|
||||
/// When claim surcharge is called by an extrinsic the rent is checked
|
||||
@@ -217,21 +229,6 @@ pub mod pallet {
|
||||
/// In other words only the origin called "root contract" is allowed to execute then.
|
||||
type CallStack: smallvec::Array<Item=Frame<Self>>;
|
||||
|
||||
/// The maximum size of a storage value and event payload in bytes.
|
||||
#[pallet::constant]
|
||||
type MaxValueSize: Get<u32>;
|
||||
|
||||
/// Used to answer contracts' queries regarding the current weight price. This is **not**
|
||||
/// used to calculate the actual fee and is only for informational purposes.
|
||||
type WeightPrice: Convert<Weight, BalanceOf<Self>>;
|
||||
|
||||
/// Describes the weights of the dispatchables of this module and is also used to
|
||||
/// construct a default cost schedule.
|
||||
type WeightInfo: WeightInfo;
|
||||
|
||||
/// Type that allows the runtime authors to add new host functions for a contract to call.
|
||||
type ChainExtension: chain_extension::ChainExtension<Self>;
|
||||
|
||||
/// The maximum number of tries that can be queued for deletion.
|
||||
#[pallet::constant]
|
||||
type DeletionQueueDepth: Get<u32>;
|
||||
@@ -239,12 +236,6 @@ pub mod pallet {
|
||||
/// The maximum amount of weight that can be consumed per block for lazy trie removal.
|
||||
#[pallet::constant]
|
||||
type DeletionWeightLimit: Get<Weight>;
|
||||
|
||||
/// The maximum length of a contract code in bytes. This limit applies to the instrumented
|
||||
/// version of the code. Therefore `instantiate_with_code` can fail even when supplying
|
||||
/// a wasm binary below this maximum size.
|
||||
#[pallet::constant]
|
||||
type MaxCodeSize: Get<u32>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
@@ -277,26 +268,6 @@ pub mod pallet {
|
||||
T::AccountId: UncheckedFrom<T::Hash>,
|
||||
T::AccountId: AsRef<[u8]>,
|
||||
{
|
||||
/// Updates the schedule for metering contracts.
|
||||
///
|
||||
/// The schedule's version cannot be less than the version of the stored schedule.
|
||||
/// If a schedule does not change the instruction weights the version does not
|
||||
/// need to be increased. Therefore we allow storing a schedule that has the same
|
||||
/// version as the stored one.
|
||||
#[pallet::weight(T::WeightInfo::update_schedule())]
|
||||
pub fn update_schedule(
|
||||
origin: OriginFor<T>,
|
||||
schedule: Schedule<T>
|
||||
) -> DispatchResultWithPostInfo {
|
||||
ensure_root(origin)?;
|
||||
if <CurrentSchedule<T>>::get().version > schedule.version {
|
||||
Err(Error::<T>::InvalidScheduleVersion)?
|
||||
}
|
||||
Self::deposit_event(Event::ScheduleUpdated(schedule.version));
|
||||
CurrentSchedule::put(schedule);
|
||||
Ok(().into())
|
||||
}
|
||||
|
||||
/// Makes a call to an account, optionally transferring some balance.
|
||||
///
|
||||
/// * If the account is a smart-contract account, the associated code will be
|
||||
@@ -304,7 +275,9 @@ pub mod pallet {
|
||||
/// * If the account is a regular account, any value will be transferred.
|
||||
/// * If no account exists and the call value is not less than `existential_deposit`,
|
||||
/// a regular account will be created and any value will be transferred.
|
||||
#[pallet::weight(T::WeightInfo::call(T::MaxCodeSize::get() / 1024).saturating_add(*gas_limit))]
|
||||
#[pallet::weight(T::WeightInfo::call(T::Schedule::get().limits.code_len / 1024)
|
||||
.saturating_add(*gas_limit)
|
||||
)]
|
||||
pub fn call(
|
||||
origin: OriginFor<T>,
|
||||
dest: <T::Lookup as StaticLookup>::Source,
|
||||
@@ -315,9 +288,9 @@ pub mod pallet {
|
||||
let origin = ensure_signed(origin)?;
|
||||
let dest = T::Lookup::lookup(dest)?;
|
||||
let mut gas_meter = GasMeter::new(gas_limit);
|
||||
let schedule = <CurrentSchedule<T>>::get();
|
||||
let schedule = T::Schedule::get();
|
||||
let (result, code_len) = match ExecStack::<T, PrefabWasmModule<T>>::run_call(
|
||||
origin, dest, &mut gas_meter, &schedule, value, data
|
||||
origin, dest, &mut gas_meter, &schedule, value, data, None,
|
||||
) {
|
||||
Ok((output, len)) => (Ok(output), len),
|
||||
Err((err, len)) => (Err(err), len),
|
||||
@@ -363,14 +336,14 @@ pub mod pallet {
|
||||
) -> DispatchResultWithPostInfo {
|
||||
let origin = ensure_signed(origin)?;
|
||||
let code_len = code.len() as u32;
|
||||
ensure!(code_len <= T::MaxCodeSize::get(), Error::<T>::CodeTooLarge);
|
||||
ensure!(code_len <= T::Schedule::get().limits.code_len, Error::<T>::CodeTooLarge);
|
||||
let mut gas_meter = GasMeter::new(gas_limit);
|
||||
let schedule = <CurrentSchedule<T>>::get();
|
||||
let schedule = T::Schedule::get();
|
||||
let executable = PrefabWasmModule::from_code(code, &schedule)?;
|
||||
let code_len = executable.code_len();
|
||||
ensure!(code_len <= T::MaxCodeSize::get(), Error::<T>::CodeTooLarge);
|
||||
ensure!(code_len <= T::Schedule::get().limits.code_len, Error::<T>::CodeTooLarge);
|
||||
let result = ExecStack::<T, PrefabWasmModule<T>>::run_instantiate(
|
||||
origin, executable, &mut gas_meter, &schedule, endowment, data, &salt,
|
||||
origin, executable, &mut gas_meter, &schedule, endowment, data, &salt, None,
|
||||
).map(|(_address, output)| output);
|
||||
gas_meter.into_dispatch_result(
|
||||
result,
|
||||
@@ -384,8 +357,10 @@ pub mod pallet {
|
||||
/// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary
|
||||
/// must be supplied.
|
||||
#[pallet::weight(
|
||||
T::WeightInfo::instantiate(T::MaxCodeSize::get() / 1024, salt.len() as u32 / 1024)
|
||||
.saturating_add(*gas_limit)
|
||||
T::WeightInfo::instantiate(
|
||||
T::Schedule::get().limits.code_len / 1024, salt.len() as u32 / 1024
|
||||
)
|
||||
.saturating_add(*gas_limit)
|
||||
)]
|
||||
pub fn instantiate(
|
||||
origin: OriginFor<T>,
|
||||
@@ -397,11 +372,11 @@ pub mod pallet {
|
||||
) -> DispatchResultWithPostInfo {
|
||||
let origin = ensure_signed(origin)?;
|
||||
let mut gas_meter = GasMeter::new(gas_limit);
|
||||
let schedule = <CurrentSchedule<T>>::get();
|
||||
let schedule = T::Schedule::get();
|
||||
let executable = PrefabWasmModule::from_storage(code_hash, &schedule, &mut gas_meter)?;
|
||||
let code_len = executable.code_len();
|
||||
let result = ExecStack::<T, PrefabWasmModule<T>>::run_instantiate(
|
||||
origin, executable, &mut gas_meter, &schedule, endowment, data, &salt,
|
||||
origin, executable, &mut gas_meter, &schedule, endowment, data, &salt, None,
|
||||
).map(|(_address, output)| output);
|
||||
gas_meter.into_dispatch_result(
|
||||
result,
|
||||
@@ -418,7 +393,7 @@ pub mod pallet {
|
||||
///
|
||||
/// If contract is not evicted as a result of this call, [`Error::ContractNotEvictable`]
|
||||
/// is returned and the sender is not eligible for the reward.
|
||||
#[pallet::weight(T::WeightInfo::claim_surcharge(T::MaxCodeSize::get() / 1024))]
|
||||
#[pallet::weight(T::WeightInfo::claim_surcharge(T::Schedule::get().limits.code_len / 1024))]
|
||||
pub fn claim_surcharge(
|
||||
origin: OriginFor<T>,
|
||||
dest: T::AccountId,
|
||||
@@ -614,12 +589,10 @@ pub mod pallet {
|
||||
///
|
||||
/// This can be triggered by a call to `seal_terminate` or `seal_restore_to`.
|
||||
TerminatedInConstructor,
|
||||
/// The debug message specified to `seal_debug_message` does contain invalid UTF-8.
|
||||
DebugMessageInvalidUTF8,
|
||||
}
|
||||
|
||||
/// Current cost schedule for contracts.
|
||||
#[pallet::storage]
|
||||
pub(crate) type CurrentSchedule<T: Config> = StorageValue<_, Schedule<T>, ValueQuery>;
|
||||
|
||||
/// A mapping from an original code hash to the original code, untouched by instrumentation.
|
||||
#[pallet::storage]
|
||||
pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, CodeHash<T>, Vec<u8>>;
|
||||
@@ -644,29 +617,6 @@ pub mod pallet {
|
||||
/// stored in said trie. Therefore this operation is performed lazily in `on_initialize`.
|
||||
#[pallet::storage]
|
||||
pub(crate) type DeletionQueue<T: Config> = StorageValue<_, Vec<DeletedContract>, ValueQuery>;
|
||||
|
||||
|
||||
#[pallet::genesis_config]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
#[doc = "Current cost schedule for contracts."]
|
||||
pub current_schedule: Schedule<T>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Config> Default for GenesisConfig<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current_schedule: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
|
||||
fn build(&self) {
|
||||
<CurrentSchedule<T>>::put(&self.current_schedule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T>
|
||||
@@ -678,6 +628,12 @@ where
|
||||
/// This function is similar to [`Self::call`], but doesn't perform any address lookups
|
||||
/// and better suitable for calling directly from Rust.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// `debug` should only ever be set to `true` when executing as an RPC because
|
||||
/// it adds allocations and could be abused to drive the runtime into an OOM panic.
|
||||
/// If set to `true` it returns additional human readable debugging information.
|
||||
///
|
||||
/// It returns the execution result and the amount of used weight.
|
||||
pub fn bare_call(
|
||||
origin: T::AccountId,
|
||||
@@ -685,17 +641,22 @@ where
|
||||
value: BalanceOf<T>,
|
||||
gas_limit: Weight,
|
||||
input_data: Vec<u8>,
|
||||
debug: bool,
|
||||
) -> ContractExecResult {
|
||||
let mut gas_meter = GasMeter::new(gas_limit);
|
||||
let schedule = <CurrentSchedule<T>>::get();
|
||||
let schedule = T::Schedule::get();
|
||||
let mut debug_message = if debug {
|
||||
Some(Vec::new())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let result = ExecStack::<T, PrefabWasmModule<T>>::run_call(
|
||||
origin, dest, &mut gas_meter, &schedule, value, input_data,
|
||||
origin, dest, &mut gas_meter, &schedule, value, input_data, debug_message.as_mut(),
|
||||
);
|
||||
let gas_consumed = gas_meter.gas_spent();
|
||||
ContractExecResult {
|
||||
result: result.map(|r| r.0).map_err(|r| r.0.error),
|
||||
gas_consumed,
|
||||
debug_message: Bytes(Vec::new()),
|
||||
gas_consumed: gas_meter.gas_spent(),
|
||||
debug_message: debug_message.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,6 +670,12 @@ where
|
||||
/// If `compute_projection` is set to `true` the result also contains the rent projection.
|
||||
/// This is optional because some non trivial and stateful work is performed to compute
|
||||
/// the projection. See [`Self::rent_projection`].
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// `debug` should only ever be set to `true` when executing as an RPC because
|
||||
/// it adds allocations and could be abused to drive the runtime into an OOM panic.
|
||||
/// If set to `true` it returns additional human readable debugging information.
|
||||
pub fn bare_instantiate(
|
||||
origin: T::AccountId,
|
||||
endowment: BalanceOf<T>,
|
||||
@@ -717,9 +684,10 @@ where
|
||||
data: Vec<u8>,
|
||||
salt: Vec<u8>,
|
||||
compute_projection: bool,
|
||||
debug: bool,
|
||||
) -> ContractInstantiateResult<T::AccountId, T::BlockNumber> {
|
||||
let mut gas_meter = GasMeter::new(gas_limit);
|
||||
let schedule = <CurrentSchedule<T>>::get();
|
||||
let schedule = T::Schedule::get();
|
||||
let executable = match code {
|
||||
Code::Upload(Bytes(binary)) => PrefabWasmModule::from_code(binary, &schedule),
|
||||
Code::Existing(hash) => PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter),
|
||||
@@ -729,11 +697,17 @@ where
|
||||
Err(error) => return ContractInstantiateResult {
|
||||
result: Err(error.into()),
|
||||
gas_consumed: gas_meter.gas_spent(),
|
||||
debug_message: Bytes(Vec::new()),
|
||||
debug_message: Vec::new(),
|
||||
}
|
||||
};
|
||||
let mut debug_message = if debug {
|
||||
Some(Vec::new())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let result = ExecStack::<T, PrefabWasmModule<T>>::run_instantiate(
|
||||
origin, executable, &mut gas_meter, &schedule, endowment, data, &salt,
|
||||
origin, executable, &mut gas_meter, &schedule,
|
||||
endowment, data, &salt, debug_message.as_mut(),
|
||||
).and_then(|(account_id, result)| {
|
||||
let rent_projection = if compute_projection {
|
||||
Some(Rent::<T, PrefabWasmModule<T>>::compute_projection(&account_id)
|
||||
@@ -751,7 +725,7 @@ where
|
||||
ContractInstantiateResult {
|
||||
result: result.map_err(|e| e.error),
|
||||
gas_consumed: gas_meter.gas_spent(),
|
||||
debug_message: Bytes(Vec::new()),
|
||||
debug_message: debug_message.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,7 +796,7 @@ where
|
||||
/// Store code for benchmarks which does not check nor instrument the code.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn store_code_raw(code: Vec<u8>) -> frame_support::dispatch::DispatchResult {
|
||||
let schedule = <CurrentSchedule<T>>::get();
|
||||
let schedule = T::Schedule::get();
|
||||
PrefabWasmModule::store_code_unchecked(code, &schedule)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user