From 6a4408cebc870cec1d9fd77acd19a7eb89df7793 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 3 Nov 2016 22:40:43 +0100 Subject: [PATCH] Backporting to beta (#3149) * The front-end for each hard-fork, also EIP-160. * Address EIP161 a/c * Include EIP-161b * EIP-161 part d. * Fix test build. * Fix one test, add another. * Fix use of bloom & renaming. * Fixed tests * Initial groundwork for EIP-155 * Fix minor bug. * Fix all tests finally. * Rest of EIP-155. * Add tests for EIP-155 algorithm. Update transaction tests validation. * Address grumbles. * Remove unused code. * Resolve IPC issues * Fixed tests * ipc backports * Fixing random test failures (#2577) * Fix SUICIDE gas mechanism and add consensus tests. * Remove commented code. * Set Frontier hardfork block number * Transaction tests, * Fixed tests * Removed banning queue --- .gitignore | 2 + ethcore/build.rs | 4 +- ethcore/res/ethereum/classic.json | 6 +- ethcore/res/ethereum/eip150_test.json | 6 +- ethcore/res/ethereum/eip161_test.json | 47 ++++++ ethcore/res/ethereum/expanse.json | 6 +- ethcore/res/ethereum/frontier.json | 6 +- ethcore/res/ethereum/frontier_like_test.json | 6 +- ethcore/res/ethereum/frontier_test.json | 6 +- ethcore/res/ethereum/homestead_test.json | 6 +- ethcore/res/ethereum/morden.json | 6 +- ethcore/res/ethereum/olympic.json | 6 +- ethcore/res/ethereum/tests | 2 +- ethcore/res/ethereum/transition_test.json | 6 +- ethcore/src/account.rs | 10 +- ethcore/src/blockchain/blockchain.rs | 8 +- ethcore/src/client/chain_notify.rs | 6 +- ethcore/src/client/client.rs | 24 ++- ethcore/src/client/mod.rs | 8 +- ethcore/src/client/test_client.rs | 4 +- ethcore/src/client/traits.rs | 8 +- ethcore/src/engines/mod.rs | 3 + ethcore/src/error.rs | 3 + ethcore/src/ethereum/ethash.rs | 42 ++++- ethcore/src/ethereum/mod.rs | 3 + ethcore/src/evm/ext.rs | 6 + ethcore/src/evm/interpreter/gasometer.rs | 20 ++- ethcore/src/evm/schedule.rs | 18 +- ethcore/src/evm/tests.rs | 8 + ethcore/src/executive.rs | 69 +++++--- ethcore/src/externalities.rs | 12 +- ethcore/src/json_tests/chain.rs | 1 + ethcore/src/json_tests/eip161_state.rs | 51 ++++++ ethcore/src/json_tests/executive.rs | 8 + ethcore/src/json_tests/mod.rs | 1 + ethcore/src/json_tests/state.rs | 1 + ethcore/src/json_tests/transaction.rs | 9 +- ethcore/src/miner/miner.rs | 10 +- ethcore/src/miner/transaction_queue.rs | 76 ++------- ethcore/src/spec/spec.rs | 9 +- ethcore/src/state.rs | 163 ++++++++++++------- ethcore/src/state_db.rs | 4 +- ethcore/src/substate.rs | 15 ++ ethcore/src/tests/client.rs | 3 +- ethcore/src/tests/helpers.rs | 3 +- ethcore/src/tests/mod.rs | 2 + ethcore/src/types/transaction.rs | 119 +++++++++++--- ethcore/src/verification/verification.rs | 4 +- ethstore/src/dir/disk.rs | 3 +- evmbin/src/ext.rs | 8 + ipc/codegen/src/lib.rs | 38 ++++- ipc/hypervisor/src/service.rs.in | 2 +- ipc/tests/nested.rs.in | 4 +- ipc/tests/service.rs.in | 2 +- ipc/tests/with_attrs.rs.in | 2 +- json/src/spec/ethash.rs | 21 ++- json/src/spec/params.rs | 11 +- parity/cli.rs | 4 +- parity/configuration.rs | 10 +- parity/main.rs | 6 - parity/modules.rs | 4 - parity/run.rs | 4 +- rpc/src/v1/helpers/dispatch.rs | 11 +- rpc/src/v1/helpers/errors.rs | 1 + rpc/src/v1/tests/eth.rs | 2 +- rpc/src/v1/tests/helpers/sync_provider.rs | 4 +- rpc/src/v1/tests/mocked/eth.rs | 14 +- rpc/src/v1/tests/mocked/eth_signing.rs | 4 +- rpc/src/v1/tests/mocked/ethcore.rs | 3 +- rpc/src/v1/tests/mocked/net.rs | 3 +- rpc/src/v1/tests/mocked/personal.rs | 8 +- rpc/src/v1/tests/mocked/personal_signer.rs | 4 +- sync/src/api.rs | 13 +- sync/src/chain.rs | 8 +- sync/src/lib.rs | 2 +- test.sh | 4 +- 76 files changed, 732 insertions(+), 314 deletions(-) create mode 100644 ethcore/res/ethereum/eip161_test.json create mode 100644 ethcore/src/json_tests/eip161_state.rs diff --git a/.gitignore b/.gitignore index 3226ea5a2..47546d0ed 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ # Build artifacts out/ + +.vscode diff --git a/ethcore/build.rs b/ethcore/build.rs index 2e07cbc2f..5e6d14733 100644 --- a/ethcore/build.rs +++ b/ethcore/build.rs @@ -18,6 +18,6 @@ extern crate ethcore_ipc_codegen; fn main() { ethcore_ipc_codegen::derive_binary("src/types/mod.rs.in").unwrap(); - ethcore_ipc_codegen::derive_ipc("src/client/traits.rs").unwrap(); - ethcore_ipc_codegen::derive_ipc("src/client/chain_notify.rs").unwrap(); + ethcore_ipc_codegen::derive_ipc_cond("src/client/traits.rs", cfg!(feature="ipc")).unwrap(); + ethcore_ipc_codegen::derive_ipc_cond("src/client/chain_notify.rs", cfg!(feature="ipc")).unwrap(); } diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index 5d951752f..02df582f4 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -11,7 +11,11 @@ "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x118c30", - "eip150Transition": "0x2625a0" + "eip150Transition": "0x2625a0", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/eip150_test.json b/ethcore/res/ethereum/eip150_test.json index 39d4b3fe8..34ef478dc 100644 --- a/ethcore/res/ethereum/eip150_test.json +++ b/ethcore/res/ethereum/eip150_test.json @@ -10,7 +10,11 @@ "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x0", - "eip150Transition": "0x0" + "eip150Transition": "0x0", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/eip161_test.json b/ethcore/res/ethereum/eip161_test.json new file mode 100644 index 000000000..884053d2a --- /dev/null +++ b/ethcore/res/ethereum/eip161_test.json @@ -0,0 +1,47 @@ +{ + "name": "Homestead (Test)", + "engine": { + "Ethash": { + "params": { + "gasLimitBoundDivisor": "0x0400", + "minimumDifficulty": "0x020000", + "difficultyBoundDivisor": "0x0800", + "durationLimit": "0x0d", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", + "homesteadTransition": "0x0", + "eip150Transition": "0x0", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0" + } + } + }, + "params": { + "accountStartNonce": "0x00", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x1" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x0000000000000042", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x400000000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", + "gasLimit": "0x1388" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } } + } +} diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json index d2d036487..8d580b6f5 100644 --- a/ethcore/res/ethereum/expanse.json +++ b/ethcore/res/ethereum/expanse.json @@ -15,7 +15,11 @@ "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", "bombDefuseTransition": "0x30d40", - "eip150Transition": "0x7fffffffffffffff" + "eip150Transition": "0x7fffffffffffffff", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index af20ac737..26ff75528 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -130,7 +130,11 @@ "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], - "eip150Transition": "0x259518" + "eip150Transition": "0x259518", + "eip155Transition": 2642462, + "eip160Transition": 2642462, + "eip161abcTransition": 2642462, + "eip161dTransition": 2642462 } } }, diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 99a7ad712..8f41c61c8 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -130,7 +130,11 @@ "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], - "eip150Transition": "0x7fffffffffffffff" + "eip150Transition": "0x7fffffffffffffff", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index 1cb3d8cfc..0fad8f37e 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -10,7 +10,11 @@ "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x7fffffffffffffff", - "eip150Transition": "0x7fffffffffffffff" + "eip150Transition": "0x7fffffffffffffff", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index ad64ce2d5..a757a7bc6 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -10,7 +10,11 @@ "blockReward": "0x4563918244F40000", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x0", - "eip150Transition": "0x7fffffffffffffff" + "eip150Transition": "0x7fffffffffffffff", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index ff1245e08..3acc8796a 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -10,7 +10,11 @@ "blockReward": "0x4563918244F40000", "registrar": "0x8e4e9b13d4b45cb0befc93c3061b1408f67316b2", "homesteadTransition": "0x789b0", - "eip150Transition": "0x1b34d8" + "eip150Transition": "0x1b34d8", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index ebc7abd4e..655410ee1 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -10,7 +10,11 @@ "blockReward": "0x14D1120D7B160000", "registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050", "homesteadTransition": "0x7fffffffffffffff", - "eip150Transition": "0x7fffffffffffffff" + "eip150Transition": "0x7fffffffffffffff", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index 97066e40c..853333e7d 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 97066e40ccd061f727deb5cd860e4d9135aa2551 +Subproject commit 853333e7da312775fb8f32f2c2771b8578cd0d79 diff --git a/ethcore/res/ethereum/transition_test.json b/ethcore/res/ethereum/transition_test.json index c004bc2ba..aebea2b4f 100644 --- a/ethcore/res/ethereum/transition_test.json +++ b/ethcore/res/ethereum/transition_test.json @@ -130,7 +130,11 @@ "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], - "eip150Transition": "0xa" + "eip150Transition": "0xa", + "eip155Transition": "0x7fffffffffffffff", + "eip160Transition": "0x7fffffffffffffff", + "eip161abcTransition": "0x7fffffffffffffff", + "eip161dTransition": "0x7fffffffffffffff" } } }, diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index 8511a5b4b..5a98d7541 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -289,11 +289,17 @@ impl Account { pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() } /// Check if account has zero nonce, balance, no code and no storage. + /// + /// NOTE: Will panic if `!self.storage_is_clean()` pub fn is_empty(&self) -> bool { - self.storage_changes.is_empty() && + assert!(self.storage_is_clean(), "Account::is_empty() may only legally be called when storage is clean."); + self.is_null() && self.storage_root == SHA3_NULL_RLP + } + + /// Check if account has zero nonce, balance, no code. + pub fn is_null(&self) -> bool { self.balance.is_zero() && self.nonce.is_zero() && - self.storage_root == SHA3_NULL_RLP && self.code_hash == SHA3_EMPTY } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 0165ccd0f..51dc7b99b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1279,7 +1279,7 @@ mod tests { action: Action::Create, value: 100.into(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); let b1a = canon_chain @@ -1343,7 +1343,7 @@ mod tests { action: Action::Create, value: 100.into(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); let t2 = Transaction { nonce: 1.into(), @@ -1352,7 +1352,7 @@ mod tests { action: Action::Create, value: 100.into(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); let t3 = Transaction { nonce: 2.into(), @@ -1361,7 +1361,7 @@ mod tests { action: Action::Create, value: 100.into(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); let b1a = canon_chain .with_transaction(t1.clone()) diff --git a/ethcore/src/client/chain_notify.rs b/ethcore/src/client/chain_notify.rs index 1d6b51803..ee390988a 100644 --- a/ethcore/src/client/chain_notify.rs +++ b/ethcore/src/client/chain_notify.rs @@ -15,12 +15,10 @@ // along with Parity. If not, see . use util::numbers::*; -use ipc::{IpcConfig, BinaryConvertError}; -use std::collections::VecDeque; -use std::mem; +use ipc::{IpcConfig}; /// Represents what has to be handled by actor listening to chain events -#[derive(Ipc)] +#[ipc] pub trait ChainNotify : Send + Sync { /// fires when chain has new blocks fn new_blocks(&self, diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 28e5e7d7d..6a4e2efe6 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -34,7 +34,7 @@ use io::*; use views::{BlockView, HeaderView, BodyView}; use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult}; use header::BlockNumber; -use state::State; +use state::{State, CleanupMode}; use spec::Spec; use basic_types::Seal; use engines::Engine; @@ -259,6 +259,22 @@ impl Client { } } + /// The env info as of the best block. + fn latest_env_info(&self) -> EnvInfo { + let header_data = self.best_block_header(); + let view = HeaderView::new(&header_data); + + EnvInfo { + number: view.number(), + author: view.author(), + timestamp: view.timestamp(), + difficulty: view.difficulty(), + last_hashes: self.build_last_hashes(view.hash()), + gas_used: U256::default(), + gas_limit: view.gas_limit(), + } + } + fn build_last_hashes(&self, parent_hash: H256) -> Arc { { let hashes = self.last_hashes.read(); @@ -714,7 +730,7 @@ impl BlockChainClient for Client { let needed_balance = t.value + t.gas * t.gas_price; if balance < needed_balance { // give the sender a sufficient balance - state.add_balance(&sender, &(needed_balance - balance)); + state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty); } let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.vm_factory).transact(t, options)); @@ -1051,6 +1067,10 @@ impl BlockChainClient for Client { fn pending_transactions(&self) -> Vec { self.miner.pending_transactions(self.chain.best_block_number()) } + + fn signing_network_id(&self) -> Option { + self.engine.signing_network_id(&self.latest_env_info()) + } } impl MiningBlockChainClient for Client { diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 32582ddf2..df1052558 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -30,13 +30,17 @@ pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use types::trace_filter::Filter as TraceFilter; pub use executive::{Executed, Executive, TransactOptions}; pub use env_info::{LastHashes, EnvInfo}; -pub use self::chain_notify::{ChainNotify, ChainNotifyClient}; +pub use self::chain_notify::ChainNotify; +#[cfg(feature="ipc")] +pub use self::chain_notify::ChainNotifyClient; +#[cfg(feature="ipc")] +pub use self::traits::RemoteClient; pub use types::call_analytics::CallAnalytics; pub use block_import_error::BlockImportError; pub use transaction_import::TransactionImportResult; pub use transaction_import::TransactionImportError; -pub use self::traits::{BlockChainClient, MiningBlockChainClient, RemoteClient}; +pub use self::traits::{BlockChainClient, MiningBlockChainClient}; mod traits { #![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index a780037b6..5b5c06a06 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -202,7 +202,7 @@ impl TestBlockChainClient { gas_price: U256::one(), nonce: U256::zero() }; - let signed_tx = tx.sign(keypair.secret()); + let signed_tx = tx.sign(keypair.secret(), None); txs.append(&signed_tx); txs.out() }, @@ -569,4 +569,6 @@ impl BlockChainClient for TestBlockChainClient { fn pending_transactions(&self) -> Vec { self.miner.pending_transactions(self.chain_info().best_block_number) } + + fn signing_network_id(&self) -> Option { None } } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 76288cb3e..694df4498 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -37,13 +37,10 @@ use executive::Executed; use env_info::LastHashes; use types::call_analytics::CallAnalytics; use block_import_error::BlockImportError; -use std::mem; -use std::collections::VecDeque; -use ipc::{IpcConfig, BinaryConvertError}; +use ipc::{IpcConfig}; use types::blockchain_info::BlockChainInfo; use types::block_status::BlockStatus; -#[derive(Ipc)] #[ipc(client_ident="RemoteClient")] /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -215,6 +212,9 @@ pub trait BlockChainClient : Sync + Send { Err(()) } } + + /// Get the preferred network ID to sign on + fn signing_network_id(&self) -> Option { None } } /// Extended client interface used for mining diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index e7738fbaa..c00bd9b7b 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -98,6 +98,9 @@ pub trait Engine : Sync + Send { /// Verify a particular transaction is valid. fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } + /// The network ID that transactions should be signed with. + fn signing_network_id(&self, _env_info: &EnvInfo) -> Option { None } + /// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods /// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer /// methods are needed for an Engine, this may be overridden. diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 449303732..6e462d5a4 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -62,6 +62,8 @@ pub enum TransactionError { }, /// Transaction's gas limit (aka gas) is invalid. InvalidGasLimit(OutOfBounds), + /// Invalid network ID given. + InvalidNetworkId, } impl fmt::Display for TransactionError { @@ -80,6 +82,7 @@ impl fmt::Display for TransactionError { GasLimitExceeded { limit, got } => format!("Gas limit exceeded. Limit={}, Given={}", limit, got), InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err), + InvalidNetworkId => "Transaction of this network ID is not allowed on this chain.".into(), }; f.write_fmt(format_args!("Transaction error ({})", msg)) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 0e208fe4b..c3ced105b 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -17,6 +17,7 @@ use ethash::{quick_get_difficulty, EthashManager, H256 as EH256}; use common::*; use block::*; +use state::CleanupMode; use spec::CommonParams; use engines::Engine; use evm::Schedule; @@ -51,8 +52,16 @@ pub struct EthashParams { pub difficulty_hardfork_bound_divisor: U256, /// Block on which there is no additional difficulty from the exponential bomb. pub bomb_defuse_transition: u64, - /// Bad gas transition block number. + /// Number of first block where EIP-150 rules begin. pub eip150_transition: u64, + /// Number of first block where EIP-155 rules begin. + pub eip155_transition: u64, + /// Number of first block where EIP-160 rules begin. + pub eip160_transition: u64, + /// Number of first block where EIP-161.abc begin. + pub eip161abc_transition: u64, + /// Number of first block where EIP-161.d begins. + pub eip161d_transition: u64, } impl From for EthashParams { @@ -72,6 +81,10 @@ impl From for EthashParams { difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into), bomb_defuse_transition: p.bomb_defuse_transition.map_or(0x7fffffffffffffff, Into::into), eip150_transition: p.eip150_transition.map_or(0, Into::into), + eip155_transition: p.eip155_transition.map_or(0, Into::into), + eip160_transition: p.eip160_transition.map_or(0, Into::into), + eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into), + eip161d_transition: p.eip161d_transition.map_or(0x7fffffffffffffff, Into::into), } } } @@ -123,7 +136,19 @@ impl Engine for Ethash { } else if env_info.number < self.ethash_params.eip150_transition { Schedule::new_homestead() } else { - Schedule::new_homestead_gas_fix() + Schedule::new_post_eip150( + env_info.number >= self.ethash_params.eip160_transition, + env_info.number >= self.ethash_params.eip161abc_transition, + env_info.number >= self.ethash_params.eip161d_transition + ) + } + } + + fn signing_network_id(&self, env_info: &EnvInfo) -> Option { + if env_info.number >= self.ethash_params.eip155_transition && self.params().network_id < 127 { + Some(self.params().network_id as u8) + } else { + None } } @@ -158,7 +183,7 @@ impl Engine for Ethash { let mut state = block.fields_mut().state; for child in &self.ethash_params.dao_hardfork_accounts { let b = state.balance(child); - state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b); + state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b, CleanupMode::NoEmpty); } // } } @@ -171,12 +196,12 @@ impl Engine for Ethash { let fields = block.fields_mut(); // Bestow block reward - fields.state.add_balance(&fields.header.author, &(reward + reward / U256::from(32) * U256::from(fields.uncles.len()))); + fields.state.add_balance(&fields.header.author, &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())), CleanupMode::NoEmpty); // Bestow uncle rewards let current_number = fields.header.number(); for u in fields.uncles.iter() { - fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8))); + fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), CleanupMode::NoEmpty); } if let Err(e) = fields.state.commit() { warn!("Encountered error on state commit: {}", e); @@ -263,6 +288,13 @@ impl Engine for Ethash { if header.number() >= self.ethash_params.homestead_transition { try!(t.check_low_s()); } + + if let Some(n) = t.network_id() { + if header.number() < self.ethash_params.eip155_transition || n as usize != self.params().network_id { + return Err(TransactionError::InvalidNetworkId.into()) + } + } + Ok(()) } diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 8b2c99f06..f94d72d0d 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -47,6 +47,9 @@ pub fn new_homestead_test() -> Spec { Spec::load(include_bytes!("../../res/ether /// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. pub fn new_eip150_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/eip150_test.json")) } +/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. +pub fn new_eip161_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/eip161_test.json")) } + /// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. pub fn new_transition_test() -> Spec { Spec::load(include_bytes!("../../res/ethereum/transition_test.json")) } diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index 815a48d31..b6107dae7 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -52,6 +52,12 @@ pub trait Ext { /// Determine whether an account exists. fn exists(&self, address: &Address) -> bool; + /// Determine whether an account exists and is not null (zero balance/nonce, no code). + fn exists_and_not_null(&self, address: &Address) -> bool; + + /// Balance of the origin account. + fn origin_balance(&self) -> U256; + /// Returns address balance. fn balance(&self, address: &Address) -> U256; diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index 1a5c93236..bd5633e04 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -130,8 +130,13 @@ impl Gasometer { instructions::SUICIDE => { let mut gas = Gas::from(schedule.suicide_gas); + let is_value_transfer = !ext.origin_balance().is_zero(); let address = u256_to_address(stack.peek(0)); - if !ext.exists(&address) { + if ( + !schedule.no_empty && !ext.exists(&address) + ) || ( + schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address) + ) { gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into())); } @@ -174,12 +179,19 @@ impl Gasometer { ); let address = u256_to_address(stack.peek(1)); + let is_value_transfer = !stack.peek(2).is_zero(); - if instruction == instructions::CALL && !ext.exists(&address) { - gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into())); + if instruction == instructions::CALL { + if ( + !schedule.no_empty && !ext.exists(&address) + ) || ( + schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address) + ) { + gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into())); + } }; - if !stack.peek(2).is_zero() { + if is_value_transfer { gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into())); }; diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index b8de785b3..b68f6acb5 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -93,6 +93,10 @@ pub struct Schedule { /// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit. /// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS pub sub_gas_cap_divisor: Option, + /// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value. + pub no_empty: bool, + /// Kill empty accounts if touched. + pub kill_empty: bool, } impl Schedule { @@ -106,16 +110,16 @@ impl Schedule { Self::new(true, true, 53000) } - /// Schedule for the Homestead-era of the Ethereum main net. - pub fn new_homestead_gas_fix() -> Schedule { - Schedule{ + /// Schedule for the post-EIP-150-era of the Ethereum main net. + pub fn new_post_eip150(fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule { + Schedule { exceptional_failed_code_deposit: true, have_delegate_call: true, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], exp_gas: 10, - exp_byte_gas: 10, + exp_byte_gas: if fix_exp {50} else {10}, sha3_gas: 30, sha3_word_gas: 6, sload_gas: 200, @@ -146,11 +150,13 @@ impl Schedule { suicide_gas: 5000, suicide_to_new_account_cost: 25000, sub_gas_cap_divisor: Some(64), + no_empty: no_empty, + kill_empty: kill_empty, } } fn new(efcd: bool, hdc: bool, tcg: usize) -> Schedule { - Schedule{ + Schedule { exceptional_failed_code_deposit: efcd, have_delegate_call: hdc, stack_limit: 1024, @@ -188,6 +194,8 @@ impl Schedule { suicide_gas: 0, suicide_to_new_account_cost: 0, sub_gas_cap_divisor: None, + no_empty: false, + kill_empty: false, } } } diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 305b9b250..af5a9dba8 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -92,6 +92,14 @@ impl Ext for FakeExt { self.balances.contains_key(address) } + fn exists_and_not_null(&self, address: &Address) -> bool { + self.balances.get(address).map_or(false, |b| !b.is_zero()) + } + + fn origin_balance(&self) -> U256 { + unimplemented!() + } + fn balance(&self, address: &Address) -> U256 { *self.balances.get(address).unwrap() } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 99038f88d..bbae930ea 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -16,7 +16,7 @@ //! Transaction Execution environment. use common::*; -use state::*; +use state::{State, CleanupMode}; use engines::Engine; use types::executed::CallType; use evm::{self, Ext, Factory, Finalize}; @@ -252,9 +252,11 @@ impl<'a> Executive<'a> { // backup used in case of running out of gas self.state.snapshot(); + let schedule = self.engine.schedule(self.info); + // at first, transfer value to destination if let ActionValue::Transfer(val) = params.value { - self.state.transfer_balance(¶ms.sender, ¶ms.address, &val); + self.state.transfer_balance(¶ms.sender, ¶ms.address, &val, substate.to_cleanup_mode(&schedule)); } trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); @@ -360,12 +362,14 @@ impl<'a> Executive<'a> { let mut unconfirmed_substate = Substate::new(); // create contract and transfer value to it if necessary + let schedule = self.engine.schedule(self.info); + let nonce_offset = if schedule.no_empty {1} else {0}.into(); let prev_bal = self.state.balance(¶ms.address); if let ActionValue::Transfer(val) = params.value { self.state.sub_balance(¶ms.sender, &val); - self.state.new_contract(¶ms.address, val + prev_bal); + self.state.new_contract(¶ms.address, val + prev_bal, nonce_offset); } else { - self.state.new_contract(¶ms.address, prev_bal); + self.state.new_contract(¶ms.address, prev_bal, nonce_offset); } let trace_info = tracer.prepare_trace_create(¶ms); @@ -401,7 +405,7 @@ impl<'a> Executive<'a> { fn finalize( &mut self, t: &SignedTransaction, - substate: Substate, + mut substate: Substate, result: evm::Result, output: Bytes, trace: Vec, @@ -427,16 +431,32 @@ impl<'a> Executive<'a> { trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n", t.gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value); - trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, t.sender().unwrap()); - self.state.add_balance(&t.sender().unwrap(), &refund_value); + let sender = match t.sender() { + Ok(sender) => sender, + Err(e) => { + debug!(target: "executive", "attempted to finalize transaction without sender: {}", e); + return Err(ExecutionError::Internal); + } + }; + + trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender); + // Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction + self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty); trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author); - self.state.add_balance(&self.info.author, &fees_value); + self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule)); // perform suicides for address in &substate.suicides { self.state.kill_account(address); } + // perform garbage-collection + for address in &substate.garbage { + if self.state.exists(address) && !self.state.exists_and_not_null(address) { + self.state.kill_account(address); + } + } + match result { Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(_) => { @@ -499,6 +519,7 @@ mod tests { use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer}; use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer}; use types::executed::CallType; + use state::{CleanupMode}; #[test] fn test_contract_address() { @@ -520,7 +541,7 @@ mod tests { params.value = ActionValue::Transfer(U256::from(0x7)); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(0x100u64)); + state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(0); let mut substate = Substate::new(); @@ -579,7 +600,7 @@ mod tests { params.value = ActionValue::Transfer(U256::from(100)); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(100)); + state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(0); let mut substate = Substate::new(); @@ -635,7 +656,7 @@ mod tests { params.call_type = CallType::Call; let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(100)); + state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(5); let mut substate = Substate::new(); @@ -744,7 +765,7 @@ mod tests { params.value = ActionValue::Transfer(100.into()); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(100)); + state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(5); let mut substate = Substate::new(); @@ -832,7 +853,7 @@ mod tests { params.value = ActionValue::Transfer(U256::from(100)); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(100)); + state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(0); let mut substate = Substate::new(); @@ -884,7 +905,7 @@ mod tests { params.value = ActionValue::Transfer(U256::from(100)); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(100)); + state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(1024); let mut substate = Substate::new(); @@ -944,7 +965,7 @@ mod tests { let mut state = state_result.reference_mut(); state.init_code(&address_a, code_a.clone()); state.init_code(&address_b, code_b.clone()); - state.add_balance(&sender, &U256::from(100_000)); + state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(0); @@ -1017,13 +1038,13 @@ mod tests { gas: U256::from(100_000), gas_price: U256::zero(), nonce: U256::zero() - }.sign(keypair.secret()); + }.sign(keypair.secret(), None); let sender = t.sender().unwrap(); let contract = contract_address(&sender, &U256::zero()); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(18)); + state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty); let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0); @@ -1084,12 +1105,12 @@ mod tests { gas: U256::from(100_000), gas_price: U256::zero(), nonce: U256::one() - }.sign(keypair.secret()); + }.sign(keypair.secret(), None); let sender = t.sender().unwrap(); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(17)); + state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty); let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0); @@ -1117,12 +1138,12 @@ mod tests { gas: U256::from(80_001), gas_price: U256::zero(), nonce: U256::zero() - }.sign(keypair.secret()); + }.sign(keypair.secret(), None); let sender = t.sender().unwrap(); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(17)); + state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty); let mut info = EnvInfo::default(); info.gas_used = U256::from(20_000); info.gas_limit = U256::from(100_000); @@ -1152,12 +1173,12 @@ mod tests { gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::zero() - }.sign(keypair.secret()); + }.sign(keypair.secret(), None); let sender = t.sender().unwrap(); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from(100_017)); + state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty); let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0); @@ -1192,7 +1213,7 @@ mod tests { params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap()); let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); + state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty); let info = EnvInfo::default(); let engine = TestEngine::new(0); let mut substate = Substate::new(); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index d91936312..1e9f82fcb 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -113,6 +113,12 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT self.state.exists(address) } + fn exists_and_not_null(&self, address: &Address) -> bool { + self.state.exists_and_not_null(address) + } + + fn origin_balance(&self) -> U256 { self.balance(&self.origin_info.address) } + fn balance(&self, address: &Address) -> U256 { self.state.balance(address) } @@ -266,11 +272,11 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT let address = self.origin_info.address.clone(); let balance = self.balance(&address); if &address == refund_address { - // TODO [todr] To be consisted with CPP client we set balance to 0 in that case. + // TODO [todr] To be consistent with CPP client we set balance to 0 in that case. self.state.sub_balance(&address, &balance); } else { - trace!("Suiciding {} -> {} (xfer: {})", address, refund_address, balance); - self.state.transfer_balance(&address, refund_address, &balance); + trace!(target: "ext", "Suiciding {} -> {} (xfer: {})", address, refund_address, balance); + self.state.transfer_balance(&address, refund_address, &balance, self.substate.to_cleanup_mode(&self.schedule)); } self.tracer.trace_suicide(address, balance, refund_address.clone()); diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 90fcf3aca..8e811b4df 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -49,6 +49,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Homestead => ethereum::new_homestead_test(), ChainEra::Eip150 => ethereum::new_eip150_test(), + ChainEra::Eip161 => ethereum::new_eip161_test(), ChainEra::TransitionTest => ethereum::new_transition_test(), }; spec.set_genesis_state(state); diff --git a/ethcore/src/json_tests/eip161_state.rs b/ethcore/src/json_tests/eip161_state.rs new file mode 100644 index 000000000..da7997fa1 --- /dev/null +++ b/ethcore/src/json_tests/eip161_state.rs @@ -0,0 +1,51 @@ +// Copyright 2015, 2016 Ethcore (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 . + +use super::test_common::*; +use tests::helpers::*; +use super::state::json_chain_test; + +fn do_json_test(json_data: &[u8]) -> Vec { + json_chain_test(json_data, ChainEra::Eip161) +} + +declare_test!{StateTests_EIP158_stEIP158SpecificTest, "StateTests/EIP158/stEIP158SpecificTest"} +declare_test!{StateTests_EIP158_stNonZeroCallsTest, "StateTests/EIP158/stNonZeroCallsTest"} +declare_test!{StateTests_EIP158_stZeroCallsTest, "StateTests/EIP158/stZeroCallsTest"} + +declare_test!{StateTests_EIP158_EIP150_stMemExpandingEIPCalls, "StateTests/EIP158/EIP150/stMemExpandingEIPCalls"} +declare_test!{StateTests_EIP158_EIP150_stEIPSpecificTest, "StateTests/EIP158/EIP150/stEIPSpecificTest"} +declare_test!{StateTests_EIP158_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP158/EIP150/stEIPsingleCodeGasPrices"} +declare_test!{StateTests_EIP158_EIP150_stChangedTests, "StateTests/EIP158/EIP150/stChangedTests"} + +declare_test!{StateTests_EIP158_Homestead_stBoundsTest, "StateTests/EIP158/Homestead/stBoundsTest"} +declare_test!{StateTests_EIP158_Homestead_stCallCodes, "StateTests/EIP158/Homestead/stCallCodes"} +declare_test!{StateTests_EIP158_Homestead_stCallCreateCallCodeTest, "StateTests/EIP158/Homestead/stCallCreateCallCodeTest"} +declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodes, "StateTests/EIP158/Homestead/stCallDelegateCodes"} +declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodesCallCode, "StateTests/EIP158/Homestead/stCallDelegateCodesCallCode"} +declare_test!{StateTests_EIP158_Homestead_stDelegatecallTest, "StateTests/EIP158/Homestead/stDelegatecallTest"} +declare_test!{StateTests_EIP158_Homestead_stHomeSteadSpecific, "StateTests/EIP158/Homestead/stHomeSteadSpecific"} +declare_test!{StateTests_EIP158_Homestead_stInitCodeTest, "StateTests/EIP158/Homestead/stInitCodeTest"} +declare_test!{StateTests_EIP158_Homestead_stLogTests, "StateTests/EIP158/Homestead/stLogTests"} +declare_test!{heavy => StateTests_EIP158_Homestead_stMemoryTest, "StateTests/EIP158/Homestead/stMemoryTest"} +declare_test!{StateTests_EIP158_Homestead_stPreCompiledContracts, "StateTests/EIP158/Homestead/stPreCompiledContracts"} +declare_test!{heavy => StateTests_EIP158_Homestead_stQuadraticComplexityTest, "StateTests/EIP158/Homestead/stQuadraticComplexityTest"} +declare_test!{StateTests_EIP158_Homestead_stRecursiveCreate, "StateTests/EIP158/Homestead/stRecursiveCreate"} +declare_test!{StateTests_EIP158_Homestead_stRefundTest, "StateTests/EIP158/Homestead/stRefundTest"} +declare_test!{StateTests_EIP158_Homestead_stSpecialTest, "StateTests/EIP158/Homestead/stSpecialTest"} +declare_test!{StateTests_EIP158_Homestead_stSystemOperationsTest, "StateTests/EIP158/Homestead/stSystemOperationsTest"} +declare_test!{StateTests_EIP158_Homestead_stTransactionTest, "StateTests/EIP158/Homestead/stTransactionTest"} +declare_test!{StateTests_EIP158_Homestead_stWalletTest, "StateTests/EIP158/Homestead/stWalletTest"} \ No newline at end of file diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 1969483ab..a551a85b7 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -91,10 +91,18 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer { self.ext.exists(address) } + fn exists_and_not_null(&self, address: &Address) -> bool { + self.ext.exists_and_not_null(address) + } + fn balance(&self, address: &Address) -> U256 { self.ext.balance(address) } + fn origin_balance(&self) -> U256 { + self.ext.origin_balance() + } + fn blockhash(&self, number: &U256) -> H256 { self.ext.blockhash(number) } diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs index 7a5dd30d2..13d3fb5bb 100644 --- a/ethcore/src/json_tests/mod.rs +++ b/ethcore/src/json_tests/mod.rs @@ -24,4 +24,5 @@ mod chain; mod homestead_state; mod homestead_chain; mod eip150_state; +mod eip161_state; mod trie; diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index a688d5904..7dd47a1e0 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -28,6 +28,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { ChainEra::Frontier => ethereum::new_mainnet_like().engine, ChainEra::Homestead => ethereum::new_homestead_test().engine, ChainEra::Eip150 => ethereum::new_eip150_test().engine, + ChainEra::Eip161 => ethereum::new_eip161_test().engine, ChainEra::TransitionTest => ethereum::new_transition_test().engine, }; diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index 7c9a3327e..66f2989eb 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -33,17 +33,24 @@ fn do_json_test(json_data: &[u8]) -> Vec { Some(x) if x < 1_150_000 => &old_schedule, Some(_) => &new_schedule }; + let allow_network_id_of_one = number.map_or(false, |n| n > 2600000); let rlp: Vec = test.rlp.into(); let res = UntrustedRlp::new(&rlp) .as_val() .map_err(From::from) - .and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call)); + .and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_network_id_of_one)); fail_unless(test.transaction.is_none() == res.is_err()); if let (Some(tx), Some(sender)) = (test.transaction, test.sender) { let t = res.unwrap(); fail_unless(t.sender().unwrap() == sender.into()); + let is_acceptable_network_id = match t.network_id() { + None => true, + Some(1) if allow_network_id_of_one => true, + _ => false, + }; + fail_unless(is_acceptable_network_id); let data: Vec = tx.data.into(); fail_unless(t.data == data); fail_unless(t.gas_price == tx.gas_price.into()); diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 4c9b9d9b5..55c05f067 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -21,7 +21,7 @@ use util::*; use util::using_queue::{UsingQueue, GetAction}; use account_provider::AccountProvider; use views::{BlockView, HeaderView}; -use state::State; +use state::{State, CleanupMode}; use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics}; use executive::contract_address; use block::{ClosedBlock, IsBlock, Block}; @@ -544,7 +544,7 @@ impl MinerService for Miner { let needed_balance = t.value + t.gas * t.gas_price; if balance < needed_balance { // give the sender a sufficient balance - state.add_balance(&sender, &(needed_balance - balance)); + state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty); } let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, chain.vm_factory()).transact(t, options)); @@ -1069,7 +1069,7 @@ mod tests { gas: U256::from(100_000), gas_price: U256::zero(), nonce: U256::zero(), - }.sign(keypair.secret()) + }.sign(keypair.secret(), None) }; let best_block = 0; // when @@ -1099,7 +1099,7 @@ mod tests { gas: U256::from(100_000), gas_price: U256::zero(), nonce: U256::zero(), - }.sign(keypair.secret()) + }.sign(keypair.secret(), None) }; let best_block = 10; // when @@ -1127,7 +1127,7 @@ mod tests { gas: U256::from(100_000), gas_price: U256::zero(), nonce: U256::zero(), - }.sign(keypair.secret()) + }.sign(keypair.secret(), None) }; let best_block = 0; // when diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index 030e46eb1..722c1eb86 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -21,55 +21,6 @@ //! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used //! for comparison (higher gas price = higher priority). //! -//! # Usage Example -//! -//! ```rust -//! extern crate ethcore_util as util; -//! extern crate ethcore; -//! extern crate rustc_serialize; -//! -//! use util::crypto::KeyPair; -//! use util::hash::Address; -//! use util::numbers::{Uint, U256}; -//! use ethcore::miner::{TransactionQueue, AccountDetails, TransactionOrigin}; -//! use ethcore::transaction::*; -//! use rustc_serialize::hex::FromHex; -//! -//! fn main() { -//! let key = KeyPair::create().unwrap(); -//! let t1 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), -//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(10) }; -//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), -//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) }; -//! -//! let st1 = t1.sign(&key.secret()); -//! let st2 = t2.sign(&key.secret()); -//! let default_nonce = |_a: &Address| AccountDetails { -//! nonce: U256::from(10), -//! balance: U256::from(1_000_000), -//! }; -//! -//! let mut txq = TransactionQueue::default(); -//! txq.add(st2.clone(), &default_nonce, TransactionOrigin::External).unwrap(); -//! txq.add(st1.clone(), &default_nonce, TransactionOrigin::External).unwrap(); -//! -//! // Check status -//! assert_eq!(txq.status().pending, 2); -//! // Check top transactions -//! let top = txq.top_transactions(); -//! assert_eq!(top.len(), 2); -//! assert_eq!(top[0], st1); -//! assert_eq!(top[1], st2); -//! -//! // And when transaction is removed (but nonce haven't changed) -//! // it will move subsequent transactions to future -//! txq.remove_invalid(&st1.hash(), &default_nonce); -//! assert_eq!(txq.status().pending, 0); -//! assert_eq!(txq.status().future, 1); -//! assert_eq!(txq.top_transactions().len(), 0); -//! } -//! ``` -//! //! # Maintaing valid state //! //! 1. Whenever transaction is imported to queue (to queue) all other transactions from this sender are revalidated in current. It means that they are moved to future and back again (height recalculation & gap filling). @@ -1006,7 +957,7 @@ mod test { fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction { let keypair = KeyPair::create().unwrap(); - new_unsigned_tx_with_gas(default_nonce_val(), gas, gas_price).sign(keypair.secret()) + new_unsigned_tx_with_gas(default_nonce_val(), gas, gas_price).sign(keypair.secret(), None) } fn new_tx() -> SignedTransaction { @@ -1029,7 +980,7 @@ mod test { let mut tx2 = new_unsigned_tx(nonce); tx2.gas_price = 2.into(); - (tx.sign(secret), tx2.sign(secret)) + (tx.sign(secret, None), tx2.sign(secret, None)) } fn new_txs(second_nonce: U256) -> (SignedTransaction, SignedTransaction) { @@ -1044,8 +995,7 @@ mod test { tx.gas_price = tx.gas_price + gas_price; let mut tx2 = new_unsigned_tx(nonce + 1.into()); tx2.gas_price = tx2.gas_price + gas_price; - - (tx.sign(secret), tx2.sign(secret)) + (tx.sign(secret, None), tx2.sign(secret, None)) } fn new_txs_with_gas_price_diff(second_nonce: U256, gas_price: U256) -> (SignedTransaction, SignedTransaction) { @@ -1056,7 +1006,7 @@ mod test { let mut tx2 = new_unsigned_tx(nonce + second_nonce); tx2.gas_price = tx2.gas_price + gas_price; - (tx.sign(secret), tx2.sign(secret)) + (tx.sign(secret, None), tx2.sign(secret, None)) } #[test] @@ -1618,9 +1568,9 @@ mod test { let mut txq = TransactionQueue::default(); let kp = KeyPair::create().unwrap(); let secret = kp.secret(); - let tx = new_unsigned_tx(U256::from(123)).sign(secret); - let tx1 = new_unsigned_tx(U256::from(124)).sign(secret); - let tx2 = new_unsigned_tx(U256::from(125)).sign(secret); + let tx = new_unsigned_tx(U256::from(123)).sign(secret, None); + let tx1 = new_unsigned_tx(U256::from(124)).sign(secret, None); + let tx2 = new_unsigned_tx(U256::from(125)).sign(secret, None); txq.add(tx, &default_nonce, TransactionOrigin::External).unwrap(); assert_eq!(txq.status().pending, 1); @@ -1876,11 +1826,11 @@ mod test { // given let mut txq = TransactionQueue::default(); let keypair = KeyPair::create().unwrap(); - let tx = new_unsigned_tx(U256::from(123)).sign(keypair.secret()); + let tx = new_unsigned_tx(U256::from(123)).sign(keypair.secret(), None); let tx2 = { let mut tx2 = (*tx).clone(); tx2.gas_price = U256::from(200); - tx2.sign(keypair.secret()) + tx2.sign(keypair.secret(), None) }; // when @@ -1899,16 +1849,16 @@ mod test { // given let mut txq = TransactionQueue::default(); let keypair = KeyPair::create().unwrap(); - let tx0 = new_unsigned_tx(U256::from(123)).sign(keypair.secret()); + let tx0 = new_unsigned_tx(U256::from(123)).sign(keypair.secret(), None); let tx1 = { let mut tx1 = (*tx0).clone(); tx1.nonce = U256::from(124); - tx1.sign(keypair.secret()) + tx1.sign(keypair.secret(), None) }; let tx2 = { let mut tx2 = (*tx1).clone(); tx2.gas_price = U256::from(200); - tx2.sign(keypair.secret()) + tx2.sign(keypair.secret(), None) }; // when @@ -2061,7 +2011,7 @@ mod test { let tx3 = new_unsigned_tx(nonce + 2.into()); - (tx.sign(secret), tx2.sign(secret), tx2_2.sign(secret), tx3.sign(secret)) + (tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None)) }; let sender = tx1.sender().unwrap(); txq.add(tx1, &default_nonce, TransactionOrigin::Local).unwrap(); diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index ea2ffa142..7a802c55b 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -37,7 +37,9 @@ pub struct CommonParams { /// Maximum size of extra data. pub maximum_extra_data_size: usize, /// Network id. - pub network_id: U256, + pub network_id: usize, + /// Main subprotocol name. + pub subprotocol_name: String, /// Minimum gas limit. pub min_gas_limit: U256, /// Fork block to check. @@ -50,6 +52,7 @@ impl From for CommonParams { account_start_nonce: p.account_start_nonce.into(), maximum_extra_data_size: p.maximum_extra_data_size.into(), network_id: p.network_id.into(), + subprotocol_name: p.subprotocol_name.unwrap_or_else(|| "eth".to_owned()), min_gas_limit: p.min_gas_limit.into(), fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None }, } @@ -155,7 +158,7 @@ impl Spec { pub fn nodes(&self) -> &[String] { &self.nodes } /// Get the configured Network ID. - pub fn network_id(&self) -> U256 { self.params.network_id } + pub fn network_id(&self) -> usize { self.params.network_id } /// Get the configured network fork block. pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params.fork_block } @@ -240,7 +243,7 @@ impl Spec { } } for (address, account) in self.genesis_state.get().iter() { - db.note_account_bloom(address); + db.note_non_null_account(address); account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address)); } assert!(db.as_hashdb().contains(&self.state_root())); diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 9f64cb032..d9e0ff473 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -191,6 +191,13 @@ enum RequireCache { Code, } +#[derive(PartialEq)] +pub enum CleanupMode<'a> { + ForceCreate, + NoEmpty, + KillEmpty(&'a mut HashSet
), +} + const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \ Therefore creating a SecTrieDB with this state's root will not fail."; @@ -324,8 +331,8 @@ impl State { /// Create a new contract at address `contract`. If there is already an account at the address /// it will have its code reset, ready for `init_code()`. - pub fn new_contract(&mut self, contract: &Address, balance: U256) { - self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce)))); + pub fn new_contract(&mut self, contract: &Address, balance: U256, nonce_offset: U256) { + self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce + nonce_offset)))); } /// Remove an existing account. @@ -336,10 +343,15 @@ impl State { /// Determine whether an account exists. pub fn exists(&self, a: &Address) -> bool { // Bloom filter does not contain empty accounts, so it is important here to - // check if account exists in the database directly before EIP-158 is in effect. + // check if account exists in the database directly before EIP-161 is in effect. self.ensure_cached(a, RequireCache::None, false, |a| a.is_some()) } + /// Determine whether an account exists and if not empty. + pub fn exists_and_not_null(&self, a: &Address) -> bool { + self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null())) + } + /// Get the balance of account `a`. pub fn balance(&self, a: &Address) -> U256 { self.ensure_cached(a, RequireCache::None, true, @@ -391,8 +403,10 @@ impl State { } } } - // account is not found in the global cache, get from the DB and insert into local - if !self.db.check_account_bloom(address) { return H256::zero() } + + // check bloom before any requests to trie + if !self.db.check_non_null_bloom(address) { return H256::zero() } + let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let maybe_acc = match db.get(address) { Ok(acc) => acc.map(Account::from_rlp), @@ -421,10 +435,18 @@ impl State { } /// Add `incr` to the balance of account `a`. - pub fn add_balance(&mut self, a: &Address, incr: &U256) { + pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) { trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)); - if !incr.is_zero() || !self.exists(a) { + let is_value_transfer = !incr.is_zero(); + if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)) { self.require(a, false).add_balance(incr); + } else { + match cleanup_mode { + CleanupMode::KillEmpty(set) => if !is_value_transfer && self.exists(a) && !self.exists_and_not_null(a) { + set.insert(a.clone()); + }, + _ => {} + } } } @@ -437,9 +459,9 @@ impl State { } /// Subtracts `by` from the balance of `from` and adds it to that of `to`. - pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256) { + pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, cleanup_mode: CleanupMode) { self.sub_balance(from, by); - self.add_balance(to, by); + self.add_balance(to, by, cleanup_mode); } /// Increment the nonce of account `a` by 1. @@ -492,16 +514,16 @@ impl State { ) -> Result<(), Error> { // first, commit the sub trees. for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) { - match a.account { - Some(ref mut account) => { - if !account.is_empty() { - db.note_account_bloom(&address); - } - let mut account_db = AccountDBMut::from_hash(db.as_hashdb_mut(), account.address_hash(address)); + if let Some(ref mut account) = a.account { + let addr_hash = account.address_hash(address); + { + let mut account_db = AccountDBMut::from_hash(db.as_hashdb_mut(), addr_hash); account.commit_storage(trie_factory, &mut account_db); account.commit_code(&mut account_db); } - _ => {} + if !account.is_empty() { + db.note_non_null_account(address); + } } } @@ -625,7 +647,9 @@ impl State { Some(r) => r, None => { // first check bloom if it is not in database for sure - if check_bloom && !self.db.check_account_bloom(a) { return f(None); } + if check_bloom && !self.db.check_non_null_bloom(a) { return f(None); } + + // not found in the global cache, get from the DB and insert into local let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let mut maybe_acc = match db.get(a) { Ok(acc) => acc.map(Account::from_rlp), @@ -656,14 +680,13 @@ impl State { match self.db.get_cached_account(a) { Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)), None => { - let maybe_acc = if self.db.check_account_bloom(a) { + let maybe_acc = if self.db.check_non_null_bloom(a) { let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); - let maybe_acc = match db.get(a) { - Ok(Some(acc)) => AccountEntry::new_clean(Some(Account::from_rlp(acc))), + match db.get(a) { + Ok(Some(acc)) => AccountEntry::new_clean(Some(Account::from_rlp(&acc))), Ok(None) => AccountEntry::new_clean(None), Err(e) => panic!("Potential DB corruption encountered: {}", e), - }; - maybe_acc + } } else { AccountEntry::new_clean(None) @@ -761,9 +784,9 @@ fn should_apply_create_transaction() { action: Action::Create, value: 100.into(), data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -822,9 +845,9 @@ fn should_trace_failed_create_transaction() { action: Action::Create, value: 100.into(), data: FromHex::from_hex("5b600056").unwrap(), - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -860,10 +883,10 @@ fn should_trace_call_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -904,9 +927,9 @@ fn should_trace_basic_call_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -947,7 +970,7 @@ fn should_trace_call_transaction_to_builtin() { action: Action::Call(0x1.into()), value: 0.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); let vm_factory = Default::default(); let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap(); @@ -990,7 +1013,7 @@ fn should_not_trace_subcall_transaction_to_builtin() { action: Action::Call(0xa.into()), value: 0.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); let vm_factory = Default::default(); @@ -1034,7 +1057,7 @@ fn should_not_trace_callcode() { action: Action::Call(0xa.into()), value: 0.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); @@ -1097,7 +1120,7 @@ fn should_not_trace_delegatecall() { action: Action::Call(0xa.into()), value: 0.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); @@ -1157,10 +1180,10 @@ fn should_trace_failed_call_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -1198,11 +1221,11 @@ fn should_trace_call_with_subcall_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); @@ -1259,10 +1282,10 @@ fn should_trace_call_with_basic_subcall_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -1315,10 +1338,10 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -1359,11 +1382,11 @@ fn should_trace_failed_subcall_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![],//600480600b6000396000f35b600056 - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -1416,12 +1439,12 @@ fn should_trace_call_with_subcall_with_subcall_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -1492,12 +1515,12 @@ fn should_trace_failed_subcall_with_subcall_transaction() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![],//600480600b6000396000f35b600056 - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); @@ -1566,11 +1589,11 @@ fn should_trace_suicide() { action: Action::Call(0xa.into()), value: 100.into(), data: vec![], - }.sign(&"".sha3()); + }.sign(&"".sha3(), None); state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap()); - state.add_balance(&0xa.into(), &50.into()); - state.add_balance(t.sender().as_ref().unwrap(), &100.into()); + state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty); + state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty); let vm_factory = Default::default(); let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { @@ -1642,7 +1665,7 @@ fn get_from_database() { let (root, db) = { let mut state = get_temp_state_in(temp.as_path()); state.inc_nonce(&a); - state.add_balance(&a, &U256::from(69u64)); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); state.commit().unwrap(); assert_eq!(state.balance(&a), U256::from(69u64)); state.drop() @@ -1659,27 +1682,47 @@ fn remove() { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); assert_eq!(state.exists(&a), false); + assert_eq!(state.exists_and_not_null(&a), false); state.inc_nonce(&a); assert_eq!(state.exists(&a), true); + assert_eq!(state.exists_and_not_null(&a), true); assert_eq!(state.nonce(&a), U256::from(1u64)); state.kill_account(&a); assert_eq!(state.exists(&a), false); + assert_eq!(state.exists_and_not_null(&a), false); assert_eq!(state.nonce(&a), U256::from(0u64)); } #[test] -fn empty_account_exists() { +fn empty_account_is_not_created() { let a = Address::zero(); let path = RandomTempPath::new(); let db = get_temp_state_db_in(path.as_path()); let (root, db) = { let mut state = State::new(db, U256::from(0), Default::default()); - state.add_balance(&a, &U256::zero()); // create an empty account + state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account + state.commit().unwrap(); + state.drop() + }; + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert!(!state.exists(&a)); + assert!(!state.exists_and_not_null(&a)); +} + +#[test] +fn empty_account_exists_when_creation_forced() { + let a = Address::zero(); + let path = RandomTempPath::new(); + let db = get_temp_state_db_in(path.as_path()); + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account state.commit().unwrap(); state.drop() }; let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert!(state.exists(&a)); + assert!(!state.exists_and_not_null(&a)); } #[test] @@ -1717,7 +1760,7 @@ fn alter_balance() { let mut state = state_result.reference_mut(); let a = Address::zero(); let b = address_from_u64(1u64); - state.add_balance(&a, &U256::from(69u64)); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); assert_eq!(state.balance(&a), U256::from(69u64)); state.commit().unwrap(); assert_eq!(state.balance(&a), U256::from(69u64)); @@ -1725,7 +1768,7 @@ fn alter_balance() { assert_eq!(state.balance(&a), U256::from(27u64)); state.commit().unwrap(); assert_eq!(state.balance(&a), U256::from(27u64)); - state.transfer_balance(&a, &b, &U256::from(18u64)); + state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty); assert_eq!(state.balance(&a), U256::from(9u64)); assert_eq!(state.balance(&b), U256::from(18u64)); state.commit().unwrap(); @@ -1778,12 +1821,12 @@ fn snapshot_basic() { let mut state = state_result.reference_mut(); let a = Address::zero(); state.snapshot(); - state.add_balance(&a, &U256::from(69u64)); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); assert_eq!(state.balance(&a), U256::from(69u64)); state.discard_snapshot(); assert_eq!(state.balance(&a), U256::from(69u64)); state.snapshot(); - state.add_balance(&a, &U256::from(1u64)); + state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty); assert_eq!(state.balance(&a), U256::from(70u64)); state.revert_to_snapshot(); assert_eq!(state.balance(&a), U256::from(69u64)); @@ -1796,7 +1839,7 @@ fn snapshot_nested() { let a = Address::zero(); state.snapshot(); state.snapshot(); - state.add_balance(&a, &U256::from(69u64)); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); assert_eq!(state.balance(&a), U256::from(69u64)); state.discard_snapshot(); assert_eq!(state.balance(&a), U256::from(69u64)); @@ -1819,7 +1862,7 @@ fn should_not_panic_on_state_diff_with_storage() { let a: Address = 0xa.into(); state.init_code(&a, b"abcdefg".to_vec()); - state.add_balance(&a, &256.into()); + state.add_balance(&a, &256.into(), CleanupMode::NoEmpty); state.set_storage(&a, 0xb.into(), 0xc.into()); let mut new_state = state.clone(); diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index 345b424b5..91611d784 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -137,13 +137,13 @@ impl StateDB { } } - pub fn check_account_bloom(&self, address: &Address) -> bool { + pub fn check_non_null_bloom(&self, address: &Address) -> bool { trace!(target: "account_bloom", "Check account bloom: {:?}", address); let bloom = self.account_bloom.lock(); bloom.check(address.sha3().as_slice()) } - pub fn note_account_bloom(&self, address: &Address) { + pub fn note_non_null_account(&self, address: &Address) { trace!(target: "account_bloom", "Note account bloom: {:?}", address); let mut bloom = self.account_bloom.lock(); bloom.set(address.sha3().as_slice()); diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index de703f369..28db7c84b 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -18,6 +18,8 @@ use std::collections::HashSet; use util::{Address, U256}; use log_entry::LogEntry; +use evm::Schedule; +use state::CleanupMode; /// State changes which should be applied in finalize, /// after transaction is fully executed. @@ -26,6 +28,9 @@ pub struct Substate { /// Any accounts that have suicided. pub suicides: HashSet
, + /// Any accounts that are tagged for garbage collection. + pub garbage: HashSet
, + /// Any logs. pub logs: Vec, @@ -45,10 +50,20 @@ impl Substate { /// Merge secondary substate `s` into self, accruing each element correspondingly. pub fn accrue(&mut self, s: Substate) { self.suicides.extend(s.suicides.into_iter()); + self.garbage.extend(s.garbage.into_iter()); self.logs.extend(s.logs.into_iter()); self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); } + + /// Get the cleanup mode object from this. + pub fn to_cleanup_mode(&mut self, schedule: &Schedule) -> CleanupMode { + match (schedule.no_empty, schedule.kill_empty) { + (false, _) => CleanupMode::ForceCreate, + (true, false) => CleanupMode::NoEmpty, + (true, true) => CleanupMode::KillEmpty(&mut self.garbage), + } + } } #[cfg(test)] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 58e7af005..3ce94009f 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -16,6 +16,7 @@ use io::IoChannel; use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID}; +use state::CleanupMode; use ethereum; use block::IsBlock; use tests::helpers::*; @@ -180,7 +181,7 @@ fn change_history_size() { let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected()).unwrap(); for _ in 0..20 { let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]); - b.block_mut().fields_mut().state.add_balance(&address, &5.into()); + b.block_mut().fields_mut().state.add_balance(&address, &5.into(), CleanupMode::NoEmpty); b.block_mut().fields_mut().state.commit().unwrap(); let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap(); client.import_sealed_block(b).unwrap(); // account change is in the journal overlay diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index facc8b4f6..10746f47a 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -33,6 +33,7 @@ pub enum ChainEra { Frontier, Homestead, Eip150, + Eip161, TransitionTest, } @@ -181,7 +182,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe action: Action::Create, data: vec![], value: U256::zero(), - }.sign(kp.secret()), None).unwrap(); + }.sign(kp.secret(), None), None).unwrap(); n += 1; } diff --git a/ethcore/src/tests/mod.rs b/ethcore/src/tests/mod.rs index db36a3762..8596db72c 100644 --- a/ethcore/src/tests/mod.rs +++ b/ethcore/src/tests/mod.rs @@ -16,4 +16,6 @@ pub mod helpers; mod client; + +#[cfg(feature="ipc")] mod rpc; diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index ebb82c528..fb3e36583 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -20,7 +20,7 @@ use util::numbers::*; use std::ops::Deref; use util::rlp::*; use util::sha3::*; -use util::{UtilError, CryptoError, Bytes, Signature, Secret, ec}; +use util::{UtilError, CryptoError, Bytes, Signature, Secret, Public, ec}; use std::cell::*; use error::*; use evm::Schedule; @@ -75,8 +75,8 @@ pub struct Transaction { impl Transaction { /// Append object with a without signature into RLP stream - pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { - s.begin_list(6); + pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option) { + s.begin_list(if let None = network_id { 6 } else { 9 }); s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); @@ -86,6 +86,11 @@ impl Transaction { }; s.append(&self.value); s.append(&self.data); + if let Some(n) = network_id { + s.append(&n); + s.append(&0u8); + s.append(&0u8); + } } } @@ -102,7 +107,7 @@ impl From for SignedTransaction { }, value: t.value.into(), data: t.data.into(), - }.sign(&t.secret.into()) + }.sign(&t.secret.into(), None) } } @@ -132,26 +137,27 @@ impl From for SignedTransaction { impl Transaction { /// The message hash of the transaction. - pub fn hash(&self) -> H256 { + pub fn hash(&self, network_id: Option) -> H256 { let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream); + self.rlp_append_unsigned_transaction(&mut stream, network_id); stream.out().sha3() } /// Signs the transaction as coming from `sender`. - pub fn sign(self, secret: &Secret) -> SignedTransaction { - let sig = ec::sign(secret, &self.hash()).unwrap(); - self.with_signature(sig) + pub fn sign(self, secret: &Secret, network_id: Option) -> SignedTransaction { + let sig = ec::sign(secret, &self.hash(network_id)) + .expect("data is valid and context has signing capabilities; qed"); + self.with_signature(sig, network_id) } /// Signs the transaction with signature. - pub fn with_signature(self, sig: H520) -> SignedTransaction { + pub fn with_signature(self, sig: Signature, network_id: Option) -> SignedTransaction { let (r, s, v) = sig.to_rsv(); SignedTransaction { unsigned: self, r: r, s: s, - v: v + 27, + v: v + if let Some(n) = network_id { 1 + n * 2 } else { 27 }, hash: Cell::new(None), sender: Cell::new(None), } @@ -201,7 +207,8 @@ impl Transaction { pub struct SignedTransaction { /// Plain Transaction. unsigned: Transaction, - /// The V field of the signature, either 27 or 28; helps describe the point on the curve. + /// The V field of the signature; the LS bit described which half of the curve our point falls + /// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks. v: u8, /// The R field of the signature; helps describe the point on the curve. r: U256, @@ -257,7 +264,7 @@ impl Encodable for SignedTransaction { impl SignedTransaction { /// Append object with a signature into RLP stream - pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { + fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { s.begin_list(9); s.append(&self.nonce); s.append(&self.gas_price); @@ -286,8 +293,16 @@ impl SignedTransaction { } } - /// 0 is `v` is 27, 1 if 28, and 4 otherwise. - pub fn standard_v(&self) -> u8 { match self.v { 27 => 0, 28 => 1, _ => 4 } } + /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. + pub fn standard_v(&self) -> u8 { match self.v { 0 => 4, v => (v - 1) & 1, } } + + /// The network ID, or `None` if this is a global transaction. + pub fn network_id(&self) -> Option { + match self.v { + 0 | 27 | 28 => None, + v => Some((v - 1) / 2), + } + } /// Construct a signature object from the sig. pub fn signature(&self) -> Signature { Signature::from_rsv(&From::from(&self.r), &From::from(&self.s), self.standard_v()) } @@ -303,28 +318,38 @@ impl SignedTransaction { /// Returns transaction sender. pub fn sender(&self) -> Result { - let sender = self.sender.get(); - match sender { - Some(s) => Ok(s), - None => { - let s = Address::from(try!(ec::recover(&self.signature(), &self.unsigned.hash())).sha3()); - self.sender.set(Some(s)); - Ok(s) - } - } + let sender = self.sender.get(); + match sender { + Some(s) => Ok(s), + None => { + let s = Address::from(try!(self.public_key()).sha3()); + self.sender.set(Some(s)); + Ok(s) + } + } + } + + /// Returns the public key of the sender. + pub fn public_key(&self) -> Result { + Ok(try!(ec::recover(&self.signature(), &self.unsigned.hash(self.network_id())))) } /// Do basic validation, checking for valid signature and minimum gas, // TODO: consider use in block validation. #[cfg(test)] #[cfg(feature = "json-tests")] - pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result { + pub fn validate(self, schedule: &Schedule, require_low: bool, allow_network_id_of_one: bool) -> Result { if require_low && !ec::is_low_s(&self.s) { return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))); } + match self.network_id() { + None => {}, + Some(1) if allow_network_id_of_one => {}, + _ => return Err(TransactionError::InvalidNetworkId.into()), + } try!(self.sender()); if self.gas < U256::from(self.gas_required(&schedule)) { - Err(From::from(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) + Err(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into()) } else { Ok(self) } @@ -364,6 +389,7 @@ fn sender_test() { } else { panic!(); } assert_eq!(t.value, U256::from(0x0au64)); assert_eq!(t.sender().unwrap(), address_from_hex("0f65fe9276bc9a24ae7083ae28e2660ef72df99e")); + assert_eq!(t.network_id(), None); } #[test] @@ -376,8 +402,9 @@ fn signing() { gas: U256::from(50_000), value: U256::from(1), data: b"Hello!".to_vec() - }.sign(&key.secret()); + }.sign(&key.secret(), None); assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap()); + assert_eq!(t.network_id(), None); } #[test] @@ -391,7 +418,45 @@ fn fake_signing() { data: b"Hello!".to_vec() }.fake_sign(Address::from(0x69)); assert_eq!(Address::from(0x69), t.sender().unwrap()); + assert_eq!(t.network_id(), None); let t = t.clone(); assert_eq!(Address::from(0x69), t.sender().unwrap()); + assert_eq!(t.network_id(), None); +} + +#[test] +fn should_recover_from_network_specific_signing() { + let key = ::util::crypto::KeyPair::create().unwrap(); + let t = Transaction { + action: Action::Create, + nonce: U256::from(42), + gas_price: U256::from(3000), + gas: U256::from(50_000), + value: U256::from(1), + data: b"Hello!".to_vec() + }.sign(&key.secret(), Some(69)); + assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap()); + assert_eq!(t.network_id(), Some(69)); +} + +#[test] +fn should_agree_with_vitalik() { + use rustc_serialize::hex::FromHex; + + let test_vector = |tx_data: &str, address: &'static str| { + let signed: SignedTransaction = decode(&FromHex::from_hex(tx_data).unwrap()); + assert_eq!(signed.sender().unwrap(), address.into()); + }; + + test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xda39a520355857fdb37ecb527fe814230fa9962c"); + test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc8a0c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0xd240215f30eafee2aaa5184d8f051ebb41c90b19"); + test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a0ad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a8a0ad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2f2822c55d894df1ba32961c43325dcb3d614ee8"); + test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0xc21df0434ceab6e18a1300d18206e54e807b4456"); + test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf975cee81edae2ab5883f4e2fb2a7f2fd56f4131"); + test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a0ceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a0ceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xd477474c9f48dcbfde5d97f30646242ab7a17e06"); + test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a0e455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2da0e455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xb49948deb719ca21e38d29e3360f534b39db0e76"); + test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xbddfc81a8ce87b2360837049a6eda68ab2f58999"); + test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a0e4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c11a0e4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x8f2edcf67f329a146dd4cb1e6b3a072daff85b38"); + test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a0d2f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba0d2f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x4ec38d4782fd4a6ff85c1cde77ccf1ae3c54472c"); } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 078bb72ae..80ce02aaa 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -360,7 +360,7 @@ mod tests { gas: U256::from(30_000), gas_price: U256::from(40_000), nonce: U256::one() - }.sign(keypair.secret()); + }.sign(keypair.secret(), None); let tr2 = Transaction { action: Action::Create, @@ -369,7 +369,7 @@ mod tests { gas: U256::from(30_000), gas_price: U256::from(40_000), nonce: U256::from(2) - }.sign(keypair.secret()); + }.sign(keypair.secret(), None); let good_transactions = [ tr1.clone(), tr2.clone() ]; diff --git a/ethstore/src/dir/disk.rs b/ethstore/src/dir/disk.rs index f71826acc..5efede9f2 100644 --- a/ethstore/src/dir/disk.rs +++ b/ethstore/src/dir/disk.rs @@ -162,7 +162,8 @@ mod test { #[test] fn should_create_new_account() { // given - let dir = env::temp_dir(); + let mut dir = env::temp_dir(); + dir.push("ethstore_should_create_new_account"); let keypair = Random.generate().unwrap(); let password = "hello world"; let directory = DiskDirectory::create(dir.clone()).unwrap(); diff --git a/evmbin/src/ext.rs b/evmbin/src/ext.rs index d9a6932ba..45a7bebf9 100644 --- a/evmbin/src/ext.rs +++ b/evmbin/src/ext.rs @@ -48,6 +48,14 @@ impl Ext for FakeExt { unimplemented!(); } + fn exists_and_not_null(&self, address: &Address) -> bool { + unimplemented!(); + } + + fn origin_balance(&self) -> U256 { + unimplemented!(); + } + fn balance(&self, _address: &Address) -> U256 { unimplemented!(); } diff --git a/ipc/codegen/src/lib.rs b/ipc/codegen/src/lib.rs index 8a3b4ba56..4491a6e35 100644 --- a/ipc/codegen/src/lib.rs +++ b/ipc/codegen/src/lib.rs @@ -49,7 +49,7 @@ include!(concat!(env!("OUT_DIR"), "/lib.rs")); include!("lib.rs.in"); #[cfg(feature = "with-syntex")] -pub fn register(reg: &mut syntex::Registry) { +pub fn register_cleaner(reg: &mut syntex::Registry) { use syntax::{ast, fold}; #[cfg(feature = "with-syntex")] @@ -59,6 +59,7 @@ pub fn register(reg: &mut syntex::Registry) { fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { match attr.node.value.node { ast::MetaItemKind::List(ref n, _) if n == &"ipc" => { return None; } + ast::MetaItemKind::Word(ref n) if n == &"ipc" => { return None; } _ => {} } @@ -73,19 +74,24 @@ pub fn register(reg: &mut syntex::Registry) { fold::Folder::fold_crate(&mut StripAttributeFolder, krate) } + reg.add_post_expansion_pass(strip_attributes); +} + +#[cfg(feature = "with-syntex")] +pub fn register(reg: &mut syntex::Registry) { reg.add_attr("feature(custom_derive)"); reg.add_attr("feature(custom_attribute)"); - reg.add_decorator("derive_Ipc", codegen::expand_ipc_implementation); + reg.add_decorator("ipc", codegen::expand_ipc_implementation); reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation); - reg.add_post_expansion_pass(strip_attributes); + register_cleaner(reg); } #[cfg(not(feature = "with-syntex"))] pub fn register(reg: &mut rustc_plugin::Registry) { reg.register_syntax_extension( - syntax::parse::token::intern("derive_Ipc"), + syntax::parse::token::intern("ipc"), syntax::ext::base::MultiDecorator( Box::new(codegen::expand_ipc_implementation))); reg.register_syntax_extension( @@ -133,6 +139,30 @@ pub fn derive_ipc(src_path: &str) -> Result<(), Error> { Ok(()) } +pub fn cleanup_ipc(src_path: &str) -> Result<(), Error> { + use std::env; + use std::path::{Path, PathBuf}; + let out_dir = env::var_os("OUT_DIR").unwrap(); + let file_name = try!(PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())); + let mut registry = syntex::Registry::new(); + register_cleaner(&mut registry); + if let Err(_) = registry.expand("", &Path::new(src_path), &Path::new(&out_dir).join(&file_name)) + { + // will be reported by compiler + return Err(Error::ExpandFailure) + } + Ok(()) +} + +pub fn derive_ipc_cond(src_path: &str, cond: bool) -> Result<(), Error> { + if cond { + derive_ipc(src_path) + } + else { + cleanup_ipc(src_path) + } +} + pub fn derive_binary(src_path: &str) -> Result<(), Error> { use std::env; use std::path::{Path, PathBuf}; diff --git a/ipc/hypervisor/src/service.rs.in b/ipc/hypervisor/src/service.rs.in index 208e3efcf..85e47da8f 100644 --- a/ipc/hypervisor/src/service.rs.in +++ b/ipc/hypervisor/src/service.rs.in @@ -34,7 +34,7 @@ pub struct HypervisorService { check_list: RwLock>, } -#[derive(Ipc)] +#[ipc] impl HypervisorService { fn module_ready(&self, module_id: u64) -> bool { let mut check_list = self.check_list.write().unwrap(); diff --git a/ipc/tests/nested.rs.in b/ipc/tests/nested.rs.in index 6b4b2b325..b9bbe7ea5 100644 --- a/ipc/tests/nested.rs.in +++ b/ipc/tests/nested.rs.in @@ -36,7 +36,7 @@ impl IpcConfig for DBWriter {} #[derive(Binary)] pub enum DBError { Write, Read } -#[derive(Ipc)] +#[ipc] impl DBWriter for DB { fn write(&self, data: Vec) -> Result<(), DBError> { let mut writes = self.writes.write().unwrap(); @@ -51,7 +51,7 @@ impl DBWriter for DB { } } -#[derive(Ipc)] +#[ipc] trait DBNotify { fn notify(&self, a: u64, b: u64) -> bool; } diff --git a/ipc/tests/service.rs.in b/ipc/tests/service.rs.in index ec403ce6e..99d78b4a7 100644 --- a/ipc/tests/service.rs.in +++ b/ipc/tests/service.rs.in @@ -31,7 +31,7 @@ pub struct CustomData { pub b: u64, } -#[derive(Ipc)] +#[ipc] impl Service { fn commit(&self, f: u32) -> u32 { let mut lock = self.commits.write().unwrap(); diff --git a/ipc/tests/with_attrs.rs.in b/ipc/tests/with_attrs.rs.in index 240e434c9..b6d0e5976 100644 --- a/ipc/tests/with_attrs.rs.in +++ b/ipc/tests/with_attrs.rs.in @@ -21,7 +21,7 @@ use std::collections::VecDeque; pub struct BadlyNamedService; -#[derive(Ipc)] +//#[derive(Ipc)] #[ipc(client_ident="PrettyNamedClient")] impl BadlyNamedService { fn is_zero(&self, x: u64) -> bool { diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs index 3feb45854..841debcec 100644 --- a/json/src/spec/ethash.rs +++ b/json/src/spec/ethash.rs @@ -63,6 +63,21 @@ pub struct EthashParams { /// See main EthashParams docs. #[serde(rename="eip150Transition")] pub eip150_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip155Transition")] + pub eip155_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip160Transition")] + pub eip160_transition: Option, + + /// See main EthashParams docs. + #[serde(rename="eip161abcTransition")] + pub eip161abc_transition: Option, + /// See main EthashParams docs. + #[serde(rename="eip161dTransition")] + pub eip161d_transition: Option, } /// Ethash engine deserialization. @@ -115,7 +130,11 @@ mod tests { "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", "bombDefuseTransition": "0x42", - "eip150Transition": "0x42" + "eip150Transition": "0x42", + "eip155Transition": "0x42", + "eip160Transition": "0x42", + "eip161abcTransition": "0x42", + "eip161dTransition": "0x42" } }"#; diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 6c80e11cc..afb5cb131 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -28,12 +28,17 @@ pub struct Params { /// Maximum size of extra data. #[serde(rename="maximumExtraDataSize")] pub maximum_extra_data_size: Uint, - /// Network id. - #[serde(rename="networkID")] - pub network_id: Uint, /// Minimum gas limit. #[serde(rename="minGasLimit")] pub min_gas_limit: Uint, + + /// Network id. + #[serde(rename="networkID")] + pub network_id: Uint, + /// Name of the main ("eth") subprotocol. + #[serde(rename="subprotocolName")] + pub subprotocol_name: Option, + /// Option fork block number to check. #[serde(rename="forkBlock")] pub fork_block: Option, diff --git a/parity/cli.rs b/parity/cli.rs index 62deafeb4..e4e6640bd 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -329,7 +329,7 @@ pub struct Args { pub flag_keys_iterations: u32, pub flag_no_import_keys: bool, pub flag_bootnodes: Option, - pub flag_network_id: Option, + pub flag_network_id: Option, pub flag_pruning: String, pub flag_pruning_history: u64, pub flag_tracing: String, @@ -415,7 +415,7 @@ pub struct Args { pub flag_rpccorsdomain: Option, pub flag_rpcapi: Option, pub flag_testnet: bool, - pub flag_networkid: Option, + pub flag_networkid: Option, pub flag_ipcdisable: bool, pub flag_ipc_off: bool, pub flag_jsonrpc_off: bool, diff --git a/parity/configuration.rs b/parity/configuration.rs index d5063360f..4cf457cab 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -81,7 +81,7 @@ impl Configuration { let http_conf = try!(self.http_config()); let ipc_conf = try!(self.ipc_config()); let net_conf = try!(self.net_config()); - let network_id = try!(self.network_id()); + let network_id = self.network_id(); let cache_config = self.cache_config(); let spec = try!(self.chain().parse()); let tracing = try!(self.args.flag_tracing.parse()); @@ -465,12 +465,8 @@ impl Configuration { Ok(ret) } - fn network_id(&self) -> Result, String> { - let net_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref()); - match net_id { - Some(id) => Ok(Some(try!(to_u256(id)))), - None => Ok(None), - } + fn network_id(&self) -> Option { + self.args.flag_network_id.or(self.args.flag_networkid) } fn rpc_apis(&self) -> String { diff --git a/parity/main.rs b/parity/main.rs index 454d2c16d..d4a9ea1ae 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -81,7 +81,6 @@ mod account; mod blockchain; mod presale; mod run; -mod sync; mod snapshot; use std::{process, env}; @@ -119,11 +118,6 @@ fn start() -> Result { fn main() { // Always print backtrace on panic. ::std::env::set_var("RUST_BACKTRACE", "1"); - // just redirect to the sync::main() - if std::env::args().nth(1).map_or(false, |arg| arg == "sync") { - sync::main(); - return; - } match start() { Ok(result) => { diff --git a/parity/modules.rs b/parity/modules.rs index 5ae5db231..ea584d93c 100644 --- a/parity/modules.rs +++ b/parity/modules.rs @@ -25,10 +25,6 @@ use self::ipc_deps::*; use ethcore_logger::Config as LogConfig; pub mod service_urls { - pub const CLIENT: &'static str = "ipc:///tmp/parity-chain.ipc"; - pub const SYNC: &'static str = "ipc:///tmp/parity-sync.ipc"; - pub const SYNC_NOTIFY: &'static str = "ipc:///tmp/parity-sync-notify.ipc"; - pub const NETWORK_MANAGER: &'static str = "ipc:///tmp/parity-manage-net.ipc"; } #[cfg(not(feature="ipc"))] diff --git a/parity/run.rs b/parity/run.rs index fa59d2a73..153a3f565 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -22,7 +22,7 @@ use fdlimit::raise_fd_limit; use ethcore_logger::{Config as LogConfig, setup_log}; use ethcore_rpc::NetworkSettings; use ethsync::NetworkConfiguration; -use util::{Colour, version, U256}; +use util::{Colour, version}; use io::{MayPanic, ForwardPanic, PanicHandler}; use ethcore::client::{Mode, Switch, DatabaseCompactionProfile, VMType, ChainNotify}; use ethcore::service::ClientService; @@ -60,7 +60,7 @@ pub struct RunCmd { pub http_conf: HttpConfiguration, pub ipc_conf: IpcConfiguration, pub net_conf: NetworkConfiguration, - pub network_id: Option, + pub network_id: Option, pub acc_conf: AccountsConfig, pub gas_pricer: GasPricerConfig, pub miner_extras: MinerExtras, diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index f709e59ab..af83824e2 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -62,15 +62,16 @@ pub fn signature_with_password(accounts: &AccountProvider, address: Address, has pub fn unlock_sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result where C: MiningBlockChainClient, M: MinerService { + let network_id = client.signing_network_id(); let address = request.from; let signed_transaction = { let t = prepare_transaction(client, miner, request); - let hash = t.hash(); + let hash = t.hash(network_id); let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(errors::from_password_error)); - t.with_signature(signature) + t.with_signature(signature, network_id) }; - trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); + trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", encode(&signed_transaction).to_vec().pretty(), network_id); dispatch_transaction(&*client, &*miner, signed_transaction) } @@ -79,9 +80,9 @@ pub fn sign_and_dispatch(client: &C, miner: &M, request: TransactionReques let signed_transaction = { let t = prepare_transaction(client, miner, request); - let hash = t.hash(); + let hash = t.hash(None); let signature = try!(account_provider.sign(address, hash).map_err(errors::from_signing_error)); - t.with_signature(signature) + t.with_signature(signature, None) }; trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index bb62a80e5..901a71f5c 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -170,6 +170,7 @@ pub fn from_transaction_error(error: EthcoreError) -> Error { format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) }, InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), + e => format!("{}", e).into(), }; Error { code: ErrorCode::ServerError(codes::TRANSACTION_ERROR), diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 2064be78e..f4f19c212 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -45,7 +45,7 @@ fn account_provider() -> Arc { fn sync_provider() -> Arc { Arc::new(TestSyncProvider::new(Config { - network_id: U256::from(3), + network_id: 3, num_peers: 120, })) } diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index 94f7b4893..bebf4468d 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -16,13 +16,13 @@ //! Test implementation of SyncProvider. -use util::{RwLock, U256}; +use util::{RwLock}; use ethsync::{SyncProvider, SyncStatus, SyncState}; /// TestSyncProvider config. pub struct Config { /// Protocol version. - pub network_id: U256, + pub network_id: usize, /// Number of peers. pub num_peers: usize, } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 813dc5136..27c5bc742 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -44,7 +44,7 @@ fn accounts_provider() -> Arc { fn sync_provider() -> Arc { Arc::new(TestSyncProvider::new(Config { - network_id: U256::from(3), + network_id: 3, num_peers: 120, })) } @@ -621,8 +621,8 @@ fn rpc_eth_send_transaction() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts_provider.sign(address, t.hash()).unwrap(); - let t = t.with_signature(signature); + let signature = tester.accounts_provider.sign(address, t.hash(None)).unwrap(); + let t = t.with_signature(signature, None); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; @@ -638,8 +638,8 @@ fn rpc_eth_send_transaction() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts_provider.sign(address, t.hash()).unwrap(); - let t = t.with_signature(signature); + let signature = tester.accounts_provider.sign(address, t.hash(None)).unwrap(); + let t = t.with_signature(signature, None); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; @@ -703,8 +703,8 @@ fn rpc_eth_send_raw_transaction() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts_provider.sign(address, t.hash()).unwrap(); - let t = t.with_signature(signature); + let signature = tester.accounts_provider.sign(address, t.hash(None)).unwrap(); + let t = t.with_signature(signature, None); let rlp = ::util::rlp::encode(&t).to_vec().to_hex(); diff --git a/rpc/src/v1/tests/mocked/eth_signing.rs b/rpc/src/v1/tests/mocked/eth_signing.rs index 5acc935b9..8a3a76137 100644 --- a/rpc/src/v1/tests/mocked/eth_signing.rs +++ b/rpc/src/v1/tests/mocked/eth_signing.rs @@ -233,8 +233,8 @@ fn should_dispatch_transaction_if_account_is_unlock() { value: U256::from(0x9184e72au64), data: vec![] }; - let signature = tester.accounts.sign(acc, t.hash()).unwrap(); - let t = t.with_signature(signature); + let signature = tester.accounts.sign(acc, t.hash(None)).unwrap(); + let t = t.with_signature(signature, None); // when let request = r#"{ diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index 42787e830..d0075c777 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -16,7 +16,6 @@ use std::sync::Arc; use util::log::RotatingLogger; -use util::U256; use ethsync::ManageNetwork; use ethcore::client::{TestBlockChainClient}; @@ -36,7 +35,7 @@ fn client_service() -> Arc { fn sync_provider() -> Arc { Arc::new(TestSyncProvider::new(Config { - network_id: U256::from(3), + network_id: 3, num_peers: 120, })) } diff --git a/rpc/src/v1/tests/mocked/net.rs b/rpc/src/v1/tests/mocked/net.rs index 036ced168..da42b4241 100644 --- a/rpc/src/v1/tests/mocked/net.rs +++ b/rpc/src/v1/tests/mocked/net.rs @@ -18,11 +18,10 @@ use std::sync::Arc; use jsonrpc_core::IoHandler; use v1::{Net, NetClient}; use v1::tests::helpers::{Config, TestSyncProvider}; -use util::numbers::*; fn sync_provider() -> Arc { Arc::new(TestSyncProvider::new(Config { - network_id: U256::from(3), + network_id: 3, num_peers: 120, })) } diff --git a/rpc/src/v1/tests/mocked/personal.rs b/rpc/src/v1/tests/mocked/personal.rs index 35d57967e..7d9cd1dce 100644 --- a/rpc/src/v1/tests/mocked/personal.rs +++ b/rpc/src/v1/tests/mocked/personal.rs @@ -227,8 +227,8 @@ fn sign_and_send_transaction() { data: vec![] }; tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap(); - let signature = tester.accounts.sign(address, t.hash()).unwrap(); - let t = t.with_signature(signature); + let signature = tester.accounts.sign(address, t.hash(None)).unwrap(); + let t = t.with_signature(signature, None); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; @@ -245,8 +245,8 @@ fn sign_and_send_transaction() { data: vec![] }; tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap(); - let signature = tester.accounts.sign(address, t.hash()).unwrap(); - let t = t.with_signature(signature); + let signature = tester.accounts.sign(address, t.hash(None)).unwrap(); + let t = t.with_signature(signature, None); let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; diff --git a/rpc/src/v1/tests/mocked/personal_signer.rs b/rpc/src/v1/tests/mocked/personal_signer.rs index b0d3ec735..603c619b9 100644 --- a/rpc/src/v1/tests/mocked/personal_signer.rs +++ b/rpc/src/v1/tests/mocked/personal_signer.rs @@ -186,8 +186,8 @@ fn should_confirm_transaction_and_dispatch() { data: vec![] }; tester.accounts.unlock_account_temporarily(address, "test".into()).unwrap(); - let signature = tester.accounts.sign(address, t.hash()).unwrap(); - let t = t.with_signature(signature); + let signature = tester.accounts.sign(address, t.hash(None)).unwrap(); + let t = t.with_signature(signature, None); assert_eq!(tester.queue.requests().len(), 1); diff --git a/sync/src/api.rs b/sync/src/api.rs index 655a78571..b07fa767b 100644 --- a/sync/src/api.rs +++ b/sync/src/api.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use std::collections::HashMap; use network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId, NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, NetworkError}; -use util::{U256, H256, Secret, Populatable, Bytes}; +use util::{H256, Secret, Populatable, Bytes}; use io::{TimerToken}; use ethcore::client::{BlockChainClient, ChainNotify}; use ethcore::header::BlockNumber; @@ -40,7 +40,9 @@ pub struct SyncConfig { /// Max blocks to download ahead pub max_download_ahead_blocks: usize, /// Network ID - pub network_id: U256, + pub network_id: usize, + /// Main "eth" subprotocol name. + pub subprotocol_name: [u8; 3], /// Fork block to check pub fork_block: Option<(BlockNumber, H256)>, } @@ -49,7 +51,8 @@ impl Default for SyncConfig { fn default() -> SyncConfig { SyncConfig { max_download_ahead_blocks: 20000, - network_id: U256::from(1), + network_id: 1, + subprotocol_name: *b"eth", fork_block: None, } } @@ -90,8 +93,6 @@ impl EthSync { } } -#[derive(Ipc)] -#[ipc(client_ident="SyncClient")] impl SyncProvider for EthSync { /// Get sync status fn status(&self) -> SyncStatus { @@ -185,8 +186,6 @@ pub trait ManageNetwork : Send + Sync { } -#[derive(Ipc)] -#[ipc(client_ident="NetworkManagerClient")] impl ManageNetwork for EthSync { fn accept_unreserved_peers(&self) { self.network.set_non_reserved_mode(NonReservedPeerMode::Accept); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index dd45e1d80..dda8d2a4c 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -163,7 +163,7 @@ pub struct SyncStatus { /// Syncing protocol version. That's the maximum protocol version we connect to. pub protocol_version: u8, /// The underlying p2p network version. - pub network_id: U256, + pub network_id: usize, /// `BlockChain` height for the moment the sync started. pub start_block_number: BlockNumber, /// Last fully downloaded and imported block number (if any). @@ -226,7 +226,7 @@ struct PeerInfo { /// Peer chain genesis hash genesis: H256, /// Peer network id - network_id: U256, + network_id: usize, /// Peer best block hash latest_hash: H256, /// Peer total difficulty if known @@ -285,7 +285,7 @@ pub struct ChainSync { /// Block parents imported this round (hash, parent) round_parents: VecDeque<(H256, H256)>, /// Network ID - network_id: U256, + network_id: usize, /// Optional fork block to check fork_block: Option<(BlockNumber, H256)>, } @@ -1737,7 +1737,7 @@ mod tests { PeerInfo { protocol_version: 0, genesis: H256::zero(), - network_id: U256::zero(), + network_id: 0, latest_hash: peer_latest_hash, difficulty: None, asking: PeerAsking::Nothing, diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 69dd03a2a..167715660 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -91,7 +91,7 @@ mod api { include!(concat!(env!("OUT_DIR"), "/api.rs")); } -pub use api::{EthSync, SyncProvider, SyncClient, NetworkManagerClient, ManageNetwork, SyncConfig, +pub use api::{EthSync, SyncProvider, ManageNetwork, SyncConfig, ServiceConfiguration, NetworkConfiguration}; pub use chain::{SyncStatus, SyncState}; pub use network::{is_valid_node_url, NonReservedPeerMode, NetworkError}; diff --git a/test.sh b/test.sh index 666f10d06..52882eaea 100755 --- a/test.sh +++ b/test.sh @@ -1,11 +1,11 @@ #!/bin/sh # Running Parity Full Test Sute -FEATURES="json-tests ipc" +FEATURES="json-tests" case $1 in --no-json) - FEATURES="ipc" + FEATURES="" shift # past argument=value ;; *)