mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 07:51:03 +00:00
Integrate pallet_contracts gas with the weight system (#5712)
Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> Co-Authored-By: Sergei Pepyakin <sergei@parity.io>
This commit is contained in:
committed by
GitHub
parent
e731817e24
commit
000c924b62
@@ -26,49 +26,20 @@
|
||||
//! this guarantees that every instrumented contract code in cache cannot have the version equal to the current one.
|
||||
//! Thus, before executing a contract it should be reinstrument with new schedule.
|
||||
|
||||
use crate::gas::{Gas, GasMeter, Token};
|
||||
use crate::wasm::{prepare, runtime::Env, PrefabWasmModule};
|
||||
use crate::{CodeHash, CodeStorage, PristineCode, Schedule, Trait};
|
||||
use sp_std::prelude::*;
|
||||
use sp_runtime::traits::{Hash, Bounded};
|
||||
use sp_runtime::traits::Hash;
|
||||
use frame_support::StorageMap;
|
||||
|
||||
/// Gas metering token that used for charging storing code into the code storage.
|
||||
///
|
||||
/// Specifies the code length in bytes.
|
||||
#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PutCodeToken(u32);
|
||||
|
||||
impl<T: Trait> Token<T> for PutCodeToken {
|
||||
type Metadata = Schedule;
|
||||
|
||||
fn calculate_amount(&self, metadata: &Schedule) -> Gas {
|
||||
metadata
|
||||
.put_code_per_byte_cost
|
||||
.checked_mul(self.0.into())
|
||||
.unwrap_or_else(|| Bounded::max_value())
|
||||
}
|
||||
}
|
||||
|
||||
/// Put code in the storage. The hash of code is used as a key and is returned
|
||||
/// as a result of this function.
|
||||
///
|
||||
/// This function instruments the given code and caches it in the storage.
|
||||
pub fn save<T: Trait>(
|
||||
original_code: Vec<u8>,
|
||||
gas_meter: &mut GasMeter<T>,
|
||||
schedule: &Schedule,
|
||||
) -> Result<CodeHash<T>, &'static str> {
|
||||
// The first time instrumentation is on the user. However, consequent reinstrumentation
|
||||
// due to the schedule changes is on governance system.
|
||||
if gas_meter
|
||||
.charge(schedule, PutCodeToken(original_code.len() as u32))
|
||||
.is_out_of_gas()
|
||||
{
|
||||
return Err("there is not enough gas for storing the code");
|
||||
}
|
||||
|
||||
let prefab_module = prepare::prepare_contract::<Env>(&original_code, schedule)?;
|
||||
let code_hash = T::Hashing::hash(&original_code);
|
||||
|
||||
|
||||
@@ -157,12 +157,14 @@ mod tests {
|
||||
use crate::gas::{Gas, GasMeter};
|
||||
use crate::tests::{Test, Call};
|
||||
use crate::wasm::prepare::prepare_contract;
|
||||
use crate::CodeHash;
|
||||
use crate::{CodeHash, BalanceOf};
|
||||
use wabt;
|
||||
use hex_literal::hex;
|
||||
use assert_matches::assert_matches;
|
||||
use sp_runtime::DispatchError;
|
||||
|
||||
const GAS_LIMIT: Gas = 10_000_000_000;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct DispatchEntry(Call);
|
||||
|
||||
@@ -373,6 +375,9 @@ mod tests {
|
||||
)
|
||||
)
|
||||
}
|
||||
fn get_weight_price(&self) -> BalanceOf<Self::T> {
|
||||
1312_u32.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ext for &mut MockExt {
|
||||
@@ -478,6 +483,9 @@ mod tests {
|
||||
fn get_runtime_storage(&self, key: &[u8]) -> Option<Vec<u8>> {
|
||||
(**self).get_runtime_storage(key)
|
||||
}
|
||||
fn get_weight_price(&self) -> BalanceOf<Self::T> {
|
||||
(**self).get_weight_price()
|
||||
}
|
||||
}
|
||||
|
||||
fn execute<E: Ext>(
|
||||
@@ -544,7 +552,7 @@ mod tests {
|
||||
CODE_TRANSFER,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -553,7 +561,7 @@ mod tests {
|
||||
to: 7,
|
||||
value: 153,
|
||||
data: Vec::new(),
|
||||
gas_left: 49978,
|
||||
gas_left: 9989000000,
|
||||
}]
|
||||
);
|
||||
}
|
||||
@@ -604,7 +612,7 @@ mod tests {
|
||||
CODE_CALL,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -613,7 +621,7 @@ mod tests {
|
||||
to: 9,
|
||||
value: 6,
|
||||
data: vec![1, 2, 3, 4],
|
||||
gas_left: 49971,
|
||||
gas_left: 9985500000,
|
||||
}]
|
||||
);
|
||||
}
|
||||
@@ -666,7 +674,7 @@ mod tests {
|
||||
CODE_INSTANTIATE,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -675,7 +683,7 @@ mod tests {
|
||||
code_hash: [0x11; 32].into(),
|
||||
endowment: 3,
|
||||
data: vec![1, 2, 3, 4],
|
||||
gas_left: 49947,
|
||||
gas_left: 9973500000,
|
||||
}]
|
||||
);
|
||||
}
|
||||
@@ -709,14 +717,14 @@ mod tests {
|
||||
CODE_TERMINATE,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
&mock_ext.terminations,
|
||||
&[TerminationEntry {
|
||||
beneficiary: 0x09,
|
||||
gas_left: 49989,
|
||||
gas_left: 9994500000,
|
||||
}]
|
||||
);
|
||||
}
|
||||
@@ -767,7 +775,7 @@ mod tests {
|
||||
&CODE_TRANSFER_LIMITED_GAS,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -860,7 +868,7 @@ mod tests {
|
||||
CODE_GET_STORAGE,
|
||||
vec![],
|
||||
mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(output, ExecReturnValue { status: STATUS_SUCCESS, data: [0x22; 32].to_vec() });
|
||||
@@ -924,7 +932,7 @@ mod tests {
|
||||
CODE_CALLER,
|
||||
vec![],
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
@@ -986,7 +994,7 @@ mod tests {
|
||||
CODE_ADDRESS,
|
||||
vec![],
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
@@ -1041,7 +1049,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn balance() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let _ = execute(
|
||||
CODE_BALANCE,
|
||||
vec![],
|
||||
@@ -1101,7 +1109,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn gas_price() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1312);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let _ = execute(
|
||||
CODE_GAS_PRICE,
|
||||
vec![],
|
||||
@@ -1159,7 +1167,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn gas_left() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1312);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
|
||||
let output = execute(
|
||||
CODE_GAS_LEFT,
|
||||
@@ -1169,7 +1177,7 @@ mod tests {
|
||||
).unwrap();
|
||||
|
||||
let gas_left = Gas::decode(&mut output.data.as_slice()).unwrap();
|
||||
assert!(gas_left < 50_000, "gas_left must be less than initial");
|
||||
assert!(gas_left < GAS_LIMIT, "gas_left must be less than initial");
|
||||
assert!(gas_left > gas_meter.gas_left(), "gas_left must be greater than final");
|
||||
}
|
||||
|
||||
@@ -1224,7 +1232,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn value_transferred() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let _ = execute(
|
||||
CODE_VALUE_TRANSFERRED,
|
||||
vec![],
|
||||
@@ -1260,7 +1268,7 @@ mod tests {
|
||||
CODE_DISPATCH_CALL,
|
||||
vec![],
|
||||
&mut mock_ext,
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
@@ -1300,7 +1308,7 @@ mod tests {
|
||||
CODE_RETURN_FROM_START_FN,
|
||||
vec![],
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(output, ExecReturnValue { status: STATUS_SUCCESS, data: vec![1, 2, 3, 4] });
|
||||
@@ -1357,7 +1365,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn now() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let _ = execute(
|
||||
CODE_TIMESTAMP_NOW,
|
||||
vec![],
|
||||
@@ -1416,7 +1424,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn minimum_balance() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let _ = execute(
|
||||
CODE_MINIMUM_BALANCE,
|
||||
vec![],
|
||||
@@ -1475,7 +1483,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn tombstone_deposit() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let _ = execute(
|
||||
CODE_TOMBSTONE_DEPOSIT,
|
||||
vec![],
|
||||
@@ -1543,7 +1551,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn random() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
|
||||
let output = execute(
|
||||
CODE_RANDOM,
|
||||
@@ -1588,7 +1596,7 @@ mod tests {
|
||||
#[test]
|
||||
fn deposit_event() {
|
||||
let mut mock_ext = MockExt::default();
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let _ = execute(
|
||||
CODE_DEPOSIT_EVENT,
|
||||
vec![],
|
||||
@@ -1601,7 +1609,7 @@ mod tests {
|
||||
vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00])
|
||||
]);
|
||||
|
||||
assert_eq!(gas_meter.gas_left(), 49934);
|
||||
assert_eq!(gas_meter.gas_left(), 9967000000);
|
||||
}
|
||||
|
||||
const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#"
|
||||
@@ -1634,7 +1642,7 @@ mod tests {
|
||||
#[test]
|
||||
fn deposit_event_max_topics() {
|
||||
// Checks that the runtime traps if there are more than `max_topic_events` topics.
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
|
||||
assert_matches!(
|
||||
execute(
|
||||
@@ -1678,7 +1686,7 @@ mod tests {
|
||||
#[test]
|
||||
fn deposit_event_duplicates() {
|
||||
// Checks that the runtime traps if there are duplicates.
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
|
||||
assert_matches!(
|
||||
execute(
|
||||
@@ -1749,7 +1757,7 @@ mod tests {
|
||||
CODE_BLOCK_NUMBER,
|
||||
vec![],
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
@@ -1789,7 +1797,7 @@ mod tests {
|
||||
CODE_SIMPLE_ASSERT,
|
||||
input_data,
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(output.data.len(), 0);
|
||||
@@ -1805,7 +1813,7 @@ mod tests {
|
||||
CODE_SIMPLE_ASSERT,
|
||||
input_data,
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).err().unwrap();
|
||||
|
||||
assert_eq!(error.buffer.capacity(), 1_234);
|
||||
@@ -1859,7 +1867,7 @@ mod tests {
|
||||
CODE_RETURN_WITH_DATA,
|
||||
hex!("00112233445566778899").to_vec(),
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(output, ExecReturnValue { status: 0, data: hex!("445566778899").to_vec() });
|
||||
@@ -1872,7 +1880,7 @@ mod tests {
|
||||
CODE_RETURN_WITH_DATA,
|
||||
hex!("112233445566778899").to_vec(),
|
||||
MockExt::default(),
|
||||
&mut GasMeter::with_limit(50_000, 1),
|
||||
&mut GasMeter::new(GAS_LIMIT),
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(output, ExecReturnValue { status: 17, data: hex!("5566778899").to_vec() });
|
||||
@@ -1958,7 +1966,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn get_runtime_storage() {
|
||||
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||
let mock_ext = MockExt::default();
|
||||
|
||||
// "\01\02\03\04" - Some(0x14144020)
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
//! Environment definition of the wasm smart-contract runtime.
|
||||
|
||||
use crate::{Schedule, Trait, CodeHash, ComputeDispatchFee, BalanceOf};
|
||||
use crate::{Schedule, Trait, CodeHash, BalanceOf};
|
||||
use crate::exec::{
|
||||
Ext, ExecResult, ExecError, ExecReturnValue, StorageKey, TopicOf, STATUS_SUCCESS,
|
||||
};
|
||||
use crate::gas::{Gas, GasMeter, Token, GasMeterResult, approx_gas_for_balance};
|
||||
use crate::gas::{Gas, GasMeter, Token, GasMeterResult};
|
||||
use sp_sandbox;
|
||||
use frame_system;
|
||||
use sp_std::{prelude::*, mem, convert::TryInto};
|
||||
@@ -32,6 +32,7 @@ use sp_io::hashing::{
|
||||
blake2_128,
|
||||
sha2_256,
|
||||
};
|
||||
use frame_support::weights::GetDispatchInfo;
|
||||
|
||||
/// The value returned from ext_call and ext_instantiate contract external functions if the call or
|
||||
/// instantiation traps. This value is chosen as if the execution does not trap, the return value
|
||||
@@ -153,8 +154,8 @@ pub enum RuntimeToken {
|
||||
/// The given number of bytes is read from the sandbox memory and
|
||||
/// is returned as the return data buffer of the call.
|
||||
ReturnData(u32),
|
||||
/// Dispatch fee calculated by `T::ComputeDispatchFee`.
|
||||
ComputedDispatchFee(Gas),
|
||||
/// Dispatched a call with the given weight.
|
||||
DispatchWithWeight(Gas),
|
||||
/// (topic_count, data_bytes): A buffer of the given size is posted as an event indexed with the
|
||||
/// given number of topics.
|
||||
DepositEvent(u32, u32),
|
||||
@@ -195,7 +196,7 @@ impl<T: Trait> Token<T> for RuntimeToken {
|
||||
data_and_topics_cost.checked_add(metadata.event_base_cost)
|
||||
)
|
||||
},
|
||||
ComputedDispatchFee(gas) => Some(gas),
|
||||
DispatchWithWeight(gas) => gas.checked_add(metadata.dispatch_base_cost),
|
||||
};
|
||||
|
||||
value.unwrap_or_else(|| Bounded::max_value())
|
||||
@@ -692,7 +693,7 @@ define_env!(Env, <E: Ext>,
|
||||
// The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten.
|
||||
ext_gas_price(ctx) => {
|
||||
ctx.scratch_buf.clear();
|
||||
ctx.gas_meter.gas_price().encode_to(&mut ctx.scratch_buf);
|
||||
ctx.ext.get_weight_price().encode_to(&mut ctx.scratch_buf);
|
||||
Ok(())
|
||||
},
|
||||
|
||||
@@ -783,16 +784,14 @@ define_env!(Env, <E: Ext>,
|
||||
let call: <<E as Ext>::T as Trait>::Call =
|
||||
read_sandbox_memory_as(ctx, call_ptr, call_len)?;
|
||||
|
||||
// Charge gas for dispatching this call.
|
||||
let fee = {
|
||||
let balance_fee = <<E as Ext>::T as Trait>::ComputeDispatchFee::compute_dispatch_fee(&call);
|
||||
approx_gas_for_balance(ctx.gas_meter.gas_price(), balance_fee)
|
||||
};
|
||||
// We already deducted the len costs when reading from the sandbox.
|
||||
// Bill on the actual weight of the dispatched call.
|
||||
let info = call.get_dispatch_info();
|
||||
charge_gas(
|
||||
&mut ctx.gas_meter,
|
||||
ctx.schedule,
|
||||
&mut ctx.special_trap,
|
||||
RuntimeToken::ComputedDispatchFee(fee)
|
||||
RuntimeToken::DispatchWithWeight(info.weight)
|
||||
)?;
|
||||
|
||||
ctx.ext.note_dispatch_call(call);
|
||||
|
||||
Reference in New Issue
Block a user