diff --git a/Cargo.lock b/Cargo.lock index e7bc9cb2f..4a0b2c4e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -554,7 +554,6 @@ dependencies = [ "ethcore-network 1.9.0", "ethcore-transaction 0.1.0", "ethereum-types 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "evm 0.1.0", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "hashdb 0.1.1", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 7db4fd20e..140f1620a 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -33,7 +33,7 @@ impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. #[cfg(feature = "jit")] - pub fn create(&self, gas: U256) -> Box { + pub fn create(&self, gas: &U256) -> Box { match self.evm { VMType::Jit => { Box::new(super::jit::JitEvm::default()) @@ -49,7 +49,7 @@ impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. #[cfg(not(feature = "jit"))] - pub fn create(&self, gas: U256) -> Box { + pub fn create(&self, gas: &U256) -> Box { match self.evm { VMType::Interpreter => if Self::can_fit_in_usize(gas) { Box::new(super::interpreter::Interpreter::::new(self.evm_cache.clone())) @@ -68,8 +68,8 @@ impl Factory { } } - fn can_fit_in_usize(gas: U256) -> bool { - gas == U256::from(gas.low_u64() as usize) + fn can_fit_in_usize(gas: &U256) -> bool { + gas == &U256::from(gas.low_u64() as usize) } } @@ -95,7 +95,7 @@ impl Default for Factory { #[test] fn test_create_vm() { - let _vm = Factory::default().create(U256::zero()); + let _vm = Factory::default().create(&U256::zero()); } /// Create tests by injecting different VM factories diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 32d9dbee5..05d1fb788 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -913,8 +913,13 @@ mod tests { use rustc_hex::FromHex; use vmtype::VMType; use factory::Factory; - use vm::{ActionParams, ActionValue}; + use vm::{Vm, ActionParams, ActionValue}; use vm::tests::{FakeExt, test_finalize}; + use ethereum_types::U256; + + fn interpreter(gas: &U256) -> Box { + Factory::new(VMType::Interpreter, 1).create(gas) + } #[test] fn should_not_fail_on_tracing_mem() { @@ -931,7 +936,7 @@ mod tests { ext.tracing = true; let gas_left = { - let mut vm = Factory::new(VMType::Interpreter, 1).create(params.gas); + let mut vm = interpreter(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -953,7 +958,7 @@ mod tests { ext.tracing = true; let err = { - let mut vm = Factory::new(VMType::Interpreter, 1).create(params.gas); + let mut vm = interpreter(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).err().unwrap() }; diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index 1eafb8d0e..a219ae988 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -38,7 +38,7 @@ fn test_add(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -58,7 +58,7 @@ fn test_sha3(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -78,7 +78,7 @@ fn test_address(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -100,7 +100,7 @@ fn test_origin(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -122,7 +122,7 @@ fn test_sender(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -157,7 +157,7 @@ fn test_extcodecopy(factory: super::Factory) { ext.codes.insert(sender, Arc::new(sender_code)); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -177,7 +177,7 @@ fn test_log_empty(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -209,7 +209,7 @@ fn test_log_sender(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -234,7 +234,7 @@ fn test_blockhash(factory: super::Factory) { ext.blockhashes.insert(U256::zero(), blockhash.clone()); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -256,7 +256,7 @@ fn test_calldataload(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -277,7 +277,7 @@ fn test_author(factory: super::Factory) { ext.info.author = author; let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -297,7 +297,7 @@ fn test_timestamp(factory: super::Factory) { ext.info.timestamp = timestamp; let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -317,7 +317,7 @@ fn test_number(factory: super::Factory) { ext.info.number = number; let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -337,7 +337,7 @@ fn test_difficulty(factory: super::Factory) { ext.info.difficulty = difficulty; let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -357,7 +357,7 @@ fn test_gas_limit(factory: super::Factory) { ext.info.gas_limit = gas_limit; let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -375,7 +375,7 @@ fn test_mul(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -393,7 +393,7 @@ fn test_sub(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -411,7 +411,7 @@ fn test_div(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -429,7 +429,7 @@ fn test_div_zero(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -447,7 +447,7 @@ fn test_mod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -466,7 +466,7 @@ fn test_smod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -485,7 +485,7 @@ fn test_sdiv(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -504,7 +504,7 @@ fn test_exp(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -524,7 +524,7 @@ fn test_comparison(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -545,7 +545,7 @@ fn test_signed_comparison(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -566,7 +566,7 @@ fn test_bitops(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -589,7 +589,7 @@ fn test_addmod_mulmod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -610,7 +610,7 @@ fn test_byte(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -629,7 +629,7 @@ fn test_signextend(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -649,7 +649,7 @@ fn test_badinstruction_int() { let mut ext = FakeExt::new(); let err = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap_err() }; @@ -669,7 +669,7 @@ fn test_pop(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -689,7 +689,7 @@ fn test_extops(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -712,7 +712,7 @@ fn test_jumps(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -740,7 +740,7 @@ fn test_calls(factory: super::Factory) { }; let gas_left = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap() }; @@ -779,7 +779,7 @@ fn test_create_in_staticcall(factory: super::Factory) { ext.is_static = true; let err = { - let mut vm = factory.create(params.gas); + let mut vm = factory.create(¶ms.gas); test_finalize(vm.exec(params, &mut ext)).unwrap_err() }; diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index 0aea8d3bf..0a5572fc4 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -16,7 +16,6 @@ memorydb = { path = "../../util/memorydb" } patricia-trie = { path = "../../util/patricia_trie" } ethcore-network = { path = "../../util/network" } ethcore-io = { path = "../../util/io" } -evm = { path = "../evm" } hashdb = { path = "../../util/hashdb" } heapsize = "0.4" vm = { path = "../vm" } diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index c6ea7826a..0e73969be 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -60,7 +60,6 @@ extern crate ethcore_bytes as bytes; extern crate ethcore_transaction as transaction; extern crate ethereum_types; extern crate ethcore; -extern crate evm; extern crate hashdb; extern crate heapsize; extern crate futures; diff --git a/ethcore/res/ethereum/kovan_wasm_test.json b/ethcore/res/ethereum/kovan_wasm_test.json new file mode 100644 index 000000000..9be03a769 --- /dev/null +++ b/ethcore/res/ethereum/kovan_wasm_test.json @@ -0,0 +1,74 @@ +{ + "name": "Kovan (Test)", + "dataDir": "kovan-test", + "engine": { + "authorityRound": { + "params": { + "stepDuration": "4", + "blockReward": "0x4563918244F40000", + "validators" : { + "list": [ + "0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED", + "0x00427feae2419c15b89d1c21af10d1b6650a4d3d", + "0x4Ed9B08e6354C70fE6F8CB0411b0d3246b424d6c", + "0x0020ee4Be0e2027d76603cB751eE069519bA81A1", + "0x0010f94b296a852aaac52ea6c5ac72e03afd032d", + "0x007733a1FE69CF3f2CF989F81C7b4cAc1693387A", + "0x00E6d2b931F55a3f1701c7389d592a7778897879", + "0x00e4a10650e5a6D6001C38ff8E64F97016a1645c", + "0x00a0a24b9f0e5ec7aa4c7389b8302fd0123194de" + ] + }, + "validateScoreTransition": 1000000, + "validateStepTransition": 1500000, + "maximumUncleCountTransition": 5067000, + "maximumUncleCount": 0 + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x400", + "registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x2A", + "forkBlock": 4297256, + "forkCanonHash": "0x0a66d93c2f727dca618fabaf70c39b37018c73d78b939d8b11efbbd09034778f", + "validateReceiptsTransition" : 1000000, + "eip155Transition": 1000000, + "validateChainIdTransition": 1000000, + "eip140Transition": 5067000, + "eip211Transition": 5067000, + "eip214Transition": 5067000, + "eip658Transition": 5067000, + "wasmActivationTransition": 10 + }, + "genesis": { + "seal": { + "authorityRound": { + "step": "0x0", + "signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x20000", + "gasLimit": "0x5B8D80" + }, + "accounts": { + "0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0x0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 5067000, "pricing": { "modexp": { "divisor": 20 } } } }, + "0x0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 5067000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0x0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 5067000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 5067000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, + "0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" } + }, + "nodes": [ + "enode://56abaf065581a5985b8c5f4f88bd202526482761ba10be9bfdcd14846dd01f652ec33fde0f8c0fd1db19b59a4c04465681fcef50e11380ca88d25996191c52de@40.71.221.215:30303", + "enode://d07827483dc47b368eaf88454fb04b41b7452cf454e194e2bd4c14f98a3278fed5d819dbecd0d010407fc7688d941ee1e58d4f9c6354d3da3be92f55c17d7ce3@52.166.117.77:30303", + "enode://8fa162563a8e5a05eef3e1cd5abc5828c71344f7277bb788a395cce4a0e30baf2b34b92fe0b2dbbba2313ee40236bae2aab3c9811941b9f5a7e8e90aaa27ecba@52.165.239.18:30303", + "enode://7e2e7f00784f516939f94e22bdc6cf96153603ca2b5df1c7cc0f90a38e7a2f218ffb1c05b156835e8b49086d11fdd1b3e2965be16baa55204167aa9bf536a4d9@52.243.47.56:30303", + "enode://0518a3d35d4a7b3e8c433e7ffd2355d84a1304ceb5ef349787b556197f0c87fad09daed760635b97d52179d645d3e6d16a37d2cc0a9945c2ddf585684beb39ac@40.68.248.100:30303" + ] +} diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ca2901aac..0245238ce 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -46,9 +46,9 @@ use encoded; use engines::{EthEngine, EpochTransition}; use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use vm::{EnvInfo, LastHashes}; -use evm::{Factory as EvmFactory, Schedule}; +use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; -use factory::Factories; +use factory::{Factories, VmFactory}; use header::{BlockNumber, Header, Seal}; use io::*; use log_entry::LocalizedLogEntry; @@ -186,7 +186,7 @@ impl Client { let trie_factory = TrieFactory::new(trie_spec); let factories = Factories { - vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size), + vm: VmFactory::new(config.vm_type.clone(), config.jump_table_size), trie: trie_factory, accountdb: Default::default(), }; @@ -1912,7 +1912,7 @@ impl MiningBlockChainClient for Client { block } - fn vm_factory(&self) -> &EvmFactory { + fn vm_factory(&self) -> &VmFactory { &self.factories.vm } diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index 00f2af816..c6cd54c7f 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -19,12 +19,11 @@ use std::fmt; use std::sync::Arc; use ethereum_types::{H256, U256}; -use journaldb; -use {trie, kvdb_memorydb, bytes}; +use {factory, journaldb, trie, kvdb_memorydb, bytes}; use kvdb::{self, KeyValueDB}; use {state, state_db, client, executive, trace, transaction, db, spec, pod_state}; use factory::Factories; -use evm::{self, VMType, FinalizationResult}; +use evm::{VMType, FinalizationResult}; use vm::{self, ActionParams}; /// EVM test Error. @@ -119,7 +118,7 @@ impl<'a> EvmTestClient<'a> { fn factories() -> Factories { Factories { - vm: evm::Factory::new(VMType::Interpreter, 5 * 1024), + vm: factory::VmFactory::new(VMType::Interpreter, 5 * 1024), trie: trie::TrieFactory::new(trie::TrieSpec::Secure), accountdb: Default::default(), } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index f1561f3e6..b80d005b5 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -45,7 +45,8 @@ use filter::Filter; use log_entry::LocalizedLogEntry; use receipt::{Receipt, LocalizedReceipt, TransactionOutcome}; use error::{ImportResult, Error as EthcoreError}; -use evm::{Factory as EvmFactory, VMType}; +use evm::VMType; +use factory::VmFactory; use vm::Schedule; use miner::{Miner, MinerService}; use spec::Spec; @@ -96,7 +97,7 @@ pub struct TestBlockChainClient { /// Spec pub spec: Spec, /// VM Factory - pub vm_factory: EvmFactory, + pub vm_factory: VmFactory, /// Timestamp assigned to latest sealed block pub latest_block_timestamp: RwLock, /// Ancient block info. @@ -167,7 +168,7 @@ impl TestBlockChainClient { queue_size: AtomicUsize::new(0), miner: Arc::new(Miner::with_spec(&spec)), spec: spec, - vm_factory: EvmFactory::new(VMType::Interpreter, 1024 * 1024), + vm_factory: VmFactory::new(VMType::Interpreter, 1024 * 1024), latest_block_timestamp: RwLock::new(10_000_000), ancient_block: RwLock::new(None), first_block: RwLock::new(None), @@ -394,7 +395,7 @@ impl MiningBlockChainClient for TestBlockChainClient { block.reopen(&*self.spec.engine) } - fn vm_factory(&self) -> &EvmFactory { + fn vm_factory(&self) -> &VmFactory { &self.vm_factory } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index eecf23a4b..1c623fd05 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -22,7 +22,8 @@ use blockchain::TreeRoute; use encoded; use vm::LastHashes; use error::{ImportResult, CallError, Error as EthcoreError, BlockImportError}; -use evm::{Factory as EvmFactory, Schedule}; +use evm::Schedule; +use factory::VmFactory; use executive::Executed; use filter::Filter; use header::{BlockNumber}; @@ -298,7 +299,7 @@ pub trait MiningBlockChainClient: BlockChainClient { fn reopen_block(&self, block: ClosedBlock) -> OpenBlock; /// Returns EvmFactory. - fn vm_factory(&self) -> &EvmFactory; + fn vm_factory(&self) -> &VmFactory; /// Broadcast a block proposal. fn broadcast_proposal_block(&self, block: SealedBlock); diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 7964c55a4..05d3e1c83 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -385,11 +385,6 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> { self.machine().verify_transaction_basic(t, header) } - /// If this machine supports wasm. - fn supports_wasm(&self) -> bool { - self.machine().supports_wasm() - } - /// Additional information. fn additional_params(&self) -> HashMap { self.machine().additional_params() diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 169c45751..03a7a1ad1 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -132,6 +132,9 @@ pub fn new_constantinople_test_machine() -> EthereumMachine { load_machine(inclu /// Create a new Musicoin-MCIP3-era spec. pub fn new_mcip3_test_machine() -> EthereumMachine { load_machine(include_bytes!("../../res/ethereum/mcip3_test.json")) } +/// Create new Kovan spec with wasm activated at certain block +pub fn new_kovan_wasm_test_machine() -> EthereumMachine { load_machine(include_bytes!("../../res/ethereum/kovan_wasm_test.json")) } + #[cfg(test)] mod tests { use ethereum_types::U256; diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 231f7b416..c8b27576f 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -22,11 +22,12 @@ use ethereum_types::{H256, U256, U512, Address}; use bytes::{Bytes, BytesRef}; use state::{Backend as StateBackend, State, Substate, CleanupMode}; use machine::EthereumMachine as Machine; -use vm::EnvInfo; use error::ExecutionError; -use evm::{CallType, Factory, Finalize, FinalizationResult}; -use vm::{self, Ext, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue}; -use wasm; +use evm::{CallType, Finalize, FinalizationResult}; +use vm::{ + self, Ext, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, + ActionValue, Schedule, +}; use externalities::*; use trace::{self, Tracer, VMTracer}; use transaction::{Action, SignedTransaction}; @@ -38,8 +39,6 @@ pub use executed::{Executed, ExecutionResult}; /// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp` const STACK_SIZE_PER_DEPTH: usize = 24*1024; -const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm"; - /// Returns new address created from address, nonce, and code hash pub fn contract_address(address_scheme: CreateContractAddress, sender: &Address, nonce: &U256, code: &[u8]) -> (Address, Option) { use rlp::RlpStream; @@ -152,14 +151,6 @@ impl TransactOptions { } } -pub fn executor(machine: &Machine, vm_factory: &Factory, params: &ActionParams) -> Box { - if machine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { - Box::new(wasm::WasmInterpreter) - } else { - vm_factory.create(params.gas) - } -} - /// Transaction executor. pub struct Executive<'a, B: 'a + StateBackend> { state: &'a mut State, @@ -334,6 +325,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { fn exec_vm( &mut self, + schedule: Schedule, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy, @@ -349,19 +341,20 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let vm_factory = self.state.vm_factory(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); - return executor(self.machine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext); + let mut vm = vm_factory.create(¶ms, &schedule); + return vm.exec(params, &mut ext).finalize(ext); } // Start in new thread to reset stack // TODO [todr] No thread builder yet, so we need to reset once for a while // https://github.com/aturon/crossbeam/issues/16 crossbeam::scope(|scope| { - let machine = self.machine; let vm_factory = self.state.vm_factory(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); scope.spawn(move || { - executor(machine, &vm_factory, ¶ms).exec(params, &mut ext).finalize(ext) + let mut vm = vm_factory.create(¶ms, &schedule); + vm.exec(params, &mut ext).finalize(ext) }) }).join() } @@ -471,7 +464,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is conditional on params.code.is_some(); qed")); let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) + self.exec_vm(schedule, params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) }; vm_tracer.done_subtrace(subvmtracer); @@ -562,9 +555,14 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed")); - let res = { - self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), &mut subtracer, &mut subvmtracer) - }; + let res = self.exec_vm( + schedule, + params, + &mut unconfirmed_substate, + OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), + &mut subtracer, + &mut subvmtracer + ); vm_tracer.done_subtrace(subvmtracer); @@ -1481,8 +1479,6 @@ mod tests { params.gas = U256::from(20025); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::zero()); - let mut state = get_temp_state_with_factory(factory); - state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = ::ethereum::new_byzantium_test_machine(); let mut substate = Substate::new(); @@ -1497,4 +1493,60 @@ mod tests { assert_eq!(output[..], returns[..]); assert_eq!(state.storage_at(&contract_address, &H256::from(&U256::zero())).unwrap(), H256::from(&U256::from(0))); } + + fn wasm_sample_code() -> Arc> { + Arc::new( + "0061736d01000000010d0360027f7f0060017f0060000002270303656e7603726574000003656e760673656e646572000103656e76066d656d6f727902010110030201020404017000000501000708010463616c6c00020901000ac10101be0102057f017e4100410028020441c0006b22043602042004412c6a41106a220041003602002004412c6a41086a22014200370200200441186a41106a22024100360200200441186a41086a220342003703002004420037022c2004410036021c20044100360218200441186a1001200020022802002202360200200120032903002205370200200441106a2002360200200441086a200537030020042004290318220537022c200420053703002004411410004100200441c0006a3602040b0b0a010041040b0410c00000" + .from_hex() + .unwrap() + ) + } + + #[test] + fn wasm_activated_test() { + let contract_address = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); + + let mut state = get_temp_state(); + state.add_balance(&sender, &U256::from(10000000000u64), CleanupMode::NoEmpty).unwrap(); + state.commit().unwrap(); + + let mut params = ActionParams::default(); + params.origin = sender.clone(); + params.sender = sender.clone(); + params.address = contract_address.clone(); + params.gas = U256::from(20025); + params.code = Some(wasm_sample_code()); + + let mut info = EnvInfo::default(); + + // 100 > 10 + info.number = 100; + + // Network with wasm activated at block 10 + let machine = ::ethereum::new_kovan_wasm_test_machine(); + + let mut output = [0u8; 20]; + let FinalizationResult { gas_left: result, .. } = { + let mut ex = Executive::new(&mut state, &info, &machine); + ex.call(params.clone(), &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() + }; + + assert_eq!(result, U256::from(18433)); + // Transaction successfully returned sender + assert_eq!(output[..], sender[..]); + + // 1 < 10 + info.number = 1; + + let mut output = [0u8; 20]; + let FinalizationResult { gas_left: result, .. } = { + let mut ex = Executive::new(&mut state, &info, &machine); + ex.call(params, &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() + }; + + assert_eq!(result, U256::from(20025)); + // Since transaction errored due to wasm was not activated, result is just empty + assert_eq!(output[..], [0u8; 20][..]); + } } diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index e9edfa3bd..68a15f164 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -15,14 +15,44 @@ // along with Parity. If not, see . use trie::TrieFactory; -use evm::Factory as EvmFactory; use account_db::Factory as AccountFactory; +use evm::{Factory as EvmFactory, VMType}; +use vm::{Vm, ActionParams, Schedule}; +use wasm::WasmInterpreter; + +const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm"; + +/// Virtual machine factory +#[derive(Default, Clone)] +pub struct VmFactory { + evm: EvmFactory, +} + +impl VmFactory { + pub fn create(&self, params: &ActionParams, schedule: &Schedule) -> Box { + if schedule.wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { + Box::new(WasmInterpreter) + } else { + self.evm.create(¶ms.gas) + } + } + + pub fn new(evm: VMType, cache_size: usize) -> Self { + VmFactory { evm: EvmFactory::new(evm, cache_size) } + } +} + +impl From for VmFactory { + fn from(evm: EvmFactory) -> Self { + VmFactory { evm: evm } + } +} /// Collection of factories. #[derive(Default, Clone)] pub struct Factories { /// factory for evm. - pub vm: EvmFactory, + pub vm: VmFactory, /// factory for tries. pub trie: TrieFactory, /// factory for account databases. diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index a962ca04f..4a6309cac 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -259,7 +259,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec { &mut tracer, &mut vm_tracer, )); - let mut evm = vm_factory.create(params.gas); + let mut evm = vm_factory.create(¶ms, &machine.schedule(0u64.into())); let res = evm.exec(params, &mut ex); // a return in finalize will not alter callcreates let callcreates = ex.callcreates.clone(); diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 62b9a13b4..fe7d964ef 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -376,11 +376,6 @@ impl EthereumMachine { Ok(()) } - /// If this machine supports wasm. - pub fn supports_wasm(&self) -> bool { - self.params().wasm - } - /// Additional params. pub fn additional_params(&self) -> HashMap { hash_map![ diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 92e35de54..ba9e578db 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -109,8 +109,8 @@ pub struct CommonParams { pub nonce_cap_increment: u64, /// Enable dust cleanup for contracts. pub remove_dust_contracts: bool, - /// Wasm support - pub wasm: bool, + /// Wasm activation blocknumber, if any disabled initially. + pub wasm_activation_transition: BlockNumber, /// Gas limit bound divisor (how much gas limit can change per block) pub gas_limit_bound_divisor: U256, /// Registrar contract address. @@ -146,6 +146,9 @@ impl CommonParams { false => ::vm::CleanDustMode::BasicOnly, }; } + if block_number >= self.wasm_activation_transition { + schedule.wasm = Some(Default::default()); + } } /// Whether these params contain any bug-fix hard forks. @@ -220,12 +223,15 @@ impl From for CommonParams { ), nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into), remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false), - wasm: p.wasm.unwrap_or(false), gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), registrar: p.registrar.map_or_else(Address::new, Into::into), node_permission_contract: p.node_permission_contract.map(Into::into), max_code_size: p.max_code_size.map_or(u64::max_value(), Into::into), transaction_permission_contract: p.transaction_permission_contract.map(Into::into), + wasm_activation_transition: p.wasm_activation_transition.map_or( + BlockNumber::max_value(), + Into::into + ), } } } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index a6de903dd..1b868c97b 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -40,7 +40,7 @@ use executed::{Executed, ExecutionError}; use types::state_diff::StateDiff; use transaction::SignedTransaction; use state_db::StateDB; -use evm::{Factory as EvmFactory}; +use factory::VmFactory; use ethereum_types::{H256, U256, Address}; use hashdb::{HashDB, AsHashDB}; @@ -376,7 +376,7 @@ impl State { } /// Get a VM factory that can execute on this state. - pub fn vm_factory(&self) -> EvmFactory { + pub fn vm_factory(&self) -> VmFactory { self.factories.vm.clone() } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 9a88b0b3d..b23245b61 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -275,7 +275,7 @@ pub fn get_temp_state() -> State<::state_db::StateDB> { pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::StateDB> { let journal_db = get_temp_state_db(); let mut factories = Factories::default(); - factories.vm = factory; + factories.vm = factory.into(); State::new(journal_db, U256::from(0), factories) } diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs index 368bcdedc..67fc59bab 100644 --- a/ethcore/vm/src/lib.rs +++ b/ethcore/vm/src/lib.rs @@ -37,7 +37,7 @@ pub mod tests; pub use action_params::{ActionParams, ActionValue, ParamsType}; pub use call_type::CallType; pub use env_info::{EnvInfo, LastHashes}; -pub use schedule::{Schedule, CleanDustMode}; +pub use schedule::{Schedule, CleanDustMode, WasmCosts}; pub use ext::{Ext, MessageCallResult, ContractCreateResult, CreateContractAddress}; pub use return_data::{ReturnData, GasLeft}; pub use error::{Error, Result}; diff --git a/ethcore/vm/src/schedule.rs b/ethcore/vm/src/schedule.rs index 11a049dfc..cc184825c 100644 --- a/ethcore/vm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -113,8 +113,8 @@ pub struct Schedule { pub kill_dust: CleanDustMode, /// Enable EIP-86 rules pub eip86: bool, - /// Wasm extra schedule settings - pub wasm: WasmCosts, + /// Wasm extra schedule settings, if wasm activated + pub wasm: Option, } /// Wasm cost table @@ -231,7 +231,7 @@ impl Schedule { have_static_call: false, kill_dust: CleanDustMode::Off, eip86: false, - wasm: Default::default(), + wasm: None, } } @@ -294,9 +294,17 @@ impl Schedule { have_static_call: false, kill_dust: CleanDustMode::Off, eip86: false, - wasm: Default::default(), + wasm: None, } } + + /// Returns wasm schedule + /// + /// May panic if there is no wasm schedule + pub fn wasm(&self) -> &WasmCosts { + // *** Prefer PANIC here instead of silently breaking consensus! *** + self.wasm.as_ref().expect("Wasm schedule expected to exist while checking wasm contract. Misconfigured client?") + } } impl Default for Schedule { diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index f141a0f96..ce4712145 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -76,15 +76,23 @@ pub fn test_finalize(res: Result) -> Result { } impl FakeExt { + /// New fake externalities pub fn new() -> Self { FakeExt::default() } + /// New fake externalities with byzantium schedule rules pub fn new_byzantium() -> Self { let mut ext = FakeExt::default(); ext.schedule = Schedule::new_byzantium(); ext } + + /// Alter fake externalities to allow wasm + pub fn with_wasm(mut self) -> Self { + self.schedule.wasm = Some(Default::default()); + self + } } impl Ext for FakeExt { diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index a0ba29f48..322a59132 100644 --- a/ethcore/wasm/src/lib.rs +++ b/ethcore/wasm/src/lib.rs @@ -68,7 +68,7 @@ impl From for vm::Error { impl vm::Vm for WasmInterpreter { fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result { - let (module, data) = parser::payload(¶ms, ext.schedule())?; + let (module, data) = parser::payload(¶ms, ext.schedule().wasm())?; let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error)?; @@ -79,8 +79,8 @@ impl vm::Vm for WasmInterpreter { &wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolover) ).map_err(Error)?; - let adjusted_gas = params.gas * U256::from(ext.schedule().wasm.opcodes_div) / - U256::from(ext.schedule().wasm.opcodes_mul); + let adjusted_gas = params.gas * U256::from(ext.schedule().wasm().opcodes_div) / + U256::from(ext.schedule().wasm().opcodes_mul); if adjusted_gas > ::std::u64::MAX.into() { @@ -111,8 +111,8 @@ impl vm::Vm for WasmInterpreter { // total_charge <- static_region * 2^32 * 2^16 // total_charge ∈ [0..2^64) if static_region ∈ [0..2^16) // qed - assert!(runtime.schedule().wasm.initial_mem < 1 << 16); - runtime.charge(|s| initial_memory as u64 * s.wasm.initial_mem as u64)?; + assert!(runtime.schedule().wasm().initial_mem < 1 << 16); + runtime.charge(|s| initial_memory as u64 * s.wasm().initial_mem as u64)?; let module_instance = module_instance.run_start(&mut runtime).map_err(Error)?; @@ -148,8 +148,8 @@ impl vm::Vm for WasmInterpreter { }; let gas_left = - U256::from(gas_left) * U256::from(ext.schedule().wasm.opcodes_mul) - / U256::from(ext.schedule().wasm.opcodes_div); + U256::from(gas_left) * U256::from(ext.schedule().wasm().opcodes_mul) + / U256::from(ext.schedule().wasm().opcodes_div); if result.is_empty() { trace!(target: "wasm", "Contract execution result is empty."); diff --git a/ethcore/wasm/src/parser.rs b/ethcore/wasm/src/parser.rs index 13e055529..8ba7a7098 100644 --- a/ethcore/wasm/src/parser.rs +++ b/ethcore/wasm/src/parser.rs @@ -21,21 +21,21 @@ use wasm_utils::{self, rules}; use parity_wasm::elements::{self, Deserialize}; use parity_wasm::peek_size; -fn gas_rules(schedule: &vm::Schedule) -> rules::Set { +fn gas_rules(wasm_costs: &vm::WasmCosts) -> rules::Set { rules::Set::new({ let mut vals = ::std::collections::HashMap::with_capacity(4); - vals.insert(rules::InstructionType::Load, schedule.wasm.mem as u32); - vals.insert(rules::InstructionType::Store, schedule.wasm.mem as u32); - vals.insert(rules::InstructionType::Div, schedule.wasm.div as u32); - vals.insert(rules::InstructionType::Mul, schedule.wasm.mul as u32); + vals.insert(rules::InstructionType::Load, wasm_costs.mem as u32); + vals.insert(rules::InstructionType::Store, wasm_costs.mem as u32); + vals.insert(rules::InstructionType::Div, wasm_costs.div as u32); + vals.insert(rules::InstructionType::Mul, wasm_costs.mul as u32); vals - }).with_grow_cost(schedule.wasm.grow_mem) + }).with_grow_cost(wasm_costs.grow_mem) } /// Splits payload to code and data according to params.params_type, also /// loads the module instance from payload and injects gas counter according /// to schedule. -pub fn payload<'a>(params: &'a vm::ActionParams, schedule: &vm::Schedule) +pub fn payload<'a>(params: &'a vm::ActionParams, wasm_costs: &vm::WasmCosts) -> Result<(elements::Module, &'a [u8]), vm::Error> { let code = match params.code { @@ -70,7 +70,7 @@ pub fn payload<'a>(params: &'a vm::ActionParams, schedule: &vm::Schedule) let contract_module = wasm_utils::inject_gas_counter( deserialized_module, - &gas_rules(schedule), + &gas_rules(wasm_costs), ); let data = match params.params_type { diff --git a/ethcore/wasm/src/runtime.rs b/ethcore/wasm/src/runtime.rs index 3bec3479f..adac12089 100644 --- a/ethcore/wasm/src/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -168,7 +168,7 @@ impl<'a> Runtime<'a> { pub fn adjusted_charge(&mut self, f: F) -> Result<()> where F: FnOnce(&vm::Schedule) -> u64 { - self.charge(|schedule| f(schedule) * schedule.wasm.opcodes_div as u64 / schedule.wasm.opcodes_mul as u64) + self.charge(|schedule| f(schedule) * schedule.wasm().opcodes_div as u64 / schedule.wasm().opcodes_mul as u64) } /// Charge gas provided by the closure @@ -195,8 +195,8 @@ impl<'a> Runtime<'a> { { self.overflow_charge(|schedule| f(schedule) - .and_then(|x| x.checked_mul(schedule.wasm.opcodes_div as u64)) - .map(|x| x / schedule.wasm.opcodes_mul as u64) + .and_then(|x| x.checked_mul(schedule.wasm().opcodes_div as u64)) + .map(|x| x / schedule.wasm().opcodes_mul as u64) ) } @@ -373,8 +373,8 @@ impl<'a> Runtime<'a> { // todo: optimize to use memory views once it's in let payload = self.memory.get(input_ptr, input_len as usize)?; - let adjusted_gas = match gas.checked_mul(self.ext.schedule().wasm.opcodes_div as u64) - .map(|x| x / self.ext.schedule().wasm.opcodes_mul as u64) + let adjusted_gas = match gas.checked_mul(self.ext.schedule().wasm().opcodes_div as u64) + .map(|x| x / self.ext.schedule().wasm().opcodes_mul as u64) { Some(x) => x, None => { @@ -400,8 +400,8 @@ impl<'a> Runtime<'a> { vm::MessageCallResult::Success(gas_left, _) => { // cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas self.gas_counter = self.gas_counter - - gas_left.low_u64() * self.ext.schedule().wasm.opcodes_div as u64 - / self.ext.schedule().wasm.opcodes_mul as u64; + gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64 + / self.ext.schedule().wasm().opcodes_mul as u64; self.memory.set(result_ptr, &result)?; Ok(0i32.into()) @@ -409,8 +409,8 @@ impl<'a> Runtime<'a> { vm::MessageCallResult::Reverted(gas_left, _) => { // cannot overflow, before making call gas_counter was incremented with gas, and gas_left < gas self.gas_counter = self.gas_counter - - gas_left.low_u64() * self.ext.schedule().wasm.opcodes_div as u64 - / self.ext.schedule().wasm.opcodes_mul as u64; + gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64 + / self.ext.schedule().wasm().opcodes_mul as u64; self.memory.set(result_ptr, &result)?; Ok((-1i32).into()) @@ -438,14 +438,14 @@ impl<'a> Runtime<'a> { fn return_address_ptr(&mut self, ptr: u32, val: Address) -> Result<()> { - self.charge(|schedule| schedule.wasm.static_address as u64)?; + self.charge(|schedule| schedule.wasm().static_address as u64)?; self.memory.set(ptr, &*val)?; Ok(()) } fn return_u256_ptr(&mut self, ptr: u32, val: U256) -> Result<()> { let value: H256 = val.into(); - self.charge(|schedule| schedule.wasm.static_u256 as u64)?; + self.charge(|schedule| schedule.wasm().static_u256 as u64)?; self.memory.set(ptr, &*value)?; Ok(()) } @@ -485,8 +485,8 @@ impl<'a> Runtime<'a> { self.adjusted_charge(|schedule| schedule.create_data_gas as u64 * code.len() as u64)?; let gas_left: U256 = U256::from(self.gas_left()?) - * U256::from(self.ext.schedule().wasm.opcodes_mul) - / U256::from(self.ext.schedule().wasm.opcodes_div); + * U256::from(self.ext.schedule().wasm().opcodes_mul) + / U256::from(self.ext.schedule().wasm().opcodes_div); match self.ext.create(&gas_left, &endowment, &code, vm::CreateContractAddress::FromSenderAndCodeHash) { vm::ContractCreateResult::Created(address, gas_left) => { @@ -494,8 +494,8 @@ impl<'a> Runtime<'a> { self.gas_counter = self.gas_limit - // this cannot overflow, since initial gas is in [0..u64::max) range, // and gas_left cannot be bigger - gas_left.low_u64() * self.ext.schedule().wasm.opcodes_div as u64 - / self.ext.schedule().wasm.opcodes_mul as u64; + gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64 + / self.ext.schedule().wasm().opcodes_mul as u64; trace!(target: "wasm", "runtime: create contract success (@{:?})", address); Ok(0i32.into()) }, @@ -508,8 +508,8 @@ impl<'a> Runtime<'a> { self.gas_counter = self.gas_limit - // this cannot overflow, since initial gas is in [0..u64::max) range, // and gas_left cannot be bigger - gas_left.low_u64() * self.ext.schedule().wasm.opcodes_div as u64 - / self.ext.schedule().wasm.opcodes_mul as u64; + gas_left.low_u64() * self.ext.schedule().wasm().opcodes_div as u64 + / self.ext.schedule().wasm().opcodes_mul as u64; Ok((-1i32).into()) }, diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 84ef28339..af2bbe367 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -43,7 +43,7 @@ macro_rules! reqrep_test { params.code = Some(Arc::new(code)); params.data = Some($input); - let mut fake_ext = FakeExt::new(); + let mut fake_ext = FakeExt::new().with_wasm(); fake_ext.info = $info; fake_ext.blockhashes = $block_hashes; @@ -79,7 +79,7 @@ fn empty() { params.address = address.clone(); params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let gas_left = { let mut interpreter = wasm_interpreter(); @@ -108,7 +108,7 @@ fn logger() { 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(); + let mut ext = FakeExt::new().with_wasm(); let gas_left = { let mut interpreter = wasm_interpreter(); @@ -157,7 +157,7 @@ fn identity() { params.sender = sender.clone(); params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -192,7 +192,7 @@ fn dispersion() { params.data = Some(vec![ 0u8, 125, 197, 255, 19 ]); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -220,7 +220,7 @@ fn suicide_not() { params.data = Some(vec![ 0u8 ]); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -253,7 +253,7 @@ fn suicide() { args.extend(refund.to_vec()); params.data = Some(args); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let gas_left = { let mut interpreter = wasm_interpreter(); @@ -280,7 +280,7 @@ fn create() { 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(); + let mut ext = FakeExt::new().with_wasm(); let gas_left = { let mut interpreter = wasm_interpreter(); @@ -324,7 +324,7 @@ fn call_msg() { params.code = Some(Arc::new(load_sample!("call.wasm"))); params.data = Some(Vec::new()); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); ext.balances.insert(receiver.clone(), U256::from(10000000000u64)); let gas_left = { @@ -367,7 +367,7 @@ fn call_code() { params.data = Some(Vec::new()); params.value = ActionValue::transfer(1_000_000_000); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -414,7 +414,7 @@ fn call_static() { params.value = ActionValue::transfer(1_000_000_000); params.code_address = contract_address.clone(); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -454,7 +454,7 @@ fn realloc() { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.data = Some(vec![0u8]); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -476,7 +476,7 @@ fn alloc() { params.gas = U256::from(10_000_000); params.code = Some(Arc::new(code)); params.data = Some(vec![0u8]); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -502,7 +502,7 @@ fn storage_read() { let mut params = ActionParams::default(); params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); ext.store.insert("0100000000000000000000000000000000000000000000000000000000000000".into(), address.into()); let (gas_left, result) = { @@ -529,7 +529,7 @@ fn keccak() { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.data = Some(b"something".to_vec()); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -664,7 +664,7 @@ fn storage_metering() { ::ethcore_logger::init_log(); // #1 - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let code = Arc::new(load_sample!("setter.wasm")); let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap(); @@ -805,7 +805,7 @@ fn embedded_keccak() { params.code = Some(Arc::new(code)); params.params_type = vm::ParamsType::Embedded; - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); @@ -833,7 +833,7 @@ fn events() { params.code = Some(Arc::new(code)); params.data = Some(b"something".to_vec()); - let mut ext = FakeExt::new(); + let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { let mut interpreter = wasm_interpreter(); diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 8e5fd9f00..53d88255b 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -98,8 +98,6 @@ pub struct Params { pub nonce_cap_increment: Option, /// See `CommonParams` docs. pub remove_dust_contracts : Option, - /// Wasm support flag - pub wasm: Option, /// See `CommonParams` docs. #[serde(rename="gasLimitBoundDivisor")] #[serde(deserialize_with="uint::validate_non_zero")] @@ -118,6 +116,9 @@ pub struct Params { /// Transaction permission contract address. #[serde(rename="transactionPermissionContract")] pub transaction_permission_contract: Option
, + /// Wasm activation block height, if not activated from start + #[serde(rename="wasmActivationTransition")] + pub wasm_activation_transition: Option, } #[cfg(test)] @@ -137,7 +138,8 @@ mod tests { "minGasLimit": "0x1388", "accountStartNonce": "0x01", "gasLimitBoundDivisor": "0x20", - "maxCodeSize": "0x1000" + "maxCodeSize": "0x1000", + "wasmActivationTransition": "0x1010" }"#; let deserialized: Params = serde_json::from_str(s).unwrap(); @@ -149,6 +151,7 @@ mod tests { assert_eq!(deserialized.account_start_nonce, Some(Uint(U256::from(0x01)))); assert_eq!(deserialized.gas_limit_bound_divisor, Uint(U256::from(0x20))); assert_eq!(deserialized.max_code_size, Some(Uint(U256::from(0x1000)))); + assert_eq!(deserialized.wasm_activation_transition, Some(Uint(U256::from(0x1010)))); } #[test]