* ethash: implement EIP-1234 (#9187)
* Implement EIP-1052 (EXTCODEHASH) and fix several issues in state account cache (#9234)
* Implement EIP-1052 and fix several issues related to account cache
* Fix jsontests
* Merge two matches together
* Avoid making unnecessary Arc<Vec>
* Address grumbles
* Comply EIP-86 with the new definition (#9140)
* Comply EIP-86 with the new CREATE2 opcode
* Fix rpc compile
* Fix interpreter CREATE/CREATE2 stack pop difference
* Add unreachable! to fix compile
* Fix instruction_info
* Fix gas check due to new stack item
* Add new tests in executive
* Fix have_create2 comment
* Remove all unused references of eip86_transition and block_number
* Implement KIP4: create2 for wasm (#9277)
* Basic implementation for kip4
* Add KIP-4 config flags
* typo: docs fix
* Fix args offset
* Add tests for create2
* tests: evm
* Update wasm-tests and fix all gas costs
* Update wasm-tests
* Update wasm-tests and fix gas costs
* `gasleft` extern implemented for WASM runtime (kip-6) (#9357)
* Wasm gasleft extern added
* wasm_gasleft_activation_transition -> kip4_transition
* use kip-6 switch
* gasleft_panic -> gasleft_fail rename
* call_msg_gasleft test added and gas_left agustments because this https://github.com/paritytech/wasm-tests/pull/52
* change .. to _
* fix comment for the have_gasleft param
* update tests (0edbf860ff)
* Add EIP-1014 transition config flag (#9268)
* Add EIP-1014 transition config flag
* Remove EIP-86 configs
* Change CREATE2 opcode index to 0xf5
* Move salt to the last item in the stack
* Change sendersaltandaddress scheme to comply with current EIP-1014
* Fix json configs
* Fix create2 test
* Fix deprecated comments
* EIP 1283: Net gas metering for SSTORE without dirty maps (#9319)
* Implement last_checkpoint_storage_at
* Add reverted_storage_at for externalities
* sstore_clears_count -> sstore_clears_refund
* Implement eip1283 for evm
* Add eip1283Transition params
* evm: fix tests
* jsontests: fix test
* Return checkpoint index when creating
* Comply with spec Version II
* Fix docs
* Fix jsontests feature compile
* Address grumbles
* Fix no-checkpoint-entry case
* Remove unnecessary expect
* Add test for State::checkpoint_storage_at
* Add executive level test for eip1283
* Hard-code transaction_checkpoint_index to 0
* Fix jsontests
* Add tests for checkpoint discard/revert
* Require checkpoint to be empty for kill_account and commit
* Get code coverage
* Use saturating_add/saturating_sub
* Fix issues in insert_cache
* Clear the state again
* Fix original_storage_at
* Early return for empty RLP trie storage
* Update comments
* Fix borrow_mut issue
* Simplify checkpoint_storage_at if branches
* Better commenting for gas handling code
* Address naming grumbles
* More tests
* Fix an issue in overwrite_with
* Add another test
* Fix comment
* Remove unnecessary bracket
* Move orig to inner if
* Remove test coverage for this PR
* Add tests for executive original value
* Add warn! for an unreachable cause
* Update state tests execution model (#9440)
* Update & fix JSON state tests.
* Update tests to be able to run ethtest at
021fe3d410773024cd5f0387e62db6e6ec800f32.
- Touch user in state
- Adjust transaction tests to new json format
* Switch to same commit for submodule ethereum/test as geth (next includes constantinople changes).
Added test `json_tests::trie::generic::TrieTests_trieanyorder` and a few
difficulty tests.
* Remove trietestnextprev as it would require to parse differently and
implement it.
* Support new (shitty) format of transaction tests.
* Ignore junk in ethereum/tests repo.
* Ignore incorrect test.
* Update to a later commit
* Move block number to a constant.
* Fix ZK2 test - touched account should also be cleared.
* Fix conflict resolution
* Fix checkpointing when creating contract failed (#9514)
* In create memory calculation is the same for create2 because the additional parameter was popped before. (#9522)
* Enable all Constantinople hard fork changes in constantinople_test.json (#9505)
* Enable all Constantinople hard fork changes in constantinople_test.json
* Address grumbles
* Remove EIP-210 activation
* 8m -> 5m
* Temporarily add back eip210 transition so we can get test passed
* Add eip210_test and remove eip210 transition from const_test
* Add constantinople conf to EvmTestClient. (#9570)
* Add constantinople conf to EvmTestClient.
* Skip some test to update submodule etheureum/tests submodule to latest.
* Put skipping 'under issue' test behind a feature.
* Change blockReward for const-test to pass ethereum/tests
* Update tests to new constantinple definition (change of reward at block
5).
Switch 'reference' to string, that way we can include issues from others
repo (more flexible)Update tests to new constantinple definition (change
of reward at block 5).
Switch 'reference' to string, that way we can include issues from others
repo (more flexible).
* Fix modexp and bn128_mul gas prices in chain config
* Changes `run_test_path` method to append its directory results (without
that it stop testing at the first file failure).
Add some missing tests.
Add skip for those (block create2 is one hundred percent false but on
hive we can see that geth and aleth got similar issue for this item).
* retab current.json
* Update reference to parity issue for failing tests.
* Hardfork the testnets (#9562)
* ethcore: propose hardfork block number 4230000 for ropsten
* ethcore: propose hardfork block number 9000000 for kovan
* ethcore: enable kip-4 and kip-6 on kovan
* etcore: bump kovan hardfork to block 9.2M
* ethcore: fix ropsten constantinople block number to 4.2M
* ethcore: disable difficulty_test_ropsten until ethereum/tests are updated upstream
* Don't hash the init_code of CREATE. (#9688)
* Implement CREATE2 gas changes and fix some potential overflowing (#9694)
* Implement CREATE2 gas changes and fix some potential overflowing
* Ignore create2 state tests
* Split CREATE and CREATE2 in gasometer
* Generalize rounding (x + 31) / 32 to to_word_size
* ethcore: delay ropsten hardfork (#9704)
* Add hardcoded headers (#9730)
* add foundation hardcoded header #6486017
* add ropsten hardcoded headers #4202497
* add kovan hardcoded headers #9023489
* gitlab ci: releasable_branches: change variables condition to schedule (#9729)
* HF in POA Core (2018-10-22) (#9724)
https://github.com/poanetwork/poa-chain-spec/pull/87
1007 lines
32 KiB
Rust
1007 lines
32 KiB
Rust
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
|
// This file is part of Parity.
|
|
|
|
// Parity is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Parity is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use std::sync::Arc;
|
|
use std::collections::HashMap;
|
|
use byteorder::{LittleEndian, ByteOrder};
|
|
use ethereum_types::{H256, U256, Address};
|
|
|
|
use super::WasmInterpreter;
|
|
use vm::{self, Vm, GasLeft, ActionParams, ActionValue, CreateContractAddress};
|
|
use vm::tests::{FakeCall, FakeExt, FakeCallType};
|
|
|
|
macro_rules! load_sample {
|
|
($name: expr) => {
|
|
include_bytes!(concat!("../../res/wasm-tests/compiled/", $name)).to_vec()
|
|
}
|
|
}
|
|
|
|
macro_rules! reqrep_test {
|
|
($name: expr, $input: expr) => {
|
|
reqrep_test!($name, $input, vm::EnvInfo::default(), HashMap::new())
|
|
};
|
|
($name: expr, $input: expr, $info: expr, $block_hashes: expr) => {
|
|
{
|
|
::ethcore_logger::init_log();
|
|
let code = load_sample!($name);
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some($input);
|
|
|
|
let mut fake_ext = FakeExt::new().with_wasm();
|
|
fake_ext.info = $info;
|
|
fake_ext.blockhashes = $block_hashes;
|
|
|
|
let mut interpreter = wasm_interpreter();
|
|
interpreter.exec(params, &mut fake_ext)
|
|
.map(|result| match result {
|
|
GasLeft::Known(_) => { panic!("Test is expected to return payload to check"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
})
|
|
}
|
|
};
|
|
}
|
|
|
|
fn test_finalize(res: Result<GasLeft, vm::Error>) -> Result<U256, vm::Error> {
|
|
match res {
|
|
Ok(GasLeft::Known(gas)) => Ok(gas),
|
|
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
|
|
fn wasm_interpreter() -> WasmInterpreter {
|
|
WasmInterpreter
|
|
}
|
|
|
|
/// Empty contract does almost nothing except producing 1 (one) local node debug log message
|
|
#[test]
|
|
fn empty() {
|
|
let code = load_sample!("empty.wasm");
|
|
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.address = address.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
|
};
|
|
|
|
assert_eq!(gas_left, U256::from(96_926));
|
|
}
|
|
|
|
// This test checks if the contract deserializes payload header properly.
|
|
// Contract is provided with receiver(address), sender, origin and transaction value
|
|
// logger.wasm writes all these provided fixed header fields to some arbitrary storage keys.
|
|
#[test]
|
|
fn logger() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let code = load_sample!("logger.wasm");
|
|
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
let sender: Address = "0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d".parse().unwrap();
|
|
let origin: Address = "0102030405060708090a0b0c0d0e0f1011121314".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.address = address.clone();
|
|
params.sender = sender.clone();
|
|
params.origin = origin.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.value = ActionValue::transfer(1_000_000_000);
|
|
params.code = Some(Arc::new(code));
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
|
};
|
|
|
|
let address_val: H256 = address.into();
|
|
assert_eq!(
|
|
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
|
&address_val,
|
|
"Logger sets 0x01 key to the provided address"
|
|
);
|
|
let sender_val: H256 = sender.into();
|
|
assert_eq!(
|
|
ext.store.get(&"0200000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
|
&sender_val,
|
|
"Logger sets 0x02 key to the provided sender"
|
|
);
|
|
let origin_val: H256 = origin.into();
|
|
assert_eq!(
|
|
ext.store.get(&"0300000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
|
&origin_val,
|
|
"Logger sets 0x03 key to the provided origin"
|
|
);
|
|
assert_eq!(
|
|
U256::from(ext.store.get(&"0400000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist")),
|
|
U256::from(1_000_000_000),
|
|
"Logger sets 0x04 key to the trasferred value"
|
|
);
|
|
assert_eq!(gas_left, U256::from(17_716));
|
|
}
|
|
|
|
// This test checks if the contract can allocate memory and pass pointer to the result stream properly.
|
|
// 1. Contract is being provided with the call descriptor ptr
|
|
// 2. Descriptor ptr is 16 byte length
|
|
// 3. The last 8 bytes of call descriptor is the space for the contract to fill [result_ptr[4], result_len[4]]
|
|
// if it has any result.
|
|
#[test]
|
|
fn identity() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let code = load_sample!("identity.wasm");
|
|
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.sender = sender.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("Identity contract should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
assert_eq!(
|
|
Address::from_slice(&result),
|
|
sender,
|
|
"Idenity test contract does not return the sender passed"
|
|
);
|
|
assert_eq!(gas_left, U256::from(98_419));
|
|
}
|
|
|
|
// Dispersion test sends byte array and expect the contract to 'disperse' the original elements with
|
|
// their modulo 19 dopant.
|
|
// The result is always twice as long as the input.
|
|
// This also tests byte-perfect memory allocation and in/out ptr lifecycle.
|
|
#[test]
|
|
fn dispersion() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let code = load_sample!("dispersion.wasm");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some(vec![
|
|
0u8, 125, 197, 255, 19
|
|
]);
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("Dispersion routine should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
assert_eq!(
|
|
result,
|
|
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
|
|
);
|
|
assert_eq!(gas_left, U256::from(92_377));
|
|
}
|
|
|
|
#[test]
|
|
fn suicide_not() {
|
|
let code = load_sample!("suicidal.wasm");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some(vec![
|
|
0u8
|
|
]);
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("Suicidal contract should return payload when had not actualy killed himself"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
assert_eq!(
|
|
result,
|
|
vec![0u8]
|
|
);
|
|
assert_eq!(gas_left, U256::from(93_378));
|
|
}
|
|
|
|
#[test]
|
|
fn suicide() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let code = load_sample!("suicidal.wasm");
|
|
|
|
let refund: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
|
|
let mut args = vec![127u8];
|
|
args.extend(refund.to_vec());
|
|
params.data = Some(args);
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(gas) => gas,
|
|
GasLeft::NeedsReturn { .. } => {
|
|
panic!("Suicidal contract should not return anything when had killed itself");
|
|
},
|
|
}
|
|
};
|
|
|
|
assert!(ext.suicides.contains(&refund));
|
|
assert_eq!(gas_left, U256::from(93_346));
|
|
}
|
|
|
|
#[test]
|
|
fn create() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(load_sample!("creator.wasm")));
|
|
params.data = Some(vec![0u8, 2, 4, 8, 16, 32, 64, 128]);
|
|
params.value = ActionValue::transfer(1_000_000_000);
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
ext.schedule.wasm.as_mut().unwrap().have_create2 = true;
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => {
|
|
panic!("Create contract always return 40 bytes of the creation address, or in the case where it fails, return 40 bytes of zero.");
|
|
},
|
|
GasLeft::NeedsReturn { gas_left, data, apply_state } => {
|
|
assert!(apply_state);
|
|
assert_eq!(data.as_ref(), [0u8; 40].as_ref()); // FakeExt never succeeds in create.
|
|
gas_left
|
|
},
|
|
}
|
|
};
|
|
|
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
|
assert!(ext.calls.contains(
|
|
&FakeCall {
|
|
call_type: FakeCallType::Create,
|
|
create_scheme: Some(CreateContractAddress::FromSenderAndCodeHash),
|
|
gas: U256::from(49_674),
|
|
sender_address: None,
|
|
receive_address: None,
|
|
value: Some((1_000_000_000 / 2).into()),
|
|
data: vec![0u8, 2, 4, 8, 16, 32, 64, 128],
|
|
code_address: None,
|
|
}
|
|
));
|
|
assert!(ext.calls.contains(
|
|
&FakeCall {
|
|
call_type: FakeCallType::Create,
|
|
create_scheme: Some(CreateContractAddress::FromSenderSaltAndCodeHash(H256::from([5u8].as_ref()))),
|
|
gas: U256::from(6039),
|
|
sender_address: None,
|
|
receive_address: None,
|
|
value: Some((1_000_000_000 / 2).into()),
|
|
data: vec![0u8, 2, 4, 8, 16, 32, 64, 128],
|
|
code_address: None,
|
|
}
|
|
));
|
|
assert_eq!(gas_left, U256::from(5974));
|
|
}
|
|
|
|
#[test]
|
|
fn call_msg() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
|
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.sender = sender.clone();
|
|
params.address = receiver.clone();
|
|
params.code_address = contract_address.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(load_sample!("call.wasm")));
|
|
params.data = Some(Vec::new());
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
ext.balances.insert(receiver.clone(), U256::from(10000000000u64));
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(gas_left) => gas_left,
|
|
GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); },
|
|
}
|
|
};
|
|
|
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
|
assert!(ext.calls.contains(
|
|
&FakeCall {
|
|
call_type: FakeCallType::Call,
|
|
create_scheme: None,
|
|
gas: U256::from(33_000),
|
|
sender_address: Some(receiver),
|
|
receive_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
|
|
value: Some(1000000000.into()),
|
|
data: vec![129u8, 123, 113, 107, 101, 97],
|
|
code_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
|
|
}
|
|
));
|
|
|
|
assert_eq!(gas_left, U256::from(91_672));
|
|
}
|
|
|
|
// The same as `call_msg`, but send a `pwasm_ethereum::gasleft`
|
|
// value as `gas` argument to the inner pwasm_ethereum::call
|
|
#[test]
|
|
fn call_msg_gasleft() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
|
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.sender = sender.clone();
|
|
params.address = receiver.clone();
|
|
params.code_address = contract_address.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(load_sample!("call_gasleft.wasm")));
|
|
params.data = Some(Vec::new());
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
ext.schedule.wasm.as_mut().unwrap().have_gasleft = true;
|
|
ext.balances.insert(receiver.clone(), U256::from(10000000000u64));
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(gas_left) => gas_left,
|
|
GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); },
|
|
}
|
|
};
|
|
|
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
|
assert!(ext.calls.contains(
|
|
&FakeCall {
|
|
call_type: FakeCallType::Call,
|
|
create_scheme: None,
|
|
gas: U256::from(91_165),
|
|
sender_address: Some(receiver),
|
|
receive_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
|
|
value: Some(1000000000.into()),
|
|
data: vec![129u8, 123, 113, 107, 101, 97],
|
|
code_address: Some(Address::from([99, 88, 77, 66, 55, 44, 33, 22, 11, 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 0])),
|
|
}
|
|
));
|
|
|
|
assert_eq!(gas_left, U256::from(91_671));
|
|
}
|
|
|
|
#[test]
|
|
fn call_code() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
|
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.sender = sender.clone();
|
|
params.address = receiver.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(load_sample!("call_code.wasm")));
|
|
params.data = Some(Vec::new());
|
|
params.value = ActionValue::transfer(1_000_000_000);
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("Call test should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
|
assert!(ext.calls.contains(
|
|
&FakeCall {
|
|
call_type: FakeCallType::Call,
|
|
create_scheme: None,
|
|
gas: U256::from(20_000),
|
|
sender_address: Some(sender),
|
|
receive_address: Some(receiver),
|
|
value: None,
|
|
data: vec![1u8, 2, 3, 5, 7, 11],
|
|
code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()),
|
|
}
|
|
));
|
|
|
|
// siphash result
|
|
let res = LittleEndian::read_u32(&result[..]);
|
|
assert_eq!(res, 4198595614);
|
|
assert_eq!(gas_left, U256::from(90_037));
|
|
}
|
|
|
|
#[test]
|
|
fn call_static() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let sender: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
let receiver: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
|
let contract_address: Address = "0d461d4174b4ae35775c4a342f1e5e1e4e6c4db5".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.sender = sender.clone();
|
|
params.address = receiver.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(load_sample!("call_static.wasm")));
|
|
params.data = Some(Vec::new());
|
|
params.value = ActionValue::transfer(1_000_000_000);
|
|
params.code_address = contract_address.clone();
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("Static call test should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
|
assert!(ext.calls.contains(
|
|
&FakeCall {
|
|
call_type: FakeCallType::Call,
|
|
create_scheme: None,
|
|
gas: U256::from(20_000),
|
|
sender_address: Some(receiver),
|
|
receive_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
|
|
value: None,
|
|
data: vec![1u8, 2, 3, 5, 7, 11],
|
|
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
|
|
}
|
|
));
|
|
|
|
// siphash result
|
|
let res = LittleEndian::read_u32(&result[..]);
|
|
assert_eq!(res, 317632590);
|
|
|
|
assert_eq!(gas_left, U256::from(90_042));
|
|
}
|
|
|
|
// Realloc test
|
|
#[test]
|
|
fn realloc() {
|
|
let code = load_sample!("realloc.wasm");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some(vec![0u8]);
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("Realloc should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
assert_eq!(result, vec![0u8; 2]);
|
|
assert_eq!(gas_left, U256::from(92_848));
|
|
}
|
|
|
|
#[test]
|
|
fn alloc() {
|
|
let code = load_sample!("alloc.wasm");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(10_000_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some(vec![0u8]);
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("alloc test should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
assert_eq!(result, vec![5u8; 1024*400]);
|
|
assert_eq!(gas_left, U256::from(6_893_881));
|
|
}
|
|
|
|
// Tests that contract's ability to read from a storage
|
|
// Test prepopulates address into storage, than executes a contract which read that address from storage and write this address into result
|
|
#[test]
|
|
fn storage_read() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let code = load_sample!("storage_read.wasm");
|
|
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
ext.store.insert("0100000000000000000000000000000000000000000000000000000000000000".into(), address.into());
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("storage_read should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
assert_eq!(Address::from(&result[12..32]), address);
|
|
assert_eq!(gas_left, U256::from(98_369));
|
|
}
|
|
|
|
// Tests keccak calculation
|
|
// keccak.wasm runs wasm-std::keccak function on data param and returns hash
|
|
#[test]
|
|
fn keccak() {
|
|
::ethcore_logger::init_log();
|
|
let code = load_sample!("keccak.wasm");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some(b"something".to_vec());
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("keccak should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
|
assert_eq!(gas_left, U256::from(85_949));
|
|
}
|
|
|
|
// math_* tests check the ability of wasm contract to perform big integer operations
|
|
// - addition
|
|
// - multiplication
|
|
// - substraction
|
|
// - division
|
|
|
|
// addition
|
|
#[test]
|
|
fn math_add() {
|
|
|
|
let (gas_left, result) = reqrep_test!(
|
|
"math.wasm",
|
|
{
|
|
let mut args = [0u8; 65];
|
|
let arg_a = U256::from_dec_str("999999999999999999999999999999").unwrap();
|
|
let arg_b = U256::from_dec_str("888888888888888888888888888888").unwrap();
|
|
arg_a.to_big_endian(&mut args[1..33]);
|
|
arg_b.to_big_endian(&mut args[33..65]);
|
|
args.to_vec()
|
|
}
|
|
).expect("Interpreter to execute without any errors");
|
|
|
|
assert_eq!(
|
|
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
|
(&result[..]).into()
|
|
);
|
|
assert_eq!(gas_left, U256::from(92_072));
|
|
}
|
|
|
|
// multiplication
|
|
#[test]
|
|
fn math_mul() {
|
|
let (gas_left, result) = reqrep_test!(
|
|
"math.wasm",
|
|
{
|
|
let mut args = [1u8; 65];
|
|
let arg_a = U256::from_dec_str("888888888888888888888888888888").unwrap();
|
|
let arg_b = U256::from_dec_str("999999999999999999999999999999").unwrap();
|
|
arg_a.to_big_endian(&mut args[1..33]);
|
|
arg_b.to_big_endian(&mut args[33..65]);
|
|
args.to_vec()
|
|
}
|
|
).expect("Interpreter to execute without any errors");
|
|
|
|
assert_eq!(
|
|
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
|
(&result[..]).into()
|
|
);
|
|
assert_eq!(gas_left, U256::from(91_400));
|
|
}
|
|
|
|
// subtraction
|
|
#[test]
|
|
fn math_sub() {
|
|
let (gas_left, result) = reqrep_test!(
|
|
"math.wasm",
|
|
{
|
|
let mut args = [2u8; 65];
|
|
let arg_a = U256::from_dec_str("999999999999999999999999999999").unwrap();
|
|
let arg_b = U256::from_dec_str("888888888888888888888888888888").unwrap();
|
|
arg_a.to_big_endian(&mut args[1..33]);
|
|
arg_b.to_big_endian(&mut args[33..65]);
|
|
args.to_vec()
|
|
}
|
|
).expect("Interpreter to execute without any errors");
|
|
|
|
assert_eq!(
|
|
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
|
(&result[..]).into()
|
|
);
|
|
assert_eq!(gas_left, U256::from(92_072));
|
|
}
|
|
|
|
// subtraction with overflow
|
|
#[test]
|
|
fn math_sub_with_overflow() {
|
|
let result = reqrep_test!(
|
|
"math.wasm",
|
|
{
|
|
let mut args = [2u8; 65];
|
|
let arg_a = U256::from_dec_str("888888888888888888888888888888").unwrap();
|
|
let arg_b = U256::from_dec_str("999999999999999999999999999999").unwrap();
|
|
arg_a.to_big_endian(&mut args[1..33]);
|
|
arg_b.to_big_endian(&mut args[33..65]);
|
|
args.to_vec()
|
|
}
|
|
);
|
|
|
|
match result {
|
|
Err(vm::Error::Wasm(_)) => {},
|
|
_ => panic!("Unexpected result {:?}", result),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn math_div() {
|
|
let (gas_left, result) = reqrep_test!(
|
|
"math.wasm",
|
|
{
|
|
let mut args = [3u8; 65];
|
|
let arg_a = U256::from_dec_str("999999999999999999999999999999").unwrap();
|
|
let arg_b = U256::from_dec_str("888888888888888888888888").unwrap();
|
|
arg_a.to_big_endian(&mut args[1..33]);
|
|
arg_b.to_big_endian(&mut args[33..65]);
|
|
args.to_vec()
|
|
}
|
|
).expect("Interpreter to execute without any errors");
|
|
|
|
assert_eq!(
|
|
U256::from_dec_str("1125000").unwrap(),
|
|
(&result[..]).into()
|
|
);
|
|
assert_eq!(gas_left, U256::from(85_700));
|
|
}
|
|
|
|
#[test]
|
|
fn storage_metering() {
|
|
::ethcore_logger::init_log();
|
|
|
|
// #1
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let code = Arc::new(load_sample!("setter.wasm"));
|
|
let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.address = address.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(code.clone());
|
|
params.data = Some(vec![
|
|
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
|
|
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
|
|
]);
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
|
};
|
|
|
|
// 0 -> not 0
|
|
assert_eq!(gas_left, U256::from(72_164));
|
|
|
|
// #2
|
|
|
|
let mut params = ActionParams::default();
|
|
params.address = address.clone();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(code.clone());
|
|
params.data = Some(vec![
|
|
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
|
|
0x6b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
|
|
]);
|
|
|
|
let gas_left = {
|
|
let mut interpreter = wasm_interpreter();
|
|
test_finalize(interpreter.exec(params, &mut ext)).unwrap()
|
|
};
|
|
|
|
// not 0 -> not 0
|
|
assert_eq!(gas_left, U256::from(87_164));
|
|
}
|
|
|
|
// This test checks the ability of wasm contract to invoke
|
|
// varios blockchain runtime methods
|
|
#[test]
|
|
fn externs() {
|
|
let (gas_left, result) = reqrep_test!(
|
|
"externs.wasm",
|
|
Vec::new(),
|
|
vm::EnvInfo {
|
|
number: 0x9999999999u64.into(),
|
|
author: "efefefefefefefefefefefefefefefefefefefef".parse().unwrap(),
|
|
timestamp: 0x8888888888u64.into(),
|
|
difficulty: H256::from("0f1f2f3f4f5f6f7f8f9fafbfcfdfefff0d1d2d3d4d5d6d7d8d9dadbdcdddedfd").into(),
|
|
gas_limit: 0x777777777777u64.into(),
|
|
last_hashes: Default::default(),
|
|
gas_used: 0.into(),
|
|
},
|
|
{
|
|
let mut hashes = HashMap::new();
|
|
hashes.insert(
|
|
U256::from(0),
|
|
H256::from("9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d")
|
|
);
|
|
hashes.insert(
|
|
U256::from(1),
|
|
H256::from("7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b")
|
|
);
|
|
hashes
|
|
}
|
|
).expect("Interpreter to execute without any errors");
|
|
|
|
assert_eq!(
|
|
&result[0..64].to_vec(),
|
|
&vec![
|
|
0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
|
|
0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,0x7b, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
|
|
],
|
|
"Block hashes requested and returned do not match"
|
|
);
|
|
|
|
assert_eq!(
|
|
&result[64..84].to_vec(),
|
|
&vec![
|
|
0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
|
|
],
|
|
"Coinbase requested and returned does not match"
|
|
);
|
|
|
|
assert_eq!(
|
|
&result[84..92].to_vec(),
|
|
&vec![
|
|
0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00
|
|
],
|
|
"Timestamp requested and returned does not match"
|
|
);
|
|
|
|
assert_eq!(
|
|
&result[92..100].to_vec(),
|
|
&vec![
|
|
0x99, 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00
|
|
],
|
|
"Block number requested and returned does not match"
|
|
);
|
|
|
|
assert_eq!(
|
|
&result[100..132].to_vec(),
|
|
&vec![
|
|
0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
|
|
0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
|
|
0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
|
|
0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
|
|
],
|
|
"Difficulty requested and returned does not match"
|
|
);
|
|
|
|
assert_eq!(
|
|
&result[132..164].to_vec(),
|
|
&vec![
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
|
|
],
|
|
"Gas limit requested and returned does not match"
|
|
);
|
|
|
|
assert_eq!(gas_left, U256::from(90_428));
|
|
}
|
|
|
|
// This test checks the ability of wasm contract to invoke gasleft
|
|
#[test]
|
|
fn gasleft() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(load_sample!("gasleft.wasm")));
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
ext.schedule.wasm.as_mut().unwrap().have_gasleft = true;
|
|
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => {},
|
|
GasLeft::NeedsReturn { gas_left, data, .. } => {
|
|
let gas = LittleEndian::read_u64(data.as_ref());
|
|
assert_eq!(gas, 93_423);
|
|
assert_eq!(gas_left, U256::from(93_349));
|
|
},
|
|
}
|
|
}
|
|
|
|
// This test should fail because
|
|
// ext.schedule.wasm.as_mut().unwrap().have_gasleft = false;
|
|
#[test]
|
|
fn gasleft_fail() {
|
|
::ethcore_logger::init_log();
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(load_sample!("gasleft.wasm")));
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
let mut interpreter = wasm_interpreter();
|
|
match interpreter.exec(params, &mut ext) {
|
|
Err(_) => {},
|
|
Ok(_) => panic!("interpreter.exec should return Err if ext.schedule.wasm.have_gasleft = false")
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn embedded_keccak() {
|
|
::ethcore_logger::init_log();
|
|
let mut code = load_sample!("keccak.wasm");
|
|
code.extend_from_slice(b"something");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.params_type = vm::ParamsType::Embedded;
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("keccak should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
|
assert_eq!(gas_left, U256::from(85_949));
|
|
}
|
|
|
|
/// This test checks the correctness of log extern
|
|
/// Target test puts one event with two topic [keccak(input), reverse(keccak(input))]
|
|
/// and reversed input as a data
|
|
#[test]
|
|
fn events() {
|
|
::ethcore_logger::init_log();
|
|
let code = load_sample!("events.wasm");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some(b"something".to_vec());
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let (gas_left, result) = {
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
|
match result {
|
|
GasLeft::Known(_) => { panic!("events should return payload"); },
|
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
|
}
|
|
};
|
|
|
|
assert_eq!(ext.logs.len(), 1);
|
|
let log_entry = &ext.logs[0];
|
|
assert_eq!(log_entry.topics.len(), 2);
|
|
assert_eq!(&log_entry.topics[0], &H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
|
assert_eq!(&log_entry.topics[1], &H256::from("871d5ea37430753faab7dff7a7187783517d83bd822c02e28a164c887e1d3768"));
|
|
assert_eq!(&log_entry.data, b"gnihtemos");
|
|
|
|
assert_eq!(&result, b"gnihtemos");
|
|
assert_eq!(gas_left, U256::from(83_161));
|
|
}
|
|
|
|
#[test]
|
|
fn recursive() {
|
|
::ethcore_logger::init_log();
|
|
let code = load_sample!("recursive.wasm");
|
|
|
|
let mut params = ActionParams::default();
|
|
params.gas = U256::from(100_000_000);
|
|
params.code = Some(Arc::new(code));
|
|
params.data = Some({
|
|
// `recursive` expects only one 32-bit word in LE that
|
|
// represents an iteration count.
|
|
//
|
|
// We pick a relative big number to definitely hit stack overflow.
|
|
use byteorder::WriteBytesExt;
|
|
let mut data = vec![];
|
|
data.write_u32::<LittleEndian>(100000).unwrap();
|
|
data
|
|
});
|
|
|
|
let mut ext = FakeExt::new().with_wasm();
|
|
|
|
let mut interpreter = wasm_interpreter();
|
|
let result = interpreter.exec(params, &mut ext);
|
|
|
|
// We expect that stack overflow will occur and it should be generated by
|
|
// deterministic stack metering. Exceeding deterministic stack height limit
|
|
// always ends with a trap generated by `unreachable` instruction.
|
|
match result {
|
|
Err(trap) => {
|
|
let err_description = trap.to_string();
|
|
assert!(
|
|
err_description.contains("Unreachable"),
|
|
"err_description: {} should contain 'Unreachable'",
|
|
err_description
|
|
);
|
|
},
|
|
_ => panic!("this test should trap"),
|
|
}
|
|
}
|