Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Add StorageMeter
Browse files Browse the repository at this point in the history
  • Loading branch information
athei committed Nov 6, 2021
1 parent 042ea46 commit d36a09f
Show file tree
Hide file tree
Showing 20 changed files with 2,744 additions and 1,476 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions bin/node/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ sc-executor = { version = "0.10.0-dev", path = "../../../client/executor" }
sp-core = { version = "4.0.0-dev", path = "../../../primitives/core" }
sp-keystore = { version = "0.10.0-dev", path = "../../../primitives/keystore" }
sp-state-machine = { version = "0.10.0-dev", path = "../../../primitives/state-machine" }
sp-tracing = { version = "4.0.0-dev", path = "../../../primitives/tracing" }
sp-trie = { version = "4.0.0-dev", path = "../../../primitives/trie" }
frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarking" }

Expand Down
6 changes: 4 additions & 2 deletions bin/node/executor/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ fn deploying_wasm_contract_should_work() {

let addr = pallet_contracts::Pallet::<Runtime>::contract_address(&charlie(), &transfer_ch, &[]);

let subsistence = pallet_contracts::Pallet::<Runtime>::subsistence_threshold();
let min_balance = <Runtime as pallet_contracts::Config>::Currency::minimum_balance();

let time = 42 * 1000;
let b = construct_block(
Expand All @@ -691,8 +691,9 @@ fn deploying_wasm_contract_should_work() {
signed: Some((charlie(), signed_extra(0, 0))),
function: Call::Contracts(
pallet_contracts::Call::instantiate_with_code::<Runtime> {
endowment: 1000 * DOLLARS + subsistence,
endowment: 1000 * DOLLARS + min_balance,
gas_limit: 500_000_000,
storage_limit: None,
code: transfer_code,
data: Vec::new(),
salt: Vec::new(),
Expand All @@ -705,6 +706,7 @@ fn deploying_wasm_contract_should_work() {
dest: sp_runtime::MultiAddress::Id(addr.clone()),
value: 10,
gas_limit: 500_000_000,
storage_limit: None,
data: vec![0x00, 0x01, 0x02, 0x03],
}),
},
Expand Down
2 changes: 1 addition & 1 deletion bin/node/executor/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub fn executor_call<
hash: sp_core::blake2_256(&code).to_vec(),
heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()),
};

sp_tracing::try_init_simple();
executor().call::<R, NC>(&mut t, &runtime_code, method, data, use_native, native_call)
}

Expand Down
28 changes: 19 additions & 9 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,10 +887,8 @@ impl pallet_tips::Config for Runtime {
}

