contracts: Add seal_rent_status (#8780)

* Move public functions up in rent.rs

* Added RentStatus

* Fix test name for consistency

Co-authored-by: Michael Müller <michi@parity.io>

* Mark rent functions as unstable

* Add unstable interfaces to README

* Fix doc typos

Co-authored-by: Andrew Jones <ascjones@gmail.com>

* Use DefaultNoBound

* Simplify calc_share(1)

* Don't output empty debug messages

* Make `seal_debug_message` unstable

Co-authored-by: Michael Müller <michi@parity.io>
Co-authored-by: Andrew Jones <ascjones@gmail.com>
This commit is contained in:
Alexander Theißen
2021-05-20 14:01:43 +02:00
committed by GitHub
parent f29a6fdad3
commit 0057c0b53f
17 changed files with 1380 additions and 1109 deletions
+65 -27
View File
@@ -17,7 +17,7 @@
use crate::{
CodeHash, Event, Config, Pallet as Contracts,
BalanceOf, ContractInfo, gas::GasMeter, rent::Rent, storage::Storage,
BalanceOf, ContractInfo, gas::GasMeter, rent::{Rent, RentStatus}, storage::Storage,
Error, ContractInfoOf, Schedule, AliveContractInfo, AccountCounter,
};
use sp_core::crypto::UncheckedFrom;
@@ -32,7 +32,7 @@ use frame_support::{
storage::{with_transaction, TransactionOutcome},
traits::{ExistenceRequirement, Currency, Time, Randomness, Get},
weights::Weight,
ensure,
ensure, DefaultNoBound,
};
use pallet_contracts_primitives::{ExecReturnValue};
use smallvec::{SmallVec, Array};
@@ -82,7 +82,7 @@ impl<T: Into<DispatchError>> From<T> for ExecError {
}
/// Information needed for rent calculations that can be requested by a contract.
#[derive(codec::Encode)]
#[derive(codec::Encode, DefaultNoBound)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct RentParams<T: Config> {
/// The total balance of the contract. Includes the balance transferred from the caller.
@@ -142,27 +142,6 @@ where
}
}
/// We cannot derive `Default` because `T` does not necessarily implement `Default`.
#[cfg(test)]
impl<T: Config> Default for RentParams<T> {
fn default() -> Self {
Self {
total_balance: Default::default(),
free_balance: Default::default(),
subsistence_threshold: Default::default(),
deposit_per_contract: Default::default(),
deposit_per_storage_byte: Default::default(),
deposit_per_storage_item: Default::default(),
rent_allowance: Default::default(),
rent_fraction: Default::default(),
storage_size: Default::default(),
code_size: Default::default(),
code_refcount: Default::default(),
_reserved: Default::default(),
}
}
}
/// An interface that provides access to the external environment in which the
/// smart-contract is executed.
///
@@ -313,6 +292,9 @@ pub trait Ext: sealing::Sealed {
/// Information needed for rent calculations.
fn rent_params(&self) -> &RentParams<Self::T>;
/// Information about the required deposit and resulting rent.
fn rent_status(&mut self, at_refcount: u32) -> RentStatus<Self::T>;
/// Get a mutable reference to the nested gas meter.
fn gas_meter(&mut self) -> &mut GasMeter<Self::T>;
@@ -909,11 +891,11 @@ where
}
}
} else {
if let Some(message) = &self.debug_message {
if let Some((msg, false)) = self.debug_message.as_ref().map(|m| (m, m.is_empty())) {
log::debug!(
target: "runtime::contracts",
"Debug Message: {}",
core::str::from_utf8(message).unwrap_or("<Invalid UTF8>"),
"Execution finished with debug buffer: {}",
core::str::from_utf8(msg).unwrap_or("<Invalid UTF8>"),
);
}
// Write back to the root gas meter.
@@ -1240,6 +1222,20 @@ where
&self.top_frame().rent_params
}
fn rent_status(&mut self, at_refcount: u32) -> RentStatus<Self::T> {
let frame = self.top_frame_mut();
let balance = T::Currency::free_balance(&frame.account_id);
let code_size = frame.rent_params.code_size;
let refcount = frame.rent_params.code_refcount;
<Rent<T, E>>::rent_status(
&balance,
&frame.contract_info(),
code_size,
refcount,
at_refcount,
)
}
fn gas_meter(&mut self) -> &mut GasMeter<Self::T> {
&mut self.top_frame_mut().nested_meter
}
@@ -2194,6 +2190,48 @@ mod tests {
});
}
#[test]
fn rent_status_works() {
let code_hash = MockLoader::insert(Call, |ctx, _| {
assert_eq!(ctx.ext.rent_status(0), RentStatus {
max_deposit: 80000,
current_deposit: 80000,
custom_refcount_deposit: None,
max_rent: 32,
current_rent: 32,
custom_refcount_rent: None,
_reserved: None,
});
assert_eq!(ctx.ext.rent_status(1), RentStatus {
max_deposit: 80000,
current_deposit: 80000,
custom_refcount_deposit: Some(80000),
max_rent: 32,
current_rent: 32,
custom_refcount_rent: Some(32),
_reserved: None,
});
exec_success()
});
ExtBuilder::default().build().execute_with(|| {
let subsistence = Contracts::<Test>::subsistence_threshold();
let schedule = <Test as Config>::Schedule::get();
let mut gas_meter = GasMeter::<Test>::new(GAS_LIMIT);
set_balance(&ALICE, subsistence * 10);
place_contract(&BOB, code_hash);
MockStack::run_call(
ALICE,
BOB,
&mut gas_meter,
&schedule,
0,
vec![],
None,
).unwrap();
});
}
#[test]
fn in_memory_changes_not_discarded() {
// Call stack: BOB -> CHARLIE (trap) -> BOB' (success)