srml-contract: Fix Gas type to u64 (#2944)

* srml-contract: Move gas costs from Config to Schedule.

* srml-contract: Define Gas units fixed as u64.

This removes Gas as a configurable type on the contracts Trait.

* Bump node runtime spec/impl versions.
This commit is contained in:
Jim Posen
2019-06-26 14:17:45 +02:00
committed by Gavin Wood
parent 554a790eaa
commit 4c52aec260
13 changed files with 151 additions and 145 deletions
@@ -26,11 +26,11 @@
//! 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::{GasMeter, Token};
use crate::gas::{Gas, GasMeter, Token};
use crate::wasm::{prepare, runtime::Env, PrefabWasmModule};
use crate::{CodeHash, CodeStorage, PristineCode, Schedule, Trait};
use rstd::prelude::*;
use runtime_primitives::traits::{CheckedMul, Hash, Bounded};
use runtime_primitives::traits::{Hash, Bounded};
use srml_support::StorageMap;
/// Gas metering token that used for charging storing code into the code storage.
@@ -41,12 +41,12 @@ use srml_support::StorageMap;
pub struct PutCodeToken(u32);
impl<T: Trait> Token<T> for PutCodeToken {
type Metadata = Schedule<T::Gas>;
type Metadata = Schedule;
fn calculate_amount(&self, metadata: &Schedule<T::Gas>) -> T::Gas {
fn calculate_amount(&self, metadata: &Schedule) -> Gas {
metadata
.put_code_per_byte_cost
.checked_mul(&self.0.into())
.checked_mul(self.0.into())
.unwrap_or_else(|| Bounded::max_value())
}
}
@@ -58,7 +58,7 @@ impl<T: Trait> Token<T> for PutCodeToken {
pub fn save<T: Trait>(
original_code: Vec<u8>,
gas_meter: &mut GasMeter<T>,
schedule: &Schedule<T::Gas>,
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.
@@ -69,7 +69,7 @@ pub fn save<T: Trait>(
return Err("there is not enough gas for storing the code");
}
let prefab_module = prepare::prepare_contract::<T, Env>(&original_code, schedule)?;
let prefab_module = prepare::prepare_contract::<Env>(&original_code, schedule)?;
let code_hash = T::Hashing::hash(&original_code);
<CodeStorage<T>>::insert(code_hash, prefab_module);
@@ -85,7 +85,7 @@ pub fn save<T: Trait>(
/// re-instrumentation and update the cache in the storage.
pub fn load<T: Trait>(
code_hash: &CodeHash<T>,
schedule: &Schedule<T::Gas>,
schedule: &Schedule,
) -> Result<PrefabWasmModule, &'static str> {
let mut prefab_module =
<CodeStorage<T>>::get(code_hash).ok_or_else(|| "code is not found")?;
@@ -97,7 +97,7 @@ pub fn load<T: Trait>(
// We need to re-instrument the code with the latest schedule here.
let original_code =
<PristineCode<T>>::get(code_hash).ok_or_else(|| "pristine code is not found")?;
prefab_module = prepare::prepare_contract::<T, Env>(&original_code, schedule)?;
prefab_module = prepare::prepare_contract::<Env>(&original_code, schedule)?;
<CodeStorage<T>>::insert(code_hash, prefab_module.clone());
}
Ok(prefab_module)
@@ -200,7 +200,7 @@ mod tests {
use crate::wasm::tests::MockExt;
use crate::wasm::Runtime;
use crate::exec::Ext;
use crate::Trait;
use crate::gas::Gas;
#[test]
fn macro_unmarshall_then_body_then_marshall_value_or_trap() {
@@ -256,7 +256,7 @@ mod tests {
#[test]
fn macro_define_func() {
define_func!( <E: Ext> ext_gas (_ctx, amount: u32) => {
let amount = <E::T as Trait>::Gas::from(amount);
let amount = Gas::from(amount);
if !amount.is_zero() {
Ok(())
} else {
@@ -308,7 +308,7 @@ mod tests {
define_env!(Env, <E: Ext>,
ext_gas( _ctx, amount: u32 ) => {
let amount = <E::T as Trait>::Gas::from(amount);
let amount = Gas::from(amount);
if !amount.is_zero() {
Ok(())
} else {
+12 -12
View File
@@ -63,17 +63,17 @@ pub struct WasmExecutable {
}
/// Loader which fetches `WasmExecutable` from the code cache.
pub struct WasmLoader<'a, T: Trait> {
schedule: &'a Schedule<T::Gas>,
pub struct WasmLoader<'a> {
schedule: &'a Schedule,
}
impl<'a, T: Trait> WasmLoader<'a, T> {
pub fn new(schedule: &'a Schedule<T::Gas>) -> Self {
impl<'a> WasmLoader<'a> {
pub fn new(schedule: &'a Schedule) -> Self {
WasmLoader { schedule }
}
}
impl<'a, T: Trait> crate::exec::Loader<T> for WasmLoader<'a, T> {
impl<'a, T: Trait> crate::exec::Loader<T> for WasmLoader<'a> {
type Executable = WasmExecutable;
fn load_init(&self, code_hash: &CodeHash<T>) -> Result<WasmExecutable, &'static str> {
@@ -93,17 +93,17 @@ impl<'a, T: Trait> crate::exec::Loader<T> for WasmLoader<'a, T> {
}
/// Implementation of `Vm` that takes `WasmExecutable` and executes it.
pub struct WasmVm<'a, T: Trait> {
schedule: &'a Schedule<T::Gas>,
pub struct WasmVm<'a> {
schedule: &'a Schedule,
}
impl<'a, T: Trait> WasmVm<'a, T> {
pub fn new(schedule: &'a Schedule<T::Gas>) -> Self {
impl<'a> WasmVm<'a> {
pub fn new(schedule: &'a Schedule) -> Self {
WasmVm { schedule }
}
}
impl<'a, T: Trait> crate::exec::Vm<T> for WasmVm<'a, T> {
impl<'a, T: Trait> crate::exec::Vm<T> for WasmVm<'a> {
type Executable = WasmExecutable;
fn execute<E: Ext<T = T>>(
@@ -303,9 +303,9 @@ mod tests {
use crate::exec::Vm;
let wasm = wabt::wat2wasm(wat).unwrap();
let schedule = crate::Schedule::<u64>::default();
let schedule = crate::Schedule::default();
let prefab_module =
prepare_contract::<Test, super::runtime::Env>(&wasm, &schedule).unwrap();
prepare_contract::<super::runtime::Env>(&wasm, &schedule).unwrap();
let exec = WasmExecutable {
// Use a "call" convention.
+14 -15
View File
@@ -20,33 +20,33 @@
use crate::wasm::env_def::ImportSatisfyCheck;
use crate::wasm::PrefabWasmModule;
use crate::{Schedule, Trait};
use crate::Schedule;
use parity_wasm::elements::{self, Internal, External, MemoryType, Type};
use pwasm_utils;
use pwasm_utils::rules;
use rstd::prelude::*;
use runtime_primitives::traits::{UniqueSaturatedInto, SaturatedConversion};
use runtime_primitives::traits::{SaturatedConversion};
struct ContractModule<'a, Gas: 'a> {
struct ContractModule<'a> {
/// A deserialized module. The module is valid (this is Guaranteed by `new` method).
///
/// An `Option` is used here for loaning (`take()`-ing) the module.
/// Invariant: Can't be `None` (i.e. on enter and on exit from the function
/// the value *must* be `Some`).
module: Option<elements::Module>,
schedule: &'a Schedule<Gas>,
schedule: &'a Schedule,
}
impl<'a, Gas: 'a + From<u32> + UniqueSaturatedInto<u32> + Clone> ContractModule<'a, Gas> {
impl<'a> ContractModule<'a> {
/// Creates a new instance of `ContractModule`.
///
/// Returns `Err` if the `original_code` couldn't be decoded or
/// if it contains an invalid module.
fn new(
original_code: &[u8],
schedule: &'a Schedule<Gas>,
) -> Result<ContractModule<'a, Gas>, &'static str> {
schedule: &'a Schedule,
) -> Result<Self, &'static str> {
use wasmi_validation::{validate_module, PlainValidator};
let module =
@@ -290,9 +290,9 @@ impl<'a, Gas: 'a + From<u32> + UniqueSaturatedInto<u32> + Clone> ContractModule<
/// - all imported functions from the external environment matches defined by `env` module,
///
/// The preprocessing includes injecting code for gas metering and metering the height of stack.
pub fn prepare_contract<T: Trait, C: ImportSatisfyCheck>(
pub fn prepare_contract<C: ImportSatisfyCheck>(
original_code: &[u8],
schedule: &Schedule<T::Gas>,
schedule: &Schedule,
) -> Result<PrefabWasmModule, &'static str> {
let mut contract_module = ContractModule::new(original_code, schedule)?;
contract_module.scan_exports()?;
@@ -347,7 +347,6 @@ pub fn prepare_contract<T: Trait, C: ImportSatisfyCheck>(
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::Test;
use crate::exec::Ext;
use std::fmt;
use wabt;
@@ -377,8 +376,8 @@ mod tests {
#[test]
fn $name() {
let wasm = wabt::Wat2Wasm::new().validate(false).convert($wat).unwrap();
let schedule = Schedule::<u64>::default();
let r = prepare_contract::<Test, TestEnv>(wasm.as_ref(), &schedule);
let schedule = Schedule::default();
let r = prepare_contract::<TestEnv>(wasm.as_ref(), &schedule);
assert_matches!(r, $($expected)*);
}
};
@@ -406,7 +405,7 @@ mod tests {
// Tests below assumes that maximum page number is configured to a certain number.
#[test]
fn assume_memory_size() {
assert_eq!(Schedule::<u64>::default().max_memory_pages, 16);
assert_eq!(Schedule::default().max_memory_pages, 16);
}
prepare_test!(memory_with_one_page,
@@ -620,9 +619,9 @@ mod tests {
)
"#
).unwrap();
let mut schedule = Schedule::<u64>::default();
let mut schedule = Schedule::default();
schedule.enable_println = true;
let r = prepare_contract::<Test, TestEnv>(wasm.as_ref(), &schedule);
let r = prepare_contract::<TestEnv>(wasm.as_ref(), &schedule);
assert_matches!(r, Ok(_));
}
}
+18 -18
View File
@@ -21,13 +21,13 @@ use crate::exec::{
Ext, VmExecResult, OutputBuf, EmptyOutputBuf, CallReceipt, InstantiateReceipt, StorageKey,
TopicOf,
};
use crate::gas::{GasMeter, Token, GasMeterResult, approx_gas_for_balance};
use crate::gas::{Gas, GasMeter, Token, GasMeterResult, approx_gas_for_balance};
use sandbox;
use system;
use rstd::prelude::*;
use rstd::mem;
use parity_codec::{Decode, Encode};
use runtime_primitives::traits::{CheckedMul, CheckedAdd, Bounded, SaturatedConversion};
use runtime_primitives::traits::{Bounded, SaturatedConversion};
/// Enumerates all possible *special* trap conditions.
///
@@ -45,7 +45,7 @@ pub(crate) struct Runtime<'a, E: Ext + 'a> {
// we wrap output buffer to make it possible to take the buffer out.
empty_output_buf: Option<EmptyOutputBuf>,
scratch_buf: Vec<u8>,
schedule: &'a Schedule<<E::T as Trait>::Gas>,
schedule: &'a Schedule,
memory: sandbox::Memory,
gas_meter: &'a mut GasMeter<E::T>,
special_trap: Option<SpecialTrap>,
@@ -55,7 +55,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> {
ext: &'a mut E,
input_data: Vec<u8>,
empty_output_buf: EmptyOutputBuf,
schedule: &'a Schedule<<E::T as Trait>::Gas>,
schedule: &'a Schedule,
memory: sandbox::Memory,
gas_meter: &'a mut GasMeter<E::T>,
) -> Self {
@@ -97,7 +97,7 @@ pub(crate) fn to_execution_result<E: Ext>(
#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
#[derive(Copy, Clone)]
pub enum RuntimeToken<Gas> {
pub enum RuntimeToken {
/// Explicit call to the `gas` function. Charge the gas meter
/// with the value provided.
Explicit(u32),
@@ -115,39 +115,39 @@ pub enum RuntimeToken<Gas> {
DepositEvent(u32, u32),
}
impl<T: Trait> Token<T> for RuntimeToken<T::Gas> {
type Metadata = Schedule<T::Gas>;
impl<T: Trait> Token<T> for RuntimeToken {
type Metadata = Schedule;
fn calculate_amount(&self, metadata: &Schedule<T::Gas>) -> T::Gas {
fn calculate_amount(&self, metadata: &Schedule) -> Gas {
use self::RuntimeToken::*;
let value = match *self {
Explicit(amount) => Some(amount.into()),
ReadMemory(byte_count) => metadata
.sandbox_data_read_cost
.checked_mul(&byte_count.into()),
.checked_mul(byte_count.into()),
WriteMemory(byte_count) => metadata
.sandbox_data_write_cost
.checked_mul(&byte_count.into()),
.checked_mul(byte_count.into()),
ReturnData(byte_count) => metadata
.return_data_per_byte_cost
.checked_mul(&byte_count.into()),
.checked_mul(byte_count.into()),
DepositEvent(topic_count, data_byte_count) => {
let data_cost = metadata
.event_data_per_byte_cost
.checked_mul(&data_byte_count.into());
.checked_mul(data_byte_count.into());
let topics_cost = metadata
.event_per_topic_cost
.checked_mul(&topic_count.into());
.checked_mul(topic_count.into());
data_cost
.and_then(|data_cost| {
topics_cost.and_then(|topics_cost| {
data_cost.checked_add(&topics_cost)
data_cost.checked_add(topics_cost)
})
})
.and_then(|data_and_topics_cost|
data_and_topics_cost.checked_add(&metadata.event_base_cost)
data_and_topics_cost.checked_add(metadata.event_base_cost)
)
},
ComputedDispatchFee(gas) => Some(gas),
@@ -221,7 +221,7 @@ fn read_sandbox_memory_into_buf<E: Ext>(
/// - out of gas
/// - designated area is not within the bounds of the sandbox memory.
fn write_sandbox_memory<T: Trait>(
schedule: &Schedule<T::Gas>,
schedule: &Schedule,
gas_meter: &mut GasMeter<T>,
memory: &sandbox::Memory,
ptr: u32,
@@ -509,7 +509,7 @@ define_env!(Env, <E: Ext>,
// Stores the amount of gas left into the scratch buffer.
//
// The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten.
// The data is encoded as Gas. The current contents of the scratch buffer are overwritten.
ext_gas_left(ctx) => {
ctx.scratch_buf.clear();
ctx.gas_meter.gas_left().encode_to(&mut ctx.scratch_buf);
@@ -573,7 +573,7 @@ define_env!(Env, <E: Ext>,
// 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::<<E as Ext>::T>(ctx.gas_meter.gas_price(), balance_fee)
approx_gas_for_balance(ctx.gas_meter.gas_price(), balance_fee)
};
charge_gas(&mut ctx.gas_meter, ctx.schedule, RuntimeToken::ComputedDispatchFee(fee))?;