Allow spending all available gas. (#2947)

* Allow spending all gas.

* Bump node runtime version
This commit is contained in:
Sergei Pepyakin
2019-06-25 17:05:48 +02:00
committed by Gavin Wood
parent 846941550d
commit 183931a8a2
3 changed files with 55 additions and 20 deletions
+2 -2
View File
@@ -58,8 +58,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 97,
impl_version: 99,
spec_version: 98,
impl_version: 100,
apis: RUNTIME_API_VERSIONS,
};
+46 -14
View File
@@ -127,7 +127,6 @@ impl<T: Trait> GasMeter<T> {
let amount = token.calculate_amount(metadata);
let new_value = match self.gas_left.checked_sub(&amount) {
None => None,
Some(val) if val.is_zero() => None,
Some(val) => Some(val),
};
@@ -304,25 +303,25 @@ mod tests {
use super::{GasMeter, Token};
use crate::tests::Test;
/// A trivial token that charges 1 unit of gas.
/// A trivial token that charges the specified number of gas units.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct UnitToken;
impl Token<Test> for UnitToken {
struct SimpleToken(u64);
impl Token<Test> for SimpleToken {
type Metadata = ();
fn calculate_amount(&self, _metadata: &()) -> u64 { 1 }
fn calculate_amount(&self, _metadata: &()) -> u64 { self.0 }
}
struct DoubleTokenMetadata {
struct MultiplierTokenMetadata {
multiplier: u64,
}
/// A simple token that charges for the given amount multiplied to
/// a multiplier taken from a given metadata.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct DoubleToken(u64);
struct MultiplierToken(u64);
impl Token<Test> for DoubleToken {
type Metadata = DoubleTokenMetadata;
fn calculate_amount(&self, metadata: &DoubleTokenMetadata) -> u64 {
impl Token<Test> for MultiplierToken {
type Metadata = MultiplierTokenMetadata;
fn calculate_amount(&self, metadata: &MultiplierTokenMetadata) -> u64 {
// Probably you want to use saturating mul in production code.
self.0 * metadata.multiplier
}
@@ -338,7 +337,8 @@ mod tests {
fn simple() {
let mut gas_meter = GasMeter::<Test>::with_limit(50000, 10);
let result = gas_meter.charge(&DoubleTokenMetadata { multiplier: 3 }, DoubleToken(10));
let result = gas_meter
.charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10));
assert!(!result.is_out_of_gas());
assert_eq!(gas_meter.gas_left(), 49_970);
@@ -349,12 +349,44 @@ mod tests {
#[test]
fn tracing() {
let mut gas_meter = GasMeter::<Test>::with_limit(50000, 10);
assert!(!gas_meter.charge(&(), UnitToken).is_out_of_gas());
assert!(!gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas());
assert!(!gas_meter
.charge(&DoubleTokenMetadata { multiplier: 3 }, DoubleToken(10))
.charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10))
.is_out_of_gas());
let mut tokens = gas_meter.tokens()[0..2].iter();
match_tokens!(tokens, UnitToken, DoubleToken(10),);
match_tokens!(tokens, SimpleToken(1), MultiplierToken(10),);
}
// This test makes sure that nothing can be executed if there is no gas.
#[test]
fn refuse_to_execute_anything_if_zero() {
let mut gas_meter = GasMeter::<Test>::with_limit(0, 10);
assert!(gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas());
}
// Make sure that if the gas meter is charged by exceeding amount then not only an error
// returned for that charge, but also for all consequent charges.
//
// This is not striclty necessary, because the execution should be interrupred immediatelly
// if the gas meter runs out of gas. However, this is just a nice property to have.
#[test]
fn overcharge_is_unrecoverable() {
let mut gas_meter = GasMeter::<Test>::with_limit(200, 10);
// The first charge is should lead to OOG.
assert!(gas_meter.charge(&(), SimpleToken(300)).is_out_of_gas());
// The gas meter is emptied at this moment, so this should also fail.
assert!(gas_meter.charge(&(), SimpleToken(1)).is_out_of_gas());
}
// Charging the exact amount that the user paid for should be
// possible.
#[test]
fn charge_exact_amount() {
let mut gas_meter = GasMeter::<Test>::with_limit(25, 10);
assert!(!gas_meter.charge(&(), SimpleToken(25)).is_out_of_gas());
}
}
+7 -4
View File
@@ -230,14 +230,17 @@ impl ExtBuilder {
}
}
// Perform a simple transfer to a non-existent account supplying way more gas than needed.
// Then we check that the all unused gas is refunded.
#[test]
fn refunds_unused_gas() {
with_externalities(&mut ExtBuilder::default().build(), || {
Balances::deposit_creating(&0, 100_000_000);
with_externalities(&mut ExtBuilder::default().gas_price(2).build(), || {
Balances::deposit_creating(&ALICE, 100_000_000);
assert_ok!(Contract::call(Origin::signed(0), 1, 0, 100_000, Vec::new()));
assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, Vec::new()));
assert_eq!(Balances::free_balance(&0), 100_000_000 - (2 * 135));
// 2 * 135 - gas price multiplied by the call base fee.
assert_eq!(Balances::free_balance(&ALICE), 100_000_000 - (2 * 135));
});
}