Some trivial externalities added (#1450)

* Add gas_left, gas_price and balance externalities

* Add a value_transferred externality
This commit is contained in:
Sergei Pepyakin
2019-01-19 12:33:28 +01:00
committed by Gav Wood
parent 1ccb590d18
commit 0ad2a5fb96
3 changed files with 309 additions and 0 deletions
+19
View File
@@ -82,6 +82,14 @@ pub trait Ext {
/// Returns a reference to the account id of the current contract.
fn address(&self) -> &AccountIdOf<Self::T>;
/// Returns the balance of the current contract.
///
/// The `value_transferred` is already added.
fn balance(&self) -> BalanceOf<Self::T>;
/// Returns the value transfered along with this call or as endowment.
fn value_transferred(&self) -> BalanceOf<Self::T>;
}
/// Loader is a companion of the `Vm` trait. It loads an appropriate abstract
@@ -292,6 +300,7 @@ where
&mut CallContext {
ctx: &mut nested,
caller: self.self_account.clone(),
value_transferred: value,
},
input_data,
empty_output_buf,
@@ -361,6 +370,7 @@ where
&mut CallContext {
ctx: &mut nested,
caller: self.self_account.clone(),
value_transferred: endowment,
},
input_data,
EmptyOutputBuf::new(),
@@ -509,6 +519,7 @@ fn transfer<'a, T: Trait, V: Vm<T>, L: Loader<T>>(
struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm<T> + 'b, L: Loader<T>> {
ctx: &'a mut ExecutionContext<'b, T, V, L>,
caller: T::AccountId,
value_transferred: T::Balance,
}
impl<'a, 'b: 'a, T, E, V, L> Ext for CallContext<'a, 'b, T, V, L>
@@ -558,6 +569,14 @@ where
fn caller(&self) -> &T::AccountId {
&self.caller
}
fn balance(&self) -> T::Balance {
self.ctx.overlay.get_balance(&self.ctx.self_account)
}
fn value_transferred(&self) -> T::Balance {
self.value_transferred
}
}
/// These tests exercise the executive layer.
+258
View File
@@ -254,6 +254,12 @@ mod tests {
fn address(&self) -> &u64 {
&69
}
fn balance(&self) -> u64 {
228
}
fn value_transferred(&self) -> u64 {
1337
}
}
fn execute<E: Ext>(
@@ -686,6 +692,257 @@ mod tests {
.unwrap();
}
const CODE_BALANCE: &str = r#"
(module
(import "env" "ext_balance" (func $ext_balance))
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))
(import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
(func $assert (param i32)
(block $ok
(br_if $ok
(get_local 0)
)
(unreachable)
)
)
(func (export "call")
;; This stores the balance in the scratch buffer
(call $ext_balance)
;; assert $ext_scratch_size == 8
(call $assert
(i32.eq
(call $ext_scratch_size)
(i32.const 8)
)
)
;; copy contents of the scratch buffer into the contract's memory.
(call $ext_scratch_copy
(i32.const 8) ;; Pointer in memory to the place where to copy.
(i32.const 0) ;; Offset from the start of the scratch buffer.
(i32.const 8) ;; Count of bytes to copy.
)
;; assert that contents of the buffer is equal to the i64 value of 228.
(call $assert
(i64.eq
(i64.load
(i32.const 8)
)
(i64.const 228)
)
)
)
(func (export "deploy"))
)
"#;
#[test]
fn balance() {
let mut mock_ext = MockExt::default();
let mut gas_meter = GasMeter::with_limit(50_000, 1);
execute(
CODE_BALANCE,
&[],
&mut Vec::new(),
&mut mock_ext,
&mut gas_meter,
)
.unwrap();
}
const CODE_GAS_PRICE: &str = r#"
(module
(import "env" "ext_gas_price" (func $ext_gas_price))
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))
(import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
(func $assert (param i32)
(block $ok
(br_if $ok
(get_local 0)
)
(unreachable)
)
)
(func (export "call")
;; This stores the gas price in the scratch buffer
(call $ext_gas_price)
;; assert $ext_scratch_size == 8
(call $assert
(i32.eq
(call $ext_scratch_size)
(i32.const 8)
)
)
;; copy contents of the scratch buffer into the contract's memory.
(call $ext_scratch_copy
(i32.const 8) ;; Pointer in memory to the place where to copy.
(i32.const 0) ;; Offset from the start of the scratch buffer.
(i32.const 8) ;; Count of bytes to copy.
)
;; assert that contents of the buffer is equal to the i64 value of 1312.
(call $assert
(i64.eq
(i64.load
(i32.const 8)
)
(i64.const 1312)
)
)
)
(func (export "deploy"))
)
"#;
#[test]
fn gas_price() {
let mut mock_ext = MockExt::default();
let mut gas_meter = GasMeter::with_limit(50_000, 1312);
execute(
CODE_GAS_PRICE,
&[],
&mut Vec::new(),
&mut mock_ext,
&mut gas_meter,
)
.unwrap();
}
const CODE_GAS_LEFT: &str = r#"
(module
(import "env" "ext_gas_left" (func $ext_gas_left))
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))
(import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32)))
(import "env" "ext_return" (func $ext_return (param i32 i32)))
(import "env" "memory" (memory 1 1))
(func $assert (param i32)
(block $ok
(br_if $ok
(get_local 0)
)
(unreachable)
)
)
(func (export "call")
;; This stores the gas left in the scratch buffer
(call $ext_gas_left)
;; assert $ext_scratch_size == 8
(call $assert
(i32.eq
(call $ext_scratch_size)
(i32.const 8)
)
)
;; copy contents of the scratch buffer into the contract's memory.
(call $ext_scratch_copy
(i32.const 8) ;; Pointer in memory to the place where to copy.
(i32.const 0) ;; Offset from the start of the scratch buffer.
(i32.const 8) ;; Count of bytes to copy.
)
(call $ext_return
(i32.const 8)
(i32.const 8)
)
(unreachable)
)
(func (export "deploy"))
)
"#;
#[test]
fn gas_left() {
let mut mock_ext = MockExt::default();
let mut gas_meter = GasMeter::with_limit(50_000, 1312);
execute(
CODE_GAS_LEFT,
&[],
&mut Vec::new(),
&mut mock_ext,
&mut gas_meter,
)
.unwrap();
}
const CODE_VALUE_TRANSFERRED: &str = r#"
(module
(import "env" "ext_value_transferred" (func $ext_value_transferred))
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))
(import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
(func $assert (param i32)
(block $ok
(br_if $ok
(get_local 0)
)
(unreachable)
)
)
(func (export "call")
;; This stores the value transferred in the scratch buffer
(call $ext_value_transferred)
;; assert $ext_scratch_size == 8
(call $assert
(i32.eq
(call $ext_scratch_size)
(i32.const 8)
)
)
;; copy contents of the scratch buffer into the contract's memory.
(call $ext_scratch_copy
(i32.const 8) ;; Pointer in memory to the place where to copy.
(i32.const 0) ;; Offset from the start of the scratch buffer.
(i32.const 8) ;; Count of bytes to copy.
)
;; assert that contents of the buffer is equal to the i64 value of 1337.
(call $assert
(i64.eq
(i64.load
(i32.const 8)
)
(i64.const 1337)
)
)
)
(func (export "deploy"))
)
"#;
#[test]
fn value_transferred() {
let mut mock_ext = MockExt::default();
let mut gas_meter = GasMeter::with_limit(50_000, 1);
execute(
CODE_VALUE_TRANSFERRED,
&[],
&mut Vec::new(),
&mut mock_ext,
&mut gas_meter,
)
.unwrap();
}
const CODE_RETURN_FROM_START_FN: &str = r#"
(module
(import "env" "ext_return" (func $ext_return (param i32 i32)))
@@ -709,6 +966,7 @@ mod tests {
)
"#;
#[test]
fn return_from_start_fn() {
let mut mock_ext = MockExt::default();
@@ -447,6 +447,38 @@ define_env!(Env, <E: Ext>,
Ok(())
},
// Stores the gas price for the current transaction into the scratch buffer.
//
// The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten.
ext_gas_price(ctx) => {
ctx.scratch_buf = ctx.gas_meter.gas_price().encode();
Ok(())
},
// 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.
ext_gas_left(ctx) => {
ctx.scratch_buf = ctx.gas_meter.gas_left().encode();
Ok(())
},
// Stores the balance of the current account into the scratch buffer.
//
// The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten.
ext_balance(ctx) => {
ctx.scratch_buf = ctx.ext.balance().encode();
Ok(())
},
// Stores the value transferred along with this call or as endowment into the scratch buffer.
//
// The data is encoded as T::Balance. The current contents of the scratch buffer are overwritten.
ext_value_transferred(ctx) => {
ctx.scratch_buf = ctx.ext.value_transferred().encode();
Ok(())
},
// Returns the size of the input buffer.
ext_input_size(ctx) -> u32 => {
Ok(ctx.input_data.len() as u32)