contracts: Expose rent parameter to contracts (#8231)

* contracts: Expose rent parameter to contracts

* cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs

* Fix typos

* Improve comments

* Add rent parameter weights

* Allow deploying a new schedule with the same version

* Add storage migration for new schedule

* Only decode the schedule version in storage migration

* Remove confusing docs

* Replace original_code_len() by aggregate_code_len()

Co-authored-by: Parity Benchmarking Bot <admin@parity.io>
This commit is contained in:
Alexander Theißen
2021-03-12 12:21:08 +01:00
committed by GitHub
parent 3743cec9bd
commit a4e8875897
11 changed files with 1129 additions and 698 deletions
+59 -13
View File
@@ -224,13 +224,21 @@ where
fn occupied_storage(&self) -> u32 {
// We disregard the size of the struct itself as the size is completely
// dominated by the code size.
let len = self.original_code_len.saturating_add(self.code.len() as u32);
let len = self.aggregate_code_len();
len.checked_div(self.refcount as u32).unwrap_or(len)
}
fn code_len(&self) -> u32 {
self.code.len() as u32
}
fn aggregate_code_len(&self) -> u32 {
self.original_code_len.saturating_add(self.code_len())
}
fn refcount(&self) -> u32 {
self.refcount as u32
}
}
#[cfg(test)]
@@ -238,7 +246,7 @@ mod tests {
use super::*;
use crate::{
CodeHash, BalanceOf, Error, Module as Contracts,
exec::{Ext, StorageKey, AccountIdOf, Executable},
exec::{Ext, StorageKey, AccountIdOf, Executable, RentParams},
gas::GasMeter,
tests::{Test, Call, ALICE, BOB},
};
@@ -249,6 +257,7 @@ mod tests {
use frame_support::{dispatch::DispatchResult, weights::Weight};
use assert_matches::assert_matches;
use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags, ExecError, ErrorOrigin};
use pretty_assertions::assert_eq;
const GAS_LIMIT: Weight = 10_000_000_000;
@@ -295,6 +304,7 @@ mod tests {
// (topics, data)
events: Vec<(Vec<H256>, Vec<u8>)>,
schedule: Schedule<Test>,
rent_params: RentParams<Test>,
}
impl Ext for MockExt {
@@ -395,46 +405,38 @@ mod tests {
fn value_transferred(&self) -> u64 {
1337
}
fn now(&self) -> &u64 {
&1111
}
fn minimum_balance(&self) -> u64 {
666
}
fn tombstone_deposit(&self) -> u64 {
16
}
fn random(&self, subject: &[u8]) -> H256 {
H256::from_slice(subject)
}
fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
self.events.push((topics, data))
}
fn set_rent_allowance(&mut self, rent_allowance: u64) {
self.rent_allowance = rent_allowance;
}
fn rent_allowance(&self) -> u64 {
self.rent_allowance
}
fn block_number(&self) -> u64 { 121 }
fn max_value_size(&self) -> u32 { 16_384 }
fn get_weight_price(&self, weight: Weight) -> BalanceOf<Self::T> {
BalanceOf::<Self::T>::from(1312_u32).saturating_mul(weight.into())
}
fn schedule(&self) -> &Schedule<Self::T> {
&self.schedule
}
fn rent_params(&self) -> &RentParams<Self::T> {
&self.rent_params
}
}
impl Ext for &mut MockExt {
@@ -537,6 +539,9 @@ mod tests {
fn schedule(&self) -> &Schedule<Self::T> {
(**self).schedule()
}
fn rent_params(&self) -> &RentParams<Self::T> {
(**self).rent_params()
}
}
fn execute<E: Ext>(
@@ -1840,4 +1845,45 @@ mod tests {
);
}
const CODE_RENT_PARAMS: &str = r#"
(module
(import "seal0" "seal_rent_params" (func $seal_rent_params (param i32 i32)))
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
;; [0, 4) buffer size = 128 bytes
(data (i32.const 0) "\80")
;; [4; inf) buffer where the result is copied
(func (export "call")
;; Load the rent params into memory
(call $seal_rent_params
(i32.const 4) ;; Pointer to the output buffer
(i32.const 0) ;; Pointer to the size of the buffer
)
;; Return the contents of the buffer
(call $seal_return
(i32.const 0) ;; return flags
(i32.const 4) ;; buffer pointer
(i32.load (i32.const 0)) ;; buffer size
)
)
(func (export "deploy"))
)
"#;
#[test]
fn rent_params_work() {
let output = execute(
CODE_RENT_PARAMS,
vec![],
MockExt::default(),
&mut GasMeter::new(GAS_LIMIT),
).unwrap();
let rent_params = <RentParams<Test>>::default().encode();
assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: rent_params });
}
}
@@ -215,6 +215,8 @@ pub enum RuntimeToken {
ChainExtension(u64),
/// Weight charged for copying data from the sandbox.
CopyIn(u32),
/// Weight of calling `seal_rent_params`.
RentParams,
}
impl<T: Config> Token<T> for RuntimeToken
@@ -283,6 +285,7 @@ where
.saturating_add(s.hash_blake2_128_per_byte.saturating_mul(len.into())),
ChainExtension(amount) => amount,
CopyIn(len) => s.return_per_byte.saturating_mul(len.into()),
RentParams => s.rent_params,
}
}
}
@@ -1513,4 +1516,25 @@ define_env!(Env, <E: Ext>,
})),
}
},
// Stores the rent params into the supplied buffer.
//
// The value is stored to linear memory at the address pointed to by `out_ptr`.
// `out_len_ptr` must point to a u32 value that describes the available space at
// `out_ptr`. This call overwrites it with the size of the value. If the available
// space at `out_ptr` is less than the size of the value a trap is triggered.
//
// The data is encoded as [`crate::exec::RentParams`].
//
// # Note
//
// The returned information was collected and cached when the current contract call
// started execution. Any change to those values that happens due to actions of the
// current call or contracts that are called by this contract are not considered.
seal_rent_params(ctx, out_ptr: u32, out_len_ptr: u32) => {
ctx.charge_gas(RuntimeToken::RentParams)?;
Ok(ctx.write_sandbox_output(
out_ptr, out_len_ptr, &ctx.ext.rent_params().encode(), false, already_charged
)?)
},
);