Skip to content

Commit

Permalink
Contracts module rejig (paritytech#1358)
Browse files Browse the repository at this point in the history
* Move prepare under code.

* Schedule update

* CodeHash

* create takes code_hash

* pass mem def and use code in vm::execute

* Actually save and load code

* Use T::Hash as CodeHash

* Explicit entrypoint name

* Return code_hash and deposit an Event

* Charge for deployed code with gas.

* ImportSatisfyCheck and FunctionImplProvider

* Progress.

* Use new infrastructure for checking imports

* Rename entrypoint to entrypoint_name

* Use strings instead of a Error enum

* Clean

* WIP

* Fix macro_define_env test.

* Fix vm code tests.

* Remove tests for now.

* Fix borked merge

* Fix build for wasm

* fmt

* Scaffolding for abstracting vm.

* Hook up execution to exec layer.

* Fix vm tests.

* Use schedule directly in WasmLoader

* Implement test language.

* Add input_data test.

* Max depth test

* ext_caller

* Simplify test.

* Add TODO

* Some tests and todos.

* top_level

* Clean.

* Restore a couple of integration tests.

* Add a few comments.

* Add ext_address runtime call.

* Deduplicate caller/self_account

* Add not_exists test.

* Change bool to TransferCause.

* Add address tests.

* Remove output_buf from parameter.

* return from start fn.

* Smart gas meter

* Tracing

* Fix prepare tests.

* Code moving

* Add ExecFeeToken

* Use tokens everywhere.

* Make it compile in no_std.

* Lift all test requirements to TestAuxiliaries

* A minor clean

* First create tests

* Remove unneeded TODO

* Docs.

* Code shuffling

* Rename create → instantiate

* Add test address.

* Code shuffling

* Add base_fee tests.

* rejig the code

* Add some comments

* on_finalise comment

* Move event deposit further

* Update Cargo.lock

* Use crates.io version of pwasm-utils

* Format todo comments

* Fix formatting

* Comments

* EmptyOutputBuf and OutputBuf split.

* Restore code_hash

* Fix node-executor.

* Fix typo

* Fix fmt

* Update srml/contract/src/account_db.rs

Co-Authored-By: pepyakin <s.pepyakin@gmail.com>

* Update srml/contract/src/lib.rs

Co-Authored-By: pepyakin <s.pepyakin@gmail.com>

* Line wraps

* Wrapping macros

* Add _ prefix

* Grumbles

* Doc updates.

* Update srml/contract/src/wasm/mod.rs

Co-Authored-By: pepyakin <s.pepyakin@gmail.com>

* Update srml/contract/src/lib.rs

Co-Authored-By: pepyakin <s.pepyakin@gmail.com>

* Add comment

* Use saturation to signal overflow

* Add prepare_test! macro

* Require deploy function.

* Add entry point tests

* Add comment.

* Rename code → code_cache to better describe

* Get rid of weird match!

* Recompile binaries

* Add comments

* refuse_instantiate_with_value_below_existential_deposit

* Little fix

* Make test more complete

* Clean

* Add integration test for instantiation

* Rebuild runtime.

* Add some tests.

* Attach an issue to a TODO

* Attach another issue

* Apply suggestions from code review

Co-Authored-By: pepyakin <s.pepyakin@gmail.com>

* Update srml/contract/src/exec.rs

Co-Authored-By: pepyakin <s.pepyakin@gmail.com>

* Update srml/contract/src/exec.rs

Co-Authored-By: pepyakin <s.pepyakin@gmail.com>

* Recompile node_runtime
  • Loading branch information
pepyakin authored and MTDK1 committed Apr 12, 2019
1 parent ae4f49a commit 779f7c2
Show file tree
Hide file tree
Showing 18 changed files with 2,711 additions and 1,620 deletions.
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
70 changes: 19 additions & 51 deletions node/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ mod tests {
use primitives::{twox_128, Blake2Hasher, ChangesTrieConfiguration,
ed25519::{Public, Pair}};
use node_primitives::{Hash, BlockNumber, AccountId};
use runtime_primitives::traits::{Header as HeaderT, Digest as DigestT};
use runtime_primitives::traits::{Header as HeaderT, Digest as DigestT, Hash as HashT};
use runtime_primitives::{generic, generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill};
use {balances, indices, staking, session, system, consensus, timestamp, treasury, contract};
use contract::ContractAddressFor;
Expand Down Expand Up @@ -315,9 +315,9 @@ mod tests {
1,
GENESIS_HASH.into(),
if support_changes_trie {
hex!("e2dc1ed62a3878e084c49baef3eed4bc462caaa1ee9db0763eaa8d39d1affc7e").into()
hex!("cc63808897a07869d3b9103df5ad92f9be2f865ece506df5de0a87b2a95131d5").into()
} else {
hex!("7dad66de05ab6391ece9db092288cb39ba723f7f5d0b69b507b753fc92c98b8e").into()
hex!("fe5275f4d9f8130c8e80d0132f0a718ae0eeea2872c841843192720ad5c3f05a").into()
},
if support_changes_trie {
vec![changes_trie_log(
Expand All @@ -343,7 +343,7 @@ mod tests {
construct_block(
2,
block1(false).1,
hex!("f085a4077d071d3334f7553bcc3f10d97fd612e25c6df5c8f94151bbe557e24a").into(),
hex!("45b6655508fb524467b5c24184a7509b9ae07db4f95e16052ed425af182f39a8").into(),
vec![ // session changes here, so we add a grandpa change signal log.
Log::from(::grandpa::RawLog::AuthoritiesChangeSignal(0, vec![
(Keyring::One.to_raw_public().into(), 1),
Expand Down Expand Up @@ -372,7 +372,7 @@ mod tests {
construct_block(
1,
GENESIS_HASH.into(),
hex!("1d47422645f5fa3d79cff9ab5cd69ee62919c909860f063bdaf18eda834baa05").into(),
hex!("ec00658cc2826d3499dde2954e399f0a0b2596eec1b0da9b76bc72394161dc99").into(),
vec![],
vec![
CheckedExtrinsic {
Expand Down Expand Up @@ -546,6 +546,8 @@ mod tests {
(import "env" "ext_input_size" (func $ext_input_size (result i32)))
(import "env" "ext_input_copy" (func $ext_input_copy (param i32 i32 i32)))
(import "env" "memory" (memory 1 1))
(func (export "deploy")
)
(func (export "call")
(block $fail
;; fail if ext_input_size != 4
Expand Down Expand Up @@ -613,63 +615,23 @@ mod tests {
)
"#;

/// Convert a byte slice to a string with hex values.
/// 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
}

/// Create a constructor for the specified code.
///
/// When constructor is executed, it will call `ext_return` with code that
/// specified in `child_bytecode`.
fn code_ctor(child_bytecode: &[u8]) -> String {
format!(
r#"
(module
;; ext_return(data_ptr: u32, data_len: u32) -> !
(import "env" "ext_return" (func $ext_return (param i32 i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(call $ext_return
(i32.const 4)
(i32.const {code_len})
)
;; ext_return is diverging, i.e. doesn't return.
unreachable
)
(data (i32.const 4) "{escaped_bytecode}")
)
"#,
escaped_bytecode = escaped_bytestring(child_bytecode),
code_len = child_bytecode.len(),
)
}

#[test]
fn deploying_wasm_contract_should_work() {
let mut t = new_test_ext(COMPACT_CODE, false);

let code_transfer = wabt::wat2wasm(CODE_TRANSFER).unwrap();
let code_ctor_transfer = wabt::wat2wasm(&code_ctor(&code_transfer)).unwrap();
let transfer_code = wabt::wat2wasm(CODE_TRANSFER).unwrap();
let transfer_ch = <Runtime as system::Trait>::Hashing::hash(&transfer_code);

let addr = <Runtime as contract::Trait>::DetermineContractAddress::contract_address_for(
&code_ctor_transfer,
&transfer_ch,
&[],
&charlie(),
);

let b = construct_block(
1,
GENESIS_HASH.into(),
hex!("c442a475a16805d20c326f1134fe5a9656511ed7e1a7f0c7dae2dfc8612e418b").into(),
hex!("6a4da4ed61c4d9eba0477aa67024d573693df781176dfe7fe903d1088b38b266").into(),
vec![],
vec![
CheckedExtrinsic {
Expand All @@ -679,11 +641,17 @@ mod tests {
CheckedExtrinsic {
signed: Some((charlie(), 0)),
function: Call::Contract(
contract::Call::create::<Runtime>(10.into(), 10_000.into(), code_ctor_transfer, Vec::new())
contract::Call::put_code::<Runtime>(10_000.into(), transfer_code)
),
},
CheckedExtrinsic {
signed: Some((charlie(), 1)),
function: Call::Contract(
contract::Call::create::<Runtime>(10.into(), 10_000.into(), transfer_ch, Vec::new())
),
},
CheckedExtrinsic {
signed: Some((charlie(), 2)),
function: Call::Contract(
contract::Call::call::<Runtime>(indices::address::Address::Id(addr), 10.into(), 10_000.into(), vec![0x00, 0x01, 0x02, 0x03])
),
Expand All @@ -695,7 +663,7 @@ mod tests {

runtime_io::with_externalities(&mut t, || {
// Verify that the contract constructor worked well and code of TRANSFER contract is actually deployed.
assert_eq!(&contract::CodeOf::<Runtime>::get(addr), &code_transfer);
assert_eq!(&contract::CodeHashOf::<Runtime>::get(addr).unwrap(), &transfer_ch);
});
}

Expand Down
6 changes: 3 additions & 3 deletions node/runtime/wasm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
3 changes: 2 additions & 1 deletion srml/contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]

[dependencies]
serde = { version = "1.0", default-features = false }
pwasm-utils = { version = "0.3", default-features = false }
pwasm-utils = { version = "0.6.1", default-features = false }
parity-codec = { version = "2.2", default-features = false }
parity-codec-derive = { version = "2.1", default-features = false }
parity-wasm = { version = "0.31", default-features = false }
Expand All @@ -21,6 +21,7 @@ srml-balances = { path = "../balances", default-features = false }
[dev-dependencies]
wabt = "~0.7.4"
assert_matches = "1.1"
hex-literal = "0.1.0"

[features]
default = ["std"]
Expand Down
23 changes: 14 additions & 9 deletions srml/contract/src/account_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

//! Auxilliaries to help with managing partial changes to accounts state.

use super::{CodeOf, StorageOf, Trait};
use super::{CodeHash, CodeHashOf, StorageOf, Trait};
use rstd::cell::RefCell;
use rstd::collections::btree_map::{BTreeMap, Entry};
use rstd::prelude::*;
Expand All @@ -25,7 +25,8 @@ use {balances, system};

pub struct ChangeEntry<T: Trait> {
balance: Option<T::Balance>,
code: Option<Vec<u8>>,
/// In the case the outer option is None, the code_hash remains untouched, while providing `Some(None)` signifies a removing of the code in question
code: Option<Option<CodeHash<T>>>,
storage: BTreeMap<Vec<u8>, Option<Vec<u8>>>,
}

Expand All @@ -44,7 +45,7 @@ pub type ChangeSet<T> = BTreeMap<<T as system::Trait>::AccountId, ChangeEntry<T>

pub trait AccountDb<T: Trait> {
fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option<Vec<u8>>;
fn get_code(&self, account: &T::AccountId) -> Vec<u8>;
fn get_code(&self, account: &T::AccountId) -> Option<CodeHash<T>>;
fn get_balance(&self, account: &T::AccountId) -> T::Balance;

fn commit(&mut self, change_set: ChangeSet<T>);
Expand All @@ -55,8 +56,8 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
fn get_storage(&self, account: &T::AccountId, location: &[u8]) -> Option<Vec<u8>> {
<StorageOf<T>>::get(account.clone(), location.to_vec())
}
fn get_code(&self, account: &T::AccountId) -> Vec<u8> {
<CodeOf<T>>::get(account)
fn get_code(&self, account: &T::AccountId) -> Option<CodeHash<T>> {
<CodeHashOf<T>>::get(account)
}
fn get_balance(&self, account: &T::AccountId) -> T::Balance {
balances::Module::<T>::free_balance(account)
Expand All @@ -68,13 +69,17 @@ impl<T: Trait> AccountDb<T> for DirectAccountDb {
balances::Module::<T>::set_free_balance_creating(&address, balance)
{
// Account killed. This will ultimately lead to calling `OnFreeBalanceZero` callback
// which will make removal of CodeOf and StorageOf for this account.
// which will make removal of CodeHashOf and StorageOf for this account.
// In order to avoid writing over the deleted properties we `continue` here.
continue;
}
}
if let Some(code) = changed.code {
<CodeOf<T>>::insert(&address, &code);
if let Some(code) = code {
<CodeHashOf<T>>::insert(&address, code);
} else {
<CodeHashOf<T>>::remove(&address);
}
}
for (k, v) in changed.storage.into_iter() {
if let Some(value) = v {
Expand Down Expand Up @@ -116,7 +121,7 @@ impl<'a, T: Trait> OverlayAccountDb<'a, T> {
.storage
.insert(location, value);
}
pub fn set_code(&mut self, account: &T::AccountId, code: Vec<u8>) {
pub fn set_code(&mut self, account: &T::AccountId, code: Option<CodeHash<T>>) {
self.local
.borrow_mut()
.entry(account.clone())
Expand All @@ -141,7 +146,7 @@ impl<'a, T: Trait> AccountDb<T> for OverlayAccountDb<'a, T> {
.cloned()
.unwrap_or_else(|| self.underlying.get_storage(account, location))
}
fn get_code(&self, account: &T::AccountId) -> Vec<u8> {
fn get_code(&self, account: &T::AccountId) -> Option<CodeHash<T>> {
self.local
.borrow()
.get(account)
Expand Down
Loading

0 comments on commit 779f7c2

Please sign in to comment.