parameter_types! {
pub ContractDeposit: Balance = deposit(
1,
<pallet_contracts::Pallet<Runtime>>::contract_info_size(),
);
pub const DepositPerItem: Balance = deposit(1, 0);
pub const DepositPerByte: Balance = deposit(0, 1);
pub const MaxValueSize: u32 = 16 * 1024;
// The lazy deletion runs inside on_initialize.
pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
Expand All @@ -917,7 +915,8 @@ impl pallet_contracts::Config for Runtime {
/// change because that would break already deployed contracts. The `Call` structure itself
/// is not allowed to change the indices of existing pallets, too.
type CallFilter = Nothing;
type ContractDeposit = ContractDeposit;
type DepositPerItem = DepositPerItem;
type DepositPerByte = DepositPerByte;
type CallStack = [pallet_contracts::Frame<Self>; 31];
type WeightPrice = pallet_transaction_payment::Pallet<Self>;
type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
Expand Down Expand Up @@ -1509,21 +1508,32 @@ impl_runtime_apis! {
dest: AccountId,
value: Balance,
gas_limit: u64,
storage_limit: Option<Balance>,
input_data: Vec<u8>,
) -> pallet_contracts_primitives::ContractExecResult {
Contracts::bare_call(origin, dest, value, gas_limit, input_data, true)
) -> pallet_contracts_primitives::ContractExecResult<Balance> {
Contracts::bare_call(origin, dest, value, gas_limit, storage_limit, input_data, true)
}

fn instantiate(
origin: AccountId,
endowment: Balance,
gas_limit: u64,
storage_limit: Option<Balance>,
code: pallet_contracts_primitives::Code<Hash>,
data: Vec<u8>,
salt: Vec<u8>,
) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId>
) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, Balance>
{
Contracts::bare_instantiate(origin, endowment, gas_limit, storage_limit, code, data, salt, true)
}

fn upload_code(
origin: AccountId,
code: Vec<u8>,
storage_limit: Option<Balance>,
) -> pallet_contracts_primitives::CodeUploadResult<Hash, Balance>
{
Contracts::bare_instantiate(origin, endowment, gas_limit, code, data, salt, true)
Contracts::bare_upload_code(origin, code, storage_limit)
}

fn get_storage(
Expand Down
125 changes: 119 additions & 6 deletions frame/contracts/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use bitflags::bitflags;
use codec::{Decode, Encode};
use sp_core::Bytes;
use sp_runtime::{DispatchError, RuntimeDebug};
use sp_runtime::{traits::Zero, DispatchError, RuntimeDebug, traits::Saturating};
use sp_std::prelude::*;

#[cfg(feature = "std")]
Expand All @@ -34,7 +34,7 @@ use serde::{Deserialize, Serialize};
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct ContractResult<T> {
pub struct ContractResult<R, Balance> {
/// How much gas was consumed during execution.
pub gas_consumed: u64,
/// How much gas is required as gas limit in order to execute this call.
Expand All @@ -45,7 +45,14 @@ pub struct ContractResult<T> {
///
/// This can only different from [`Self::gas_consumed`] when weight pre charging
/// is used. Currently, only `seal_call_runtime` makes use of pre charging.
/// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging
/// when a non-zero `gas_limit` argument is supplied.
pub gas_required: u64,
/// How much balance was deposited and reserved during execution in order to pay for storage.
///
/// The storage deposit is never actually charged from the caller in case of [`Self::result`]
/// is `Err`. This is because on error all storage changes are rolled back.
pub storage_deposit: StorageDeposit<Balance>,
/// An optional debug message. This message is only filled when explicitly requested
/// by the code that calls into the contract. Otherwise it is empty.
///
Expand All @@ -63,15 +70,20 @@ pub struct ContractResult<T> {
#[cfg_attr(feature = "std", serde(with = "as_string"))]
pub debug_message: Vec<u8>,
/// The execution result of the wasm code.
pub result: T,
pub result: R,
}

/// Result type of a `bare_call` call.
pub type ContractExecResult = ContractResult<Result<ExecReturnValue, DispatchError>>;
pub type ContractExecResult<Balance> =
ContractResult<Result<ExecReturnValue, DispatchError>, Balance>;

/// Result type of a `bare_instantiate` call.
pub type ContractInstantiateResult<AccountId> =
ContractResult<Result<InstantiateReturnValue<AccountId>, DispatchError>>;
pub type ContractInstantiateResult<AccountId, Balance> =
ContractResult<Result<InstantiateReturnValue<AccountId>, DispatchError>, Balance>;

/// Result type of a `bare_code_upload` call.
pub type CodeUploadResult<CodeHash, Balance> =
Result<CodeUploadReturnValue<CodeHash, Balance>, DispatchError>;

/// Result type of a `get_storage` call.
pub type GetStorageResult = Result<Option<Vec<u8>>, ContractAccessError>;
Expand Down Expand Up @@ -123,6 +135,17 @@ pub struct InstantiateReturnValue<AccountId> {
pub account_id: AccountId,
}

/// The result of succesfully uploading a contract.
#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct CodeUploadReturnValue<CodeHash, Balance> {
/// The key under which the new code is stored.
pub code_hash: CodeHash,
/// The deposit that was reserved at the caller. Is zero when the code already existed.
pub deposit: Balance,
}

/// Reference to an existing code hash or a new wasm module.
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
Expand All @@ -134,6 +157,96 @@ pub enum Code<Hash> {
Existing(Hash),
}

/// The amount of balance that was either charged or refunded in order to pay for storage.
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub enum StorageDeposit<Balance> {
/// The transaction increased overall storage usage.
///
/// This means that the specified amount of balance was transferred from the call origin
/// to the contracts involved.
Charge(Balance),
/// The transaction reduced storage consumption.
///
/// This means that the specified amount of balance was transferred from the involved
/// contracts to the call origin.
Refund(Balance),
}

impl<Balance: Zero> Default for StorageDeposit<Balance> {
fn default() -> Self {
Self::Charge(Zero::zero())
}
}

impl<Balance: Zero> StorageDeposit<Balance> {
/// Returns how much balance is charged or `0` in case of a refund.
pub fn charge_or_zero(self) -> Balance {
match self {
Self::Charge(amount) => amount,
Self::Refund(_) => Zero::zero(),
}
}
}

impl<Balance> StorageDeposit<Balance>
where
Balance: Saturating + Ord + Copy
{
/// This is essentially a saturating signed add.
pub fn saturating_add(&self, rhs: &Self) -> Self {
use StorageDeposit::*;
match (self, rhs) {
(Charge(lhs), Charge(rhs)) => Charge(lhs.saturating_add(*rhs)),
(Refund(lhs), Refund(rhs)) => Refund(lhs.saturating_add(*rhs)),
(Charge(lhs), Refund(rhs)) => if lhs >= rhs {
Charge(lhs.saturating_sub(*rhs))
} else {
Refund(rhs.saturating_sub(*lhs))
},
(Refund(lhs), Charge(rhs)) => if lhs > rhs {
Refund(lhs.saturating_sub(*rhs))
} else {
Charge(rhs.saturating_sub(*lhs))
},
}
}

/// This is essentially a saturating signed sub.
pub fn saturating_sub(&self, rhs: &Self) -> Self {
use StorageDeposit::*;
match (self, rhs) {
(Charge(lhs), Refund(rhs)) => Charge(lhs.saturating_add(*rhs)),
(Refund(lhs), Charge(rhs)) => Refund(lhs.saturating_add(*rhs)),
(Charge(lhs), Charge(rhs)) => if lhs >= rhs {
Charge(lhs.saturating_sub(*rhs))
} else {
Refund(rhs.saturating_sub(*lhs))
},
(Refund(lhs), Refund(rhs)) => if lhs > rhs {
Refund(lhs.saturating_sub(*rhs))
} else {
Charge(rhs.saturating_sub(*lhs))
},
}
}

/// If the amount of deposit (this type) is constrained by a `limit` this calcuates how
/// much balance (if any) is still available from this limit.
///
/// # Note
///
/// In case of a refund the return value can be larger than `limit`.
pub fn available(&self, limit: &Balance) -> Balance {
use StorageDeposit::*;
match self {
Charge(amount) => limit.saturating_sub(*amount),
Refund(amount) => limit.saturating_add(*amount),
}
}
}

#[cfg(feature = "std")]
mod as_string {
use super::*;
Expand Down
18 changes: 15 additions & 3 deletions frame/contracts/rpc/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

use codec::Codec;
use pallet_contracts_primitives::{
Code, ContractExecResult, ContractInstantiateResult, GetStorageResult,
Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, GetStorageResult,
};
use sp_std::vec::Vec;

Expand All @@ -45,8 +45,9 @@ sp_api::decl_runtime_apis! {
dest: AccountId,
value: Balance,
gas_limit: u64,
storage_limit: Option<Balance>,
input_data: Vec<u8>,
) -> ContractExecResult;
) -> ContractExecResult<Balance>;

/// Instantiate a new contract.
///
Expand All @@ -55,10 +56,21 @@ sp_api::decl_runtime_apis! {
origin: AccountId,
endowment: Balance,
gas_limit: u64,
storage_limit: Option<Balance>,
code: Code<Hash>,
data: Vec<u8>,
salt: Vec<u8>,
) -> ContractInstantiateResult<AccountId>;
) -> ContractInstantiateResult<AccountId, Balance>;


/// Upload new code without instantiating a contract from it.
///
/// See `pallet_contracts::Pallet::upload_code`.
fn upload_code(
origin: AccountId,
code: Vec<u8>,
storage_limit: Option<Balance>,
) -> CodeUploadResult<Hash, Balance>;

/// Query a given storage key in a given contract.
///
Expand Down
Loading

0 comments on commit d36a09f

Please sign in to comment.