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

Commit

Permalink
Contracts: Make Balance Slicable. (#168)
Browse files Browse the repository at this point in the history
* Make Trait::Balance: Slicable

* Rebuild binaries.
  • Loading branch information
pepyakin authored and gavofyork committed May 23, 2018
1 parent b26259f commit 02339b0
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 847 deletions.
254 changes: 0 additions & 254 deletions demo/runtime/wasm/Cargo.lock

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
254 changes: 0 additions & 254 deletions polkadot/runtime/wasm/Cargo.lock

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
168 changes: 90 additions & 78 deletions substrate/runtime/staking/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
// TODO: Extract to it's own crate?

use codec::Slicable;
use primitives::traits::As;
use rstd::prelude::*;
use sandbox;
use {AccountDb, Module, OverlayAccountDb, Trait};
Expand Down Expand Up @@ -190,15 +189,19 @@ pub(crate) fn execute<'a, 'b: 'a, T: Trait>(
fn ext_transfer<T: Trait>(e: &mut ExecutionExt<T>, args: &[sandbox::TypedValue]) -> Result<sandbox::ReturnValue, sandbox::HostError> {
let transfer_to_ptr = args[0].as_i32().unwrap() as u32;
let transfer_to_len = args[1].as_i32().unwrap() as u32;
let value = args[2].as_i32().unwrap() as u64;
let value_ptr = args[2].as_i32().unwrap() as u32;
let value_len = args[3].as_i32().unwrap() as u32;

// TODO: slicable
let mut transfer_to = Vec::new();
transfer_to.resize(transfer_to_len as usize, 0);
e.memory().get(transfer_to_ptr, &mut transfer_to)?;
let value = T::Balance::sa(value as usize);
let transfer_to = T::AccountId::decode(&mut &transfer_to[..]).unwrap();

let mut value_buf = Vec::new();
value_buf.resize(value_len as usize, 0);
e.memory().get(value_ptr, &mut value_buf)?;
let value = T::Balance::decode(&mut &value_buf[..]).unwrap();

let account = e.account().clone();
if let Some(commit_state) =
Module::<T>::effect_transfer(&account, &transfer_to, value, e.account_db())
Expand All @@ -213,10 +216,13 @@ pub(crate) fn execute<'a, 'b: 'a, T: Trait>(
fn ext_create<T: Trait>(e: &mut ExecutionExt<T>, args: &[sandbox::TypedValue]) -> Result<sandbox::ReturnValue, sandbox::HostError> {
let code_ptr = args[0].as_i32().unwrap() as u32;
let code_len = args[1].as_i32().unwrap() as u32;
let value = args[2].as_i32().unwrap() as u32;
let value_ptr = args[2].as_i32().unwrap() as u32;
let value_len = args[3].as_i32().unwrap() as u32;

// TODO: slicable
let value = T::Balance::sa(value as usize);
let mut value_buf = Vec::new();
value_buf.resize(value_len as usize, 0);
e.memory().get(value_ptr, &mut value_buf)?;
let value = T::Balance::decode(&mut &value_buf[..]).unwrap();

let mut code = Vec::new();
code.resize(code_len as usize, 0u8);
Expand Down Expand Up @@ -506,30 +512,35 @@ mod tests {
assert_matches!(r, Err(Error::Memory));
}

#[test]
fn contract_transfer() {
let code_transfer = wabt::wat2wasm(
r#"
const CODE_TRANSFER: &str = r#"
(module
;; ext_transfer(transfer_to: u32, transfer_to_len: u32, value: u32)
(import "env" "ext_transfer" (func $ext_transfer (param i32 i32 i32)))
;; ext_transfer(transfer_to: u32, transfer_to_len: u32, value_ptr: u32, value_len: u32)
(import "env" "ext_transfer" (func $ext_transfer (param i32 i32 i32 i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(call $ext_transfer
(i32.const 4) ;; Pointer to "Transfer to" address.
(i32.const 8) ;; Length of "Transfer to" address.
(i32.const 6) ;; value to transfer
(i32.const 12) ;; Pointer to the buffer with value to transfer
(i32.const 8) ;; Length of the buffer with value to transfer.
)
)
;; Destination AccountId to transfer the funds.
;; Represented by u64 (8 bytes long) in little endian.
(data (i32.const 4) "\02\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")
)
"#,
).unwrap();
"#;

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

with_externalities(&mut new_test_ext(1, 3, 1, false), || {
<FreeBalance<Test>>::insert(0, 111);
Expand All @@ -546,61 +557,55 @@ mod tests {
});
}

fn escaped_bytestring(bytes: &[u8]) -> String {
use std::fmt::Write;
let mut result = String::new();
for b in bytes {
write!(result, "\\{:02x}", b).unwrap();
/// Returns code that uses `ext_create` runtime call.
///
/// Takes bytecode of the contract that needs to be deployed.
fn code_create(child_bytecode: &[u8]) -> String {
/// Convert a byte slice to a string with hex values.
///
/// Each value is preceeded with a `\` character.
fn escaped_bytestring(bytes: &[u8]) -> String {
use std::fmt::Write;
let mut result = String::new();
for b in bytes {
write!(result, "\\{:02x}", b).unwrap();
}
result
}
result
}

#[test]
fn contract_create() {
let code_transfer = wabt::wat2wasm(
r#"
format!(
r#"
(module
;; ext_transfer(transfer_to: u32, transfer_to_len: u32, value: u32)
(import "env" "ext_transfer" (func $ext_transfer (param i32 i32 i32)))
;; ext_create(code_ptr: u32, code_len: u32, value_ptr: u32, value_len: u32)
(import "env" "ext_create" (func $ext_create (param i32 i32 i32 i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(call $ext_transfer
(i32.const 4) ;; Pointer to "Transfer to" address.
(i32.const 8) ;; Length of "Transfer to" address.
(i32.const 6) ;; value to transfer
(call $ext_create
(i32.const 12) ;; Pointer to `code`
(i32.const {code_len}) ;; Length of `code`
(i32.const 4) ;; Pointer to the buffer with value to transfer
(i32.const 8) ;; Length of the buffer with value to transfer
)
)
;; Amount of value to transfer.
;; Represented by u64 (8 bytes long) in little endian.
(data (i32.const 4) "\03\00\00\00\00\00\00\00")
;; Destination AccountId to transfer the funds.
;; Represented by u64 (8 bytes long) in little endian.
(data (i32.const 4) "\02\00\00\00\00\00\00\00")
;; Embedded wasm code.
(data (i32.const 12) "{escaped_bytecode}")
)
"#,
).unwrap();

let code_create = wabt::wat2wasm(format!(
r#"
(module
;; ext_create(code_ptr: u32, code_len: u32, value: u32)
(import "env" "ext_create" (func $ext_create (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
"#,
escaped_bytecode = escaped_bytestring(&child_bytecode),
code_len = child_bytecode.len(),
)
}

(func (export "call")
(call $ext_create
(i32.const 4) ;; Pointer to `code`
(i32.const {code_length}) ;; Length of `code`
(i32.const 3) ;; Value to transfer
)
)
(data (i32.const 4) "{escaped_code_transfer}")
)
"#,
escaped_code_transfer = escaped_bytestring(&code_transfer),
code_length = code_transfer.len(),
)).unwrap();
#[test]
fn contract_create() {
let code_transfer = wabt::wat2wasm(CODE_TRANSFER).unwrap();
let code_create = wabt::wat2wasm(&code_create(&code_transfer)).unwrap();

with_externalities(&mut new_test_ext(1, 3, 1, false), || {
<FreeBalance<Test>>::insert(0, 111);
Expand All @@ -620,9 +625,10 @@ mod tests {
});
}

#[test]
fn contract_adder() {
let code_adder = wabt::wat2wasm(r#"
/// This code a value from the storage, increment it's first byte
/// and then stores it back in the storage.
const CODE_ADDER: &str =
r#"
(module
;; ext_set_storage(location_ptr: i32, value_non_null: bool, value_ptr: i32)
(import "env" "ext_set_storage" (func $ext_set_storage (param i32 i32 i32)))
Expand Down Expand Up @@ -652,10 +658,14 @@ mod tests {
)
)
;; Location of storage to put the data. 32 bytes.
;; Location of storage to load/store the data. 32 bytes.
(data (i32.const 4) "\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01")
)
"#).unwrap();
"#;

#[test]
fn contract_adder() {
let code_adder = wabt::wat2wasm(CODE_ADDER).unwrap();

with_externalities(&mut new_test_ext(1, 3, 1, false), || {
<FreeBalance<Test>>::insert(0, 111);
Expand All @@ -681,12 +691,10 @@ mod tests {
});
}

#[test]
fn contract_out_of_gas() {
// This code should make 100_000 iterations so it should
// consume more than 100_000 units of gas.
let code_loop = wabt::wat2wasm(
r#"
// This code should make 100_000 iterations so it should
// consume more than 100_000 units of gas.
const CODE_LOOP: &str =
r#"
(module
(func (export "call")
(local $i i32)
Expand All @@ -710,8 +718,11 @@ mod tests {
end
)
)
"#,
).unwrap();
"#;

#[test]
fn contract_out_of_gas() {
let code_loop = wabt::wat2wasm(CODE_LOOP).unwrap();

with_externalities(&mut new_test_ext(1, 3, 1, false), || {
// Set initial balances.
Expand All @@ -730,10 +741,8 @@ mod tests {
});
}

#[test]
fn contract_internal_mem() {
let code_mem = wabt::wat2wasm(
r#"
const CODE_MEM: &str =
r#"
(module
;; Internal memory is not allowed.
(memory 1 1)
Expand All @@ -742,8 +751,11 @@ mod tests {
nop
)
)
"#,
).unwrap();
"#;

#[test]
fn contract_internal_mem() {
let code_mem = wabt::wat2wasm(CODE_MEM).unwrap();

with_externalities(&mut new_test_ext(1, 3, 1, false), || {
// Set initial balances.
Expand Down
2 changes: 1 addition & 1 deletion substrate/runtime/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl<Hashing, AccountId> ContractAddressFor<AccountId> for Hashing where

pub trait Trait: system::Trait + session::Trait {
/// The balance of an account.
type Balance: Parameter + SimpleArithmetic + Default + Copy;
type Balance: Parameter + SimpleArithmetic + Slicable + Default + Copy;
type DetermineContractAddress: ContractAddressFor<Self::AccountId>;
}

Expand Down
Loading

0 comments on commit 02339b0

Please sign in to comment.