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

Contracts: Make Balance Slicable. #168

Merged
merged 2 commits into from
May 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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