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

Commit

Permalink
Specify how much gas to allot for a call
Browse files Browse the repository at this point in the history
  • Loading branch information
pepyakin committed Aug 30, 2018
1 parent 39aef46 commit 19e893b
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 18 deletions.
26 changes: 14 additions & 12 deletions substrate/runtime/contract/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,20 @@ const CODE_TRANSFER: &str = r#"
;; ext_call(
;; callee_ptr: u32,
;; callee_len: u32,
;; gas: u64,
;; value_ptr: u32,
;; value_len: u32,
;; input_data_ptr: u32,
;; input_data_len: u32
;; ) -> u32
(import "env" "ext_call" (func $ext_call (param i32 i32 i32 i32 i32 i32) (result i32)))
(import "env" "ext_call" (func $ext_call (param i32 i32 i64 i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(drop
(call $ext_call
(i32.const 4) ;; Pointer to "callee" address.
(i32.const 8) ;; Length of "callee" address.
(i64.const 0) ;; How much gas to devote for the execution. 0 = all.
(i32.const 12) ;; Pointer to the buffer with value to transfer
(i32.const 8) ;; Length of the buffer with value to transfer.
(i32.const 0) ;; Pointer to input data buffer address
Expand Down Expand Up @@ -216,10 +218,10 @@ fn contract_transfer() {
assert_eq!(
Staking::free_balance(&0),
// 3 - value sent with the transaction
// 2 * 9 - gas used by the contract (8) multiplied by gas price (2)
// 2 * 10 - gas used by the contract (10) multiplied by gas price (2)
// 2 * 135 - base gas fee for call (by transaction)
// 2 * 135 - base gas fee for call (by the contract)
100_000_000 - 3 - (2 * 9) - (2 * 135) - (2 * 135),
100_000_000 - 3 - (2 * 10) - (2 * 135) - (2 * 135),
);
assert_eq!(
Staking::free_balance(&1),
Expand Down Expand Up @@ -283,10 +285,10 @@ fn contract_transfer_max_depth() {
assert_eq!(
Staking::free_balance(&0),
// 3 - value sent with the transaction
// 2 * 9 * 100 - gas used by the contract (9) multiplied by gas price (2)
// multiplied by max depth (100).
// 2 * 10 * 100 - gas used by the contract (10) multiplied by gas price (2)
// multiplied by max depth (100).
// 2 * 135 * 100 - base gas fee for call (by transaction) multiplied by max depth (100).
100_000_000 - 3 - (2 * 135 * 100) - (2 * 9 * 100),
100_000_000 - 3 - (2 * 10 * 100) - (2 * 135 * 100),
);
assert_eq!(Staking::free_balance(&CONTRACT_SHOULD_TRANSFER_TO), 14);
});
Expand Down Expand Up @@ -396,12 +398,12 @@ fn contract_create() {
);

// 11 - value sent with the transaction
// 2 * 135 - gas spent by the deployer contract (135) multiplied by gas price (2)
// 2 * 138 - gas spent by the deployer contract (138) multiplied by gas price (2)
// 2 * 135 - base gas fee for call (top level)
// 2 * 175 - base gas fee for create (by contract)
// ((21 / 2) * 2) - price per account creation
let expected_gas_after_create =
100_000_000 - 11 - (2 * 135) - (2 * 135) - (2 * 175) - ((21 / 2) * 2);
100_000_000 - 11 - (2 * 138) - (2 * 135) - (2 * 175) - ((21 / 2) * 2);
assert_eq!(Staking::free_balance(&0), expected_gas_after_create);
assert_eq!(Staking::free_balance(&1), 8);
assert_eq!(Staking::free_balance(&derived_address), 3);
Expand All @@ -412,10 +414,10 @@ fn contract_create() {
assert_eq!(
Staking::free_balance(&0),
// 22 - value sent with the transaction
// (2 * 9) - gas used by the contract
// (2 * 10) - gas used by the contract
// (2 * 135) - base gas fee for call (top level)
// (2 * 135) - base gas fee for call (by transfer contract)
expected_gas_after_create - 22 - (2 * 9) - (2 * 135) - (2 * 135),
expected_gas_after_create - 22 - (2 * 10) - (2 * 135) - (2 * 135),
);
assert_eq!(Staking::free_balance(&derived_address), 22 - 3);
assert_eq!(Staking::free_balance(&9), 36);
Expand Down Expand Up @@ -447,12 +449,12 @@ fn top_level_create() {
));

// 11 - value sent with the transaction
// (3 * 126) - gas spent by the ctor
// (3 * 129) - gas spent by the ctor
// (3 * 175) - base gas fee for create (175) (top level) multipled by gas price (3)
// ((21 / 3) * 3) - price for contract creation
assert_eq!(
Staking::free_balance(&0),
100_000_000 - 11 - (3 * 126) - (3 * 175) - ((21 / 3) * 3)
100_000_000 - 11 - (3 * 129) - (3 * 175) - ((21 / 3) * 3)
);
assert_eq!(Staking::free_balance(&derived_address), 30 + 11);

Expand Down
11 changes: 7 additions & 4 deletions substrate/runtime/contract/src/vm/env_def/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ define_env!(init_env, <E: Ext>,
Ok(())
},

// ext_call(transfer_to_ptr: u32, transfer_to_len: u32, value_ptr: u32, value_len: u32, input_data_ptr: u32, input_data_len: u32)
ext_call(ctx, callee_ptr: u32, callee_len: u32, value_ptr: u32, value_len: u32, input_data_ptr: u32, input_data_len: u32) -> u32 => {
// ext_call(transfer_to_ptr: u32, transfer_to_len: u32, gas: u64, value_ptr: u32, value_len: u32, input_data_ptr: u32, input_data_len: u32)
ext_call(ctx, callee_ptr: u32, callee_len: u32, gas: u64, value_ptr: u32, value_len: u32, input_data_ptr: u32, input_data_len: u32) -> u32 => {
let mut callee = Vec::new();
callee.resize(callee_len as usize, 0);
ctx.memory().get(callee_ptr, &mut callee)?;
Expand All @@ -201,8 +201,11 @@ define_env!(init_env, <E: Ext>,
input_data.resize(input_data_len as usize, 0u8);
ctx.memory().get(input_data_ptr, &mut input_data)?;

// TODO: Let user to choose how much gas to allocate for the execution.
let nested_gas_limit = ctx.gas_meter.gas_left();
let nested_gas_limit = if gas == 0 {
ctx.gas_meter.gas_left()
} else {
<<<E as Ext>::T as Trait>::Gas as As<u64>>::sa(gas)
};
let ext = &mut ctx.ext;
let call_outcome = ctx.gas_meter.with_nested(nested_gas_limit, |nested_meter| {
match nested_meter {
Expand Down
71 changes: 69 additions & 2 deletions substrate/runtime/contract/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ mod tests {
to: u64,
value: u64,
data: Vec<u8>,
gas_left: u64,
}
#[derive(Default)]
pub struct MockExt {
Expand Down Expand Up @@ -320,13 +321,14 @@ mod tests {
&mut self,
to: &u64,
value: u64,
_gas_meter: &mut GasMeter<Test>,
gas_meter: &mut GasMeter<Test>,
data: &[u8],
) -> Result<CallReceipt, ()> {
self.transfers.push(TransferEntry {
to: *to,
value,
data: data.to_vec(),
gas_left: gas_meter.gas_left(),
});
// Assume for now that it was just a plain transfer.
// TODO: Add tests for different call outcomes.
Expand All @@ -341,18 +343,20 @@ mod tests {
;; ext_call(
;; callee_ptr: u32,
;; callee_len: u32,
;; gas: u64,
;; value_ptr: u32,
;; value_len: u32,
;; input_data_ptr: u32,
;; input_data_len: u32
;;) -> u32
(import "env" "ext_call" (func $ext_call (param i32 i32 i32 i32 i32 i32) (result i32)))
(import "env" "ext_call" (func $ext_call (param i32 i32 i64 i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(drop
(call $ext_call
(i32.const 4) ;; Pointer to "callee" address.
(i32.const 8) ;; Length of "callee" address.
(i64.const 0) ;; How much gas to devote for the execution. 0 = all.
(i32.const 12) ;; Pointer to the buffer with value to transfer
(i32.const 8) ;; Length of the buffer with value to transfer.
(i32.const 20) ;; Pointer to input data buffer address
Expand Down Expand Up @@ -391,6 +395,7 @@ mod tests {
data: vec![
1, 2, 3, 4,
],
gas_left: 49990,
}]
);
}
Expand Down Expand Up @@ -480,4 +485,66 @@ mod tests {
Err(_)
);
}

const CODE_TRANSFER_LIMITED_GAS: &str = r#"
(module
;; ext_call(
;; callee_ptr: u32,
;; callee_len: u32,
;; gas: u64,
;; value_ptr: u32,
;; value_len: u32,
;; input_data_ptr: u32,
;; input_data_len: u32
;;) -> u32
(import "env" "ext_call" (func $ext_call (param i32 i32 i64 i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(drop
(call $ext_call
(i32.const 4) ;; Pointer to "callee" address.
(i32.const 8) ;; Length of "callee" address.
(i64.const 228) ;; How much gas to devote for the execution.
(i32.const 12) ;; Pointer to the buffer with value to transfer
(i32.const 8) ;; Length of the buffer with value to transfer.
(i32.const 20) ;; Pointer to input data buffer address
(i32.const 4) ;; Length of input data buffer
)
)
)
;; Destination AccountId to transfer the funds.
;; Represented by u64 (8 bytes long) in little endian.
(data (i32.const 4) "\09\00\00\00\00\00\00\00")
;; Amount of value to transfer.
;; Represented by u64 (8 bytes long) in little endian.
(data (i32.const 12) "\06\00\00\00\00\00\00\00")
(data (i32.const 20) "\01\02\03\04")
)
"#;

#[test]
fn contract_call_limited_gas() {
let code_transfer = wabt::wat2wasm(CODE_TRANSFER_LIMITED_GAS).unwrap();

let mut mock_ext = MockExt::default();
execute(
&code_transfer,
&[],
&mut mock_ext,
&mut GasMeter::with_limit(50_000, 1),
).unwrap();

assert_eq!(
&mock_ext.transfers,
&[TransferEntry {
to: 9,
value: 6,
data: vec![
1, 2, 3, 4,
],
gas_left: 228,
}]
);
}
}

0 comments on commit 19e893b

Please sign in to comment.