diff --git a/Cargo.lock b/Cargo.lock index b900c7f23..2b3d9ccb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,6 +240,8 @@ dependencies = [ "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.2.0", "ethcore-devtools 1.2.0", + "ethcore-ipc 1.2.0", + "ethcore-ipc-codegen 1.2.0", "ethcore-util 1.2.0", "ethjson 0.1.0", "heapsize 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -248,6 +250,7 @@ dependencies = [ "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -301,7 +304,7 @@ dependencies = [ "ethsync 1.2.0", "json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", + "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git?branch=multiple_cors_domains)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -578,6 +581,16 @@ dependencies = [ "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-http-server" +version = "5.1.0" +source = "git+https://github.com/ethcore/jsonrpc-http-server.git?branch=multiple_cors_domains#9c026feeb6573c82c99c8005c5d8244de68a2e30" +dependencies = [ + "hyper 0.9.3 (git+https://github.com/ethcore/hyper)", + "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" diff --git a/devtools/src/random_path.rs b/devtools/src/random_path.rs index b037867fa..990d375e3 100644 --- a/devtools/src/random_path.rs +++ b/devtools/src/random_path.rs @@ -59,7 +59,7 @@ impl RandomTempPath { impl Drop for RandomTempPath { fn drop(&mut self) { if let Err(e) = fs::remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); + panic!("Failed to remove temp directory. Here's what prevented this from happening: ({})", e); } } } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index b5f50b207..d0b1927f6 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -5,6 +5,11 @@ license = "GPL-3.0" name = "ethcore" version = "1.2.0" authors = ["Ethcore "] +build = "build.rs" + +[build-dependencies] +syntex = "*" +"ethcore-ipc-codegen" = { path = "../ipc/codegen" } [dependencies] log = "0.3" @@ -23,6 +28,7 @@ lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } ethjson = { path = "../json" } bloomchain = "0.1" +"ethcore-ipc" = { path = "../ipc/rpc" } [features] jit = ["evmjit"] diff --git a/ethcore/build.rs b/ethcore/build.rs new file mode 100644 index 000000000..dadcce13a --- /dev/null +++ b/ethcore/build.rs @@ -0,0 +1,33 @@ +// 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 . + +extern crate syntex; +extern crate ethcore_ipc_codegen as codegen; + +use std::env; +use std::path::Path; + +fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + // serialization pass + { + let src = Path::new("src/types/mod.rs.in"); + let dst = Path::new(&out_dir).join("types.rs"); + let mut registry = syntex::Registry::new(); + codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7e5f896fd..d95152341 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -27,7 +27,7 @@ use chainfilter::{ChainFilter, BloomIndex, FilterDataSource}; use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData}; use blockchain::best_block::BestBlock; use blockchain::bloom_indexer::BloomIndexer; -use blockchain::tree_route::TreeRoute; +use types::tree_route::TreeRoute; use blockchain::update::ExtrasUpdate; use blockchain::{CacheSize, ImportRoute}; use db::{Writable, Readable, Key, CacheUpdatePolicy}; diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 29a4ee684..62196825f 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -21,7 +21,6 @@ mod best_block; mod block_info; mod bloom_indexer; mod cache; -mod tree_route; mod update; mod import_route; #[cfg(test)] @@ -29,5 +28,5 @@ mod generator; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize; -pub use self::tree_route::TreeRoute; +pub use types::tree_route::TreeRoute; pub use self::import_route::ImportRoute; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 23b81b34e..0d61325d9 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -44,34 +44,8 @@ use receipt::LocalizedReceipt; pub use blockchain::CacheSize as BlockChainCacheSize; use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Database as TraceDatabase}; use trace; - -/// General block status -#[derive(Debug, Eq, PartialEq)] -pub enum BlockStatus { - /// Part of the blockchain. - InChain, - /// Queued for import. - Queued, - /// Known as bad. - Bad, - /// Unknown. - Unknown, -} - -/// Information about the blockchain gathered together. -#[derive(Debug)] -pub struct BlockChainInfo { - /// Blockchain difficulty. - pub total_difficulty: U256, - /// Block queue difficulty. - pub pending_total_difficulty: U256, - /// Genesis block hash. - pub genesis_hash: H256, - /// Best blockchain block hash. - pub best_block_hash: H256, - /// Best blockchain block number. - pub best_block_number: BlockNumber -} +pub use types::blockchain_info::BlockChainInfo; +pub use types::block_status::BlockStatus; impl fmt::Display for BlockChainInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -424,7 +398,7 @@ impl Client where V: Verifier { } impl BlockChainClient for Client where V: Verifier { - fn call(&self, t: &SignedTransaction) -> Result { + fn call(&self, t: &SignedTransaction) -> Result { let header = self.block_header(BlockId::Latest).unwrap(); let view = HeaderView::new(&header); let last_hashes = self.build_last_hashes(view.hash()); @@ -439,7 +413,10 @@ impl BlockChainClient for Client where V: Verifier { }; // that's just a copy of the state. let mut state = self.state(); - let sender = try!(t.sender()); + let sender = try!(t.sender().map_err(|e| { + let message = format!("Transaction malformed: {:?}", e); + ExecutionError::TransactionMalformed(message) + })); let balance = state.balance(&sender); // give the sender max balance state.sub_balance(&sender, &balance); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 90dd78015..a748ff900 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -18,13 +18,12 @@ mod client; mod config; -mod ids; mod test_client; mod trace; pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig, Switch}; -pub use self::ids::{BlockId, TransactionId, UncleId, TraceId}; +pub use types::ids::*; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::trace::Filter as TraceFilter; pub use executive::{Executed, Executive, TransactOptions}; @@ -42,7 +41,7 @@ use header::{BlockNumber, Header}; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; -use error::{ImportResult, Error}; +use error::{ImportResult, ExecutionError}; use receipt::LocalizedReceipt; use engine::{Engine}; use trace::LocalizedTrace; @@ -133,7 +132,7 @@ pub trait BlockChainClient : Sync + Send { fn try_seal(&self, block: LockedBlock, seal: Vec) -> Result; /// Makes a non-persistent transaction call. - fn call(&self, t: &SignedTransaction) -> Result; + fn call(&self, t: &SignedTransaction) -> Result; /// Attempt to seal the block internally. See `Engine`. fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option> { self.engine().generate_seal(block, accounts) } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index c3df57b76..4ec993fe5 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -31,7 +31,7 @@ use error::{ImportResult}; use block_queue::BlockQueueInfo; use block::{SealedBlock, ClosedBlock, LockedBlock}; use executive::Executed; -use error::Error; +use error::{ExecutionError}; use engine::Engine; use trace::LocalizedTrace; @@ -221,7 +221,7 @@ impl TestBlockChainClient { } impl BlockChainClient for TestBlockChainClient { - fn call(&self, _t: &SignedTransaction) -> Result { + fn call(&self, _t: &SignedTransaction) -> Result { Ok(self.execution_result.read().unwrap().clone().unwrap()) } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 922d72700..edec7c959 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -20,47 +20,7 @@ use util::*; use header::BlockNumber; use basic_types::LogBloom; -/// Result of executing the transaction. -#[derive(PartialEq, Debug)] -pub enum ExecutionError { - /// Returned when there gas paid for transaction execution is - /// lower than base gas required. - NotEnoughBaseGas { - /// Absolute minimum gas required. - required: U256, - /// Gas provided. - got: U256 - }, - /// Returned when block (gas_used + gas) > gas_limit. - /// - /// If gas =< gas_limit, upstream may try to execute the transaction - /// in next block. - BlockGasLimitReached { - /// Gas limit of block for transaction. - gas_limit: U256, - /// Gas used in block prior to transaction. - gas_used: U256, - /// Amount of gas in block. - gas: U256 - }, - /// Returned when transaction nonce does not match state nonce. - InvalidNonce { - /// Nonce expected. - expected: U256, - /// Nonce found. - got: U256 - }, - /// Returned when cost of transaction (value + gas_price * gas) exceeds - /// current sender balance. - NotEnoughCash { - /// Minimum required balance. - required: U512, - /// Actual balance. - got: U512 - }, - /// Returned when internal evm error occurs. - Internal -} +pub use types::executed::ExecutionError; #[derive(Debug, PartialEq)] /// Errors concerning transaction processing. diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 4247114ef..74e0499c1 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -24,6 +24,8 @@ use substate::*; use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer}; use crossbeam; +pub use types::executed::{Executed, ExecutionResult}; + /// Max depth to avoid stack overflow (when it's reached we start a new thread with VM) /// TODO [todr] We probably need some more sophisticated calculations here (limit on my machine 132) /// Maybe something like here: `https://github.com/ethereum/libethereum/blob/4db169b8504f2b87f7d5a481819cfb959fc65f6c/libethereum/ExtVM.cpp` @@ -45,45 +47,6 @@ pub struct TransactOptions { pub check_nonce: bool, } -/// Transaction execution receipt. -#[derive(Debug, PartialEq, Clone)] -pub struct Executed { - /// Gas paid up front for execution of transaction. - pub gas: U256, - - /// Gas used during execution of transaction. - pub gas_used: U256, - - /// Gas refunded after the execution of transaction. - /// To get gas that was required up front, add `refunded` and `gas_used`. - pub refunded: U256, - - /// Cumulative gas used in current block so far. - /// - /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` - /// - /// where `tn` is current transaction. - pub cumulative_gas_used: U256, - - /// Vector of logs generated by transaction. - pub logs: Vec, - - /// Addresses of contracts created during execution of transaction. - /// Ordered from earliest creation. - /// - /// eg. sender creates contract A and A in constructor creates contract B - /// - /// B creation ends first, and it will be the first element of the vector. - pub contracts_created: Vec
, - /// Transaction output. - pub output: Bytes, - /// The trace of this transaction. - pub trace: Option, -} - -/// Transaction execution result. -pub type ExecutionResult = Result; - /// Transaction executor. pub struct Executive<'a> { state: &'a mut State, @@ -119,7 +82,7 @@ impl<'a> Executive<'a> { } /// This function should be used to execute transaction. - pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result { + pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result { let check = options.check_nonce; match options.tracing { true => self.transact_with_tracer(t, check, ExecutiveTracer::default()), @@ -128,8 +91,11 @@ impl<'a> Executive<'a> { } /// Execute transaction/call with tracing enabled - pub fn transact_with_tracer(&'a mut self, t: &SignedTransaction, check_nonce: bool, mut tracer: T) -> Result where T: Tracer { - let sender = try!(t.sender()); + pub fn transact_with_tracer(&'a mut self, t: &SignedTransaction, check_nonce: bool, mut tracer: T) -> Result where T: Tracer { + let sender = try!(t.sender().map_err(|e| { + let message = format!("Transaction malformed: {:?}", e); + ExecutionError::TransactionMalformed(message) + })); let nonce = self.state.nonce(&sender); let schedule = self.engine.schedule(self.info); @@ -983,8 +949,8 @@ mod tests { }; match res { - Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))) => (), - _ => assert!(false, "Expected invalid signature error.") + Err(ExecutionError::TransactionMalformed(_)) => (), + _ => assert!(false, "Expected an invalid transaction error.") } } @@ -1015,7 +981,7 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) + Err(ExecutionError::InvalidNonce { expected, got }) if expected == U256::zero() && got == U256::one() => (), _ => assert!(false, "Expected invalid nonce error.") } @@ -1049,7 +1015,7 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) + Err(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas }) if gas_limit == U256::from(100_000) && gas_used == U256::from(20_000) && gas == U256::from(80_001) => (), _ => assert!(false, "Expected block gas limit error.") } @@ -1083,7 +1049,7 @@ mod tests { }; match res { - Err(Error::Execution(ExecutionError::NotEnoughCash { required , got })) + Err(ExecutionError::NotEnoughCash { required , got }) if required == U512::from(100_018) && got == U512::from(100_017) => (), _ => assert!(false, "Expected not enough cash error. {:?}", res) } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 43b4c5099..0b62ec4fb 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -85,6 +85,7 @@ extern crate num_cpus; extern crate crossbeam; extern crate ethjson; extern crate bloomchain; +#[macro_use] extern crate ethcore_ipc as ipc; #[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(feature = "jit" )] extern crate evmjit; @@ -98,12 +99,9 @@ pub mod ethereum; pub mod filter; pub mod header; pub mod service; -pub mod log_entry; pub mod trace; pub mod spec; -pub mod transaction; pub mod views; -pub mod receipt; pub mod pod_state; mod db; @@ -128,9 +126,12 @@ mod executive; mod externalities; mod verification; mod blockchain; +mod types; #[cfg(test)] mod tests; #[cfg(test)] #[cfg(feature="json-tests")] mod json_tests; + +pub use types::*; diff --git a/ethcore/src/trace/flat.rs b/ethcore/src/trace/flat.rs index ae3f22050..f9d3b0831 100644 --- a/ethcore/src/trace/flat.rs +++ b/ethcore/src/trace/flat.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Flat trace module + use trace::BlockTraces; use super::trace::{Trace, Action, Res}; diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 831a55cd5..01763a167 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -21,20 +21,18 @@ mod bloom; mod config; mod db; mod executive_tracer; -mod filter; -mod flat; +pub mod flat; mod import; -mod localized; mod noop_tracer; -pub mod trace; +pub use types::trace_types::*; pub use self::block::BlockTraces; pub use self::config::{Config, Switch}; pub use self::db::TraceDB; -pub use self::trace::Trace; +pub use types::trace_types::trace::Trace; pub use self::noop_tracer::NoopTracer; pub use self::executive_tracer::ExecutiveTracer; -pub use self::filter::{Filter, AddressesFilter}; +pub use types::trace_types::filter::{Filter, AddressesFilter}; pub use self::import::ImportRequest; pub use self::localized::LocalizedTrace; use util::{Bytes, Address, U256, H256}; diff --git a/ethcore/src/types/block_status.rs b/ethcore/src/types/block_status.rs new file mode 100644 index 000000000..ca0f47227 --- /dev/null +++ b/ethcore/src/types/block_status.rs @@ -0,0 +1,33 @@ +// 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 . + +//! Block status description module + +use ipc::binary::BinaryConvertError; +use std::collections::VecDeque; + +/// General block status +#[derive(Debug, Eq, PartialEq, Binary)] +pub enum BlockStatus { + /// Part of the blockchain. + InChain, + /// Queued for import. + Queued, + /// Known as bad. + Bad, + /// Unknown. + Unknown, +} diff --git a/ethcore/src/types/blockchain_info.rs b/ethcore/src/types/blockchain_info.rs new file mode 100644 index 000000000..4e8634dba --- /dev/null +++ b/ethcore/src/types/blockchain_info.rs @@ -0,0 +1,38 @@ +// 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 . + +//! Blockhain info type definition + +use util::numbers::*; +use header::BlockNumber; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; + +/// Information about the blockchain gathered together. +#[derive(Debug, Binary)] +pub struct BlockChainInfo { + /// Blockchain difficulty. + pub total_difficulty: U256, + /// Block queue difficulty. + pub pending_total_difficulty: U256, + /// Genesis block hash. + pub genesis_hash: H256, + /// Best blockchain block hash. + pub best_block_hash: H256, + /// Best blockchain block number. + pub best_block_number: BlockNumber +} diff --git a/ethcore/src/types/executed.rs b/ethcore/src/types/executed.rs new file mode 100644 index 000000000..f03a1c26b --- /dev/null +++ b/ethcore/src/types/executed.rs @@ -0,0 +1,109 @@ +// 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 . + +//! Transaction execution format module. + +use util::numbers::*; +use util::Bytes; +use trace::Trace; +use types::log_entry::LogEntry; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; + +/// Transaction execution receipt. +#[derive(Debug, PartialEq, Clone, Binary)] +pub struct Executed { + /// Gas paid up front for execution of transaction. + pub gas: U256, + + /// Gas used during execution of transaction. + pub gas_used: U256, + + /// Gas refunded after the execution of transaction. + /// To get gas that was required up front, add `refunded` and `gas_used`. + pub refunded: U256, + + /// Cumulative gas used in current block so far. + /// + /// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)` + /// + /// where `tn` is current transaction. + pub cumulative_gas_used: U256, + + /// Vector of logs generated by transaction. + pub logs: Vec, + + /// Addresses of contracts created during execution of transaction. + /// Ordered from earliest creation. + /// + /// eg. sender creates contract A and A in constructor creates contract B + /// + /// B creation ends first, and it will be the first element of the vector. + pub contracts_created: Vec
, + /// Transaction output. + pub output: Bytes, + /// The trace of this transaction. + pub trace: Option, +} + +/// Result of executing the transaction. +#[derive(PartialEq, Debug, Binary)] +pub enum ExecutionError { + /// Returned when there gas paid for transaction execution is + /// lower than base gas required. + NotEnoughBaseGas { + /// Absolute minimum gas required. + required: U256, + /// Gas provided. + got: U256 + }, + /// Returned when block (gas_used + gas) > gas_limit. + /// + /// If gas =< gas_limit, upstream may try to execute the transaction + /// in next block. + BlockGasLimitReached { + /// Gas limit of block for transaction. + gas_limit: U256, + /// Gas used in block prior to transaction. + gas_used: U256, + /// Amount of gas in block. + gas: U256 + }, + /// Returned when transaction nonce does not match state nonce. + InvalidNonce { + /// Nonce expected. + expected: U256, + /// Nonce found. + got: U256 + }, + /// Returned when cost of transaction (value + gas_price * gas) exceeds + /// current sender balance. + NotEnoughCash { + /// Minimum required balance. + required: U512, + /// Actual balance. + got: U512 + }, + /// Returned when internal evm error occurs. + Internal, + /// Returned when generic transaction occurs + TransactionMalformed(String), +} + + +/// Transaction execution result. +pub type ExecutionResult = Result; diff --git a/ethcore/src/client/ids.rs b/ethcore/src/types/ids.rs similarity index 85% rename from ethcore/src/client/ids.rs rename to ethcore/src/types/ids.rs index 39a19c82d..8fffcb8f7 100644 --- a/ethcore/src/client/ids.rs +++ b/ethcore/src/types/ids.rs @@ -18,10 +18,13 @@ use util::hash::H256; use header::BlockNumber; -use util::bytes::{FromRawBytes, FromBytesError, ToBytesWithMap, Populatable}; +use ipc::binary::BinaryConvertError; +use ipc::binary::BinaryConvertable; +use std::mem; +use std::collections::VecDeque; /// Uniquely identifies block. -#[derive(Debug, PartialEq, Clone, Hash, Eq)] +#[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)] pub enum BlockId { /// Block's sha3. /// Querying by hash is always faster. @@ -35,7 +38,7 @@ pub enum BlockId { } /// Uniquely identifies transaction. -#[derive(Debug, PartialEq, Clone, Hash, Eq)] +#[derive(Debug, PartialEq, Clone, Hash, Eq, Binary)] pub enum TransactionId { /// Transaction's sha3. Hash(H256), @@ -53,13 +56,10 @@ pub struct TraceId { } /// Uniquely identifies Uncle. +#[derive(Debug)] pub struct UncleId ( /// Block id. pub BlockId, /// Position in block. pub usize ); - -sized_binary_map!(TransactionId); -sized_binary_map!(UncleId); -sized_binary_map!(BlockId); diff --git a/ethcore/src/log_entry.rs b/ethcore/src/types/log_entry.rs similarity index 91% rename from ethcore/src/log_entry.rs rename to ethcore/src/types/log_entry.rs index 2a7ca080f..7d8dccc6c 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/types/log_entry.rs @@ -14,15 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Block log. +//! Log entry type definition. -use util::*; +use util::numbers::*; +use std::ops::Deref; +use util::rlp::*; +use util::Bytes; +use util::HeapSizeOf; +use util::sha3::*; use basic_types::LogBloom; use header::BlockNumber; use ethjson; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// A record of execution for a `LOG` operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq, Binary)] pub struct LogEntry { /// The address of the contract executing at the point of the `LOG` operation. pub address: Address, @@ -77,7 +85,7 @@ impl From for LogEntry { } /// Log localized in a blockchain. -#[derive(Default, Debug, PartialEq, Clone)] +#[derive(Default, Debug, PartialEq, Clone, Binary)] pub struct LocalizedLogEntry { /// Plain log entry. pub entry: LogEntry, diff --git a/ethcore/src/types/mod.rs b/ethcore/src/types/mod.rs new file mode 100644 index 000000000..112f79c32 --- /dev/null +++ b/ethcore/src/types/mod.rs @@ -0,0 +1,20 @@ +// 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 . + +//! Types used in the public api + +#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues +include!(concat!(env!("OUT_DIR"), "/types.rs")); diff --git a/ethcore/src/types/mod.rs.in b/ethcore/src/types/mod.rs.in new file mode 100644 index 000000000..1f67a9184 --- /dev/null +++ b/ethcore/src/types/mod.rs.in @@ -0,0 +1,25 @@ +// 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 . + +pub mod transaction; +pub mod ids; +pub mod receipt; +pub mod tree_route; +pub mod blockchain_info; +pub mod log_entry; +pub mod trace_types; +pub mod executed; +pub mod block_status; diff --git a/ethcore/src/receipt.rs b/ethcore/src/types/receipt.rs similarity index 80% rename from ethcore/src/receipt.rs rename to ethcore/src/types/receipt.rs index 2fbd3f14c..cc83e2f97 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/types/receipt.rs @@ -16,13 +16,18 @@ //! Receipt -use util::*; +use util::numbers::*; +use util::rlp::*; +use util::HeapSizeOf; use basic_types::LogBloom; use header::BlockNumber; use log_entry::{LogEntry, LocalizedLogEntry}; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// Information describing execution of a transaction. -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Binary)] pub struct Receipt { /// The state root after executing the transaction. pub state_root: H256, @@ -76,7 +81,7 @@ impl HeapSizeOf for Receipt { } /// Receipt with additional info. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct LocalizedReceipt { /// Transaction hash. pub transaction_hash: H256, @@ -98,7 +103,7 @@ pub struct LocalizedReceipt { #[test] fn test_basic() { - let expected = FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let expected = ::rustc_serialize::hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap(); let r = Receipt::new( x!("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee"), x!(0x40cae), diff --git a/ethcore/src/trace/filter.rs b/ethcore/src/types/trace_types/filter.rs similarity index 93% rename from ethcore/src/trace/filter.rs rename to ethcore/src/types/trace_types/filter.rs index d1f699c52..c02a15c03 100644 --- a/ethcore/src/trace/filter.rs +++ b/ethcore/src/types/trace_types/filter.rs @@ -14,41 +14,49 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Trace filters type definitions + use std::ops::Range; use bloomchain::{Filter as BloomFilter, Bloom, Number}; use util::{Address, FixedHash}; use util::sha3::Hashable; use basic_types::LogBloom; -use super::flat::FlatTrace; -use super::trace::Action; +use trace::flat::FlatTrace; +use types::trace_types::trace::Action; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// Addresses filter. /// /// Used to create bloom possibilities and match filters. -pub struct AddressesFilter(Vec
); +#[derive(Binary)] +pub struct AddressesFilter { + list: Vec
+} impl From> for AddressesFilter { fn from(addresses: Vec
) -> Self { - AddressesFilter(addresses) + AddressesFilter { list: addresses } } } impl AddressesFilter { /// Returns true if address matches one of the searched addresses. pub fn matches(&self, address: &Address) -> bool { - self.matches_all() || self.0.contains(address) + self.matches_all() || self.list.contains(address) } /// Returns true if this address filter matches everything. pub fn matches_all(&self) -> bool { - self.0.is_empty() + self.list.is_empty() } /// Returns blooms of this addresses filter. pub fn blooms(&self) -> Vec { - match self.0.is_empty() { + match self.list.is_empty() { true => vec![LogBloom::new()], - false => self.0.iter() + false => self.list.iter() .map(|address| LogBloom::from_bloomed(&address.sha3())) .collect() } @@ -56,11 +64,11 @@ impl AddressesFilter { /// Returns vector of blooms zipped with blooms of this addresses filter. pub fn with_blooms(&self, blooms: Vec) -> Vec { - match self.0.is_empty() { + match self.list.is_empty() { true => blooms, false => blooms .into_iter() - .flat_map(|bloom| self.0.iter() + .flat_map(|bloom| self.list.iter() .map(|address| bloom.with_bloomed(&address.sha3())) .collect::>()) .collect() @@ -68,6 +76,7 @@ impl AddressesFilter { } } +#[derive(Binary)] /// Traces filter. pub struct Filter { /// Block range. diff --git a/ethcore/src/trace/localized.rs b/ethcore/src/types/trace_types/localized.rs similarity index 89% rename from ethcore/src/trace/localized.rs rename to ethcore/src/types/trace_types/localized.rs index ef18d6898..334d7b518 100644 --- a/ethcore/src/trace/localized.rs +++ b/ethcore/src/types/trace_types/localized.rs @@ -14,12 +14,17 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Localized traces type definitions + use util::H256; use super::trace::{Action, Res}; use header::BlockNumber; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// Localized trace. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Binary)] pub struct LocalizedTrace { /// Type of action performed by a transaction. pub action: Action, diff --git a/ethcore/src/types/trace_types/mod.rs b/ethcore/src/types/trace_types/mod.rs new file mode 100644 index 000000000..db429a8f4 --- /dev/null +++ b/ethcore/src/types/trace_types/mod.rs @@ -0,0 +1,21 @@ +// 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 . + +//! Types used in the public api + +pub mod filter; +pub mod trace; +pub mod localized; diff --git a/ethcore/src/trace/trace.rs b/ethcore/src/types/trace_types/trace.rs similarity index 96% rename from ethcore/src/trace/trace.rs rename to ethcore/src/types/trace_types/trace.rs index f7efe9721..f8fe07360 100644 --- a/ethcore/src/trace/trace.rs +++ b/ethcore/src/types/trace_types/trace.rs @@ -15,14 +15,18 @@ // along with Parity. If not, see . //! Tracing datatypes. + use util::{U256, Bytes, Address, FixedHash}; use util::rlp::*; use util::sha3::Hashable; use action_params::ActionParams; use basic_types::LogBloom; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; /// `Call` result. -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, Binary)] pub struct CallResult { /// Gas used by call. pub gas_used: U256, @@ -51,7 +55,7 @@ impl Decodable for CallResult { } /// `Create` result. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct CreateResult { /// Gas used by create. pub gas_used: U256, @@ -84,7 +88,7 @@ impl Decodable for CreateResult { } /// Description of a _call_ action, either a `CALL` operation or a message transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct Call { /// The sending account. pub from: Address, @@ -146,7 +150,7 @@ impl Call { } /// Description of a _create_ action, either a `CREATE` operation or a create transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub struct Create { /// The address of the creator. pub from: Address, @@ -202,7 +206,7 @@ impl Create { } /// Description of an action that we trace; will be either a call or a create. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub enum Action { /// It's a call action. Call(Call), @@ -249,7 +253,7 @@ impl Action { } /// The result of the performed action. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] pub enum Res { /// Successful call action result. Call(CallResult), @@ -300,7 +304,7 @@ impl Decodable for Res { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Binary)] /// A trace; includes a description of the action being traced and sub traces of each interior action. pub struct Trace { /// The number of EVM execution environments active when this action happened; 0 if it's diff --git a/ethcore/src/transaction.rs b/ethcore/src/types/transaction.rs similarity index 91% rename from ethcore/src/transaction.rs rename to ethcore/src/types/transaction.rs index ca54f26bb..842decd88 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -16,13 +16,21 @@ //! Transaction data structure. -use util::*; +use util::numbers::*; +use std::ops::Deref; +use util::rlp::*; +use util::sha3::*; +use util::{UtilError, CryptoError, Bytes, Signature, Secret, ec}; +use std::cell::*; use error::*; use evm::Schedule; use header::BlockNumber; use ethjson; +use ipc::binary::BinaryConvertError; +use std::mem; +use std::collections::VecDeque; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Binary)] /// Transaction action type. pub enum Action { /// Create creates new contract. @@ -48,7 +56,7 @@ impl Decodable for Action { /// A set of information describing an externally-originating message call /// or contract creation operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq, Binary)] pub struct Transaction { /// Nonce. pub nonce: U256, @@ -183,7 +191,7 @@ impl Transaction { } /// Signed transaction information. -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, Eq, Binary)] pub struct SignedTransaction { /// Plain Transaction. unsigned: Transaction, @@ -310,7 +318,7 @@ impl SignedTransaction { } try!(self.sender()); if self.gas < U256::from(self.gas_required(&schedule)) { - Err(From::from(TransactionError::InvalidGasLimit(OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) + Err(From::from(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) } else { Ok(self) } @@ -318,7 +326,7 @@ impl SignedTransaction { } /// Signed Transaction that is a part of canon blockchain. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Binary)] pub struct LocalizedTransaction { /// Signed part. pub signed: SignedTransaction, @@ -340,7 +348,7 @@ impl Deref for LocalizedTransaction { #[test] fn sender_test() { - let t: SignedTransaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); + let t: SignedTransaction = decode(&::rustc_serialize::hex::FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); assert_eq!(t.data, b""); assert_eq!(t.gas, U256::from(0x5208u64)); assert_eq!(t.gas_price, U256::from(0x01u64)); @@ -354,7 +362,7 @@ fn sender_test() { #[test] fn signing() { - let key = KeyPair::create().unwrap(); + let key = ::util::crypto::KeyPair::create().unwrap(); let t = Transaction { action: Action::Create, nonce: U256::from(42), diff --git a/ethcore/src/blockchain/tree_route.rs b/ethcore/src/types/tree_route.rs similarity index 96% rename from ethcore/src/blockchain/tree_route.rs rename to ethcore/src/types/tree_route.rs index 3c4906449..2ad0aa240 100644 --- a/ethcore/src/blockchain/tree_route.rs +++ b/ethcore/src/types/tree_route.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +//! Tree route info type definition + use util::numbers::H256; /// Represents a tree route between `from` block and `to` block: diff --git a/ipc/codegen/src/serialization.rs b/ipc/codegen/src/serialization.rs index 6a9784790..e8f3d2cd8 100644 --- a/ipc/codegen/src/serialization.rs +++ b/ipc/codegen/src/serialization.rs @@ -175,6 +175,11 @@ fn binary_expr_struct( ) -> Result { let size_exprs: Vec> = fields.iter().enumerate().map(|(index, field)| { + + if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { + return quote_expr!(cx, 1); + } + let field_type_ident = builder.id( &::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))); @@ -228,23 +233,34 @@ fn binary_expr_struct( }, }; - write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() { - 0 => mem::size_of::<$field_type_ident>(), - _ => { let size = $member_expr .size(); length_stack.push_back(size); size }, - }).unwrap()); - - write_stmts.push(quote_stmt!(cx, - if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap()); + if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { + write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap()); + write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).unwrap()); + } + else { + write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => { let size = $member_expr .size(); length_stack.push_back(size); size }, + }).unwrap()); + write_stmts.push(quote_stmt!(cx, + if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap()); + } write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap()); let field_index = builder.id(&format!("{}", index)); map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap()); - map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() { - 0 => mem::size_of::<$field_type_ident>(), - _ => length_stack.pop_front().unwrap(), - }).unwrap()); - map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap()); + + if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" { + map_stmts.push(quote_stmt!(cx, total = total + 1;).unwrap()); + } + else { + map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => length_stack.pop_front().unwrap(), + }).unwrap()); + map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap()); + } }; let read_expr = match fields.iter().any(|f| codegen::has_ptr(&f.ty)) { @@ -366,6 +382,8 @@ fn fields_sequence( use syntax::parse::token; use syntax::ast::TokenTree::Token; + let named_members = fields.iter().any(|f| f.ident.is_some()); + ::quasi::parse_expr_panic(&mut ::syntax::parse::new_parser_from_tts( ext_cx.parse_sess(), ext_cx.cfg(), @@ -373,7 +391,12 @@ fn fields_sequence( let _sp = ext_cx.call_site(); let mut tt = ::std::vec::Vec::new(); tt.push(Token(_sp, token::Ident(variant_ident.clone()))); - tt.push(Token(_sp, token::OpenDelim(token::Paren))); + if named_members { + tt.push(Token(_sp, token::OpenDelim(token::Brace))); + } + else { + tt.push(Token(_sp, token::OpenDelim(token::Paren))); + } for (idx, field) in fields.iter().enumerate() { if field.ident.is_some() { @@ -381,6 +404,21 @@ fn fields_sequence( tt.push(Token(_sp, token::Colon)); } + // special case for u8, it just takes byte form sequence + if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" { + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer")))); + + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map")))); + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx))))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + + tt.push(Token(_sp, token::Comma)); + continue; + } + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!")))); tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push( @@ -393,6 +431,7 @@ fn fields_sequence( tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push(Token(_sp, token::BinOp(token::And))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer")))); tt.push(Token(_sp, token::OpenDelim(token::Bracket))); @@ -418,8 +457,12 @@ fn fields_sequence( tt.push(Token(_sp, token::CloseDelim(token::Paren))); tt.push(Token(_sp, token::Comma)); } - tt.push(Token(_sp, token::CloseDelim(token::Paren))); - + if named_members { + tt.push(Token(_sp, token::CloseDelim(token::Brace))); + } + else { + tt.push(Token(_sp, token::CloseDelim(token::Paren))); + } tt }) ).unwrap() @@ -455,6 +498,21 @@ fn named_fields_sequence( tt.push(Token(_sp, token::Ident(field.ident.clone().unwrap()))); tt.push(Token(_sp, token::Colon)); + // special case for u8, it just takes byte form sequence + if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" { + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer")))); + + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map")))); + tt.push(Token(_sp, token::OpenDelim(token::Bracket))); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx))))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + + tt.push(Token(_sp, token::Comma)); + continue; + } + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!")))); tt.push(Token(_sp, token::OpenDelim(token::Paren))); tt.push(Token( @@ -573,7 +631,6 @@ fn binary_expr_variant( .map(|(id, field)|(field.ident.unwrap(), builder.pat().ref_id(id)))) .build(); - let binary_expr = try!(binary_expr_struct( cx, &builder, @@ -593,7 +650,7 @@ fn binary_expr_variant( let buffer = &mut buffer[1..]; $write_expr }), - read: quote_arm!(cx, $pat => { $read_expr } ), + read: quote_arm!(cx, $variant_index_ident => { $read_expr } ), }) }, } diff --git a/ipc/rpc/src/binary.rs b/ipc/rpc/src/binary.rs index 3ba172c6e..4fb359f7c 100644 --- a/ipc/rpc/src/binary.rs +++ b/ipc/rpc/src/binary.rs @@ -17,9 +17,10 @@ //! Binary representation of types use util::bytes::Populatable; -use util::numbers::{U256, H256, H2048, Address}; +use util::numbers::{U256, U512, H256, H2048, Address}; use std::mem; use std::collections::VecDeque; +use std::ops::Range; #[derive(Debug)] pub struct BinaryConvertError; @@ -232,6 +233,29 @@ impl BinaryConvertable for ::std::cell::RefCell where T: BinaryConvertable } } +impl BinaryConvertable for ::std::cell::Cell where T: BinaryConvertable + Copy { + fn size(&self) -> usize { + self.get().size() + } + + fn from_empty_bytes() -> Result { + Ok(::std::cell::Cell::new(try!(T::from_empty_bytes()))) + } + + fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result { + Ok(::std::cell::Cell::new(try!(T::from_bytes(buffer, length_stack)))) + } + + fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> { + try!(self.get().to_bytes(buffer, length_stack)); + Ok(()) + } + + fn len_params() -> usize { + T::len_params() + } +} + impl BinaryConvertable for Vec { fn size(&self) -> usize { self.len() @@ -365,8 +389,9 @@ pub fn serialize(t: &T) -> Result, BinaryConvertEr Ok(buff.into_inner()) } +#[macro_export] macro_rules! binary_fixed_size { - ($target_ty: ident) => { + ($target_ty: ty) => { impl BinaryConvertable for $target_ty { fn from_bytes(bytes: &[u8], _length_stack: &mut VecDeque) -> Result { match bytes.len().cmp(&::std::mem::size_of::<$target_ty>()) { @@ -398,9 +423,12 @@ binary_fixed_size!(usize); binary_fixed_size!(i32); binary_fixed_size!(bool); binary_fixed_size!(U256); +binary_fixed_size!(U512); binary_fixed_size!(H256); binary_fixed_size!(H2048); binary_fixed_size!(Address); +binary_fixed_size!(Range); +binary_fixed_size!(Range); #[test] fn vec_serialize() { diff --git a/ipc/tests/binary.rs.in b/ipc/tests/binary.rs.in index 710752237..74dd39c1b 100644 --- a/ipc/tests/binary.rs.in +++ b/ipc/tests/binary.rs.in @@ -36,3 +36,9 @@ pub struct DoubleRoot { pub struct ReferenceStruct<'a> { pub ref_data: &'a u64, } + +#[derive(Binary, PartialEq, Debug)] +pub enum EnumWithStruct { + Left, + Right { how_much: u64 }, +} diff --git a/ipc/tests/run.rs b/ipc/tests/run.rs index c07145f77..cdda5275b 100644 --- a/ipc/tests/run.rs +++ b/ipc/tests/run.rs @@ -16,9 +16,7 @@ #![allow(dead_code)] -extern crate bincode; extern crate ethcore_ipc as ipc; -extern crate serde; extern crate ethcore_devtools as devtools; extern crate semver; extern crate nanomsg; diff --git a/miner/src/lib.rs b/miner/src/lib.rs index bd2904fc2..f92e0de52 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -63,7 +63,7 @@ pub use external::{ExternalMiner, ExternalMinerService}; use util::{H256, U256, Address, Bytes}; use ethcore::client::{BlockChainClient, Executed}; use ethcore::block::{ClosedBlock}; -use ethcore::error::{Error}; +use ethcore::error::{Error, ExecutionError}; use ethcore::transaction::SignedTransaction; /// Miner client API @@ -150,7 +150,7 @@ pub trait MinerService : Send + Sync { fn balance(&self, chain: &BlockChainClient, address: &Address) -> U256; /// Call into contract code using pending state. - fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result; + fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result; /// Get storage value in pending state. fn storage_at(&self, chain: &BlockChainClient, address: &Address, position: &H256) -> H256; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 78ff824f6..33d21613f 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -240,7 +240,7 @@ impl MinerService for Miner { } } - fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result { + fn call(&self, chain: &BlockChainClient, t: &SignedTransaction) -> Result { let sealing_work = self.sealing_work.lock().unwrap(); match sealing_work.peek_last_ref() { Some(work) => { @@ -258,7 +258,10 @@ impl MinerService for Miner { }; // that's just a copy of the state. let mut state = block.state().clone(); - let sender = try!(t.sender()); + let sender = try!(t.sender().map_err(|e| { + let message = format!("Transaction malformed: {:?}", e); + ExecutionError::TransactionMalformed(message) + })); let balance = state.balance(&sender); // give the sender max balance state.sub_balance(&sender, &balance); diff --git a/parity/cli.rs b/parity/cli.rs index 84c941d33..90d7167dc 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -42,6 +42,9 @@ Account Options: ACCOUNTS is a comma-delimited list of addresses. --password FILE Provide a file containing a password for unlocking an account. + --keys-iterations NUM Specify the number of iterations to use when deriving key + from the password (bigger is more secure) + [default: 10240]. Networking Options: --port PORT Override the port on which the node should listen @@ -99,7 +102,9 @@ Sealing/Mining Options: [default: 0.005]. The minimum gas price is set accordingly. --usd-per-eth SOURCE USD value of a single ETH. SOURCE may be either an - amount in USD or a web service [default: etherscan]. + amount in USD, a web service or 'auto' to use each + web service in turn and fallback on the last known + good value [default: auto]. --gas-floor-target GAS Amount of gas per block to target when sealing a new block [default: 4712388]. --author ADDRESS Specify the block author (aka "coinbase") address @@ -182,6 +187,7 @@ pub struct Args { pub flag_password: Vec, pub flag_cache: Option, pub flag_keys_path: String, + pub flag_keys_iterations: u32, pub flag_bootnodes: Option, pub flag_network_id: Option, pub flag_pruning: String, diff --git a/parity/configuration.rs b/parity/configuration.rs index 8d0eea9bb..ba7789c08 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -37,6 +37,11 @@ pub struct Configuration { pub args: Args } +pub struct Directories { + pub keys: String, + pub db: String, +} + impl Configuration { pub fn parse() -> Self { Configuration { @@ -60,11 +65,6 @@ impl Configuration { self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32 } - pub fn path(&self) -> String { - let d = self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path); - d.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) - } - pub fn author(&self) -> Address { let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author); Address::from_str(clean_0x(d)).unwrap_or_else(|_| { @@ -91,11 +91,18 @@ impl Configuration { die!("{}: Invalid basic transaction price given in USD. Must be a decimal number.", self.args.flag_usd_per_tx) }); let usd_per_eth = match self.args.flag_usd_per_eth.as_str() { + "auto" => PriceInfo::get().map_or_else(|| { + let last_known_good = 9.69696; + // TODO: use #1083 to read last known good value. + last_known_good + }, |x| x.ethusd), "etherscan" => PriceInfo::get().map_or_else(|| { die!("Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth.") }, |x| x.ethusd), x => FromStr::from_str(x).unwrap_or_else(|_| die!("{}: Invalid ether price given in USD. Must be a decimal number.", x)) }; + // TODO: use #1083 to write last known good value as use_per_eth. + let wei_per_usd: f32 = 1.0e18 / usd_per_eth; let gas_per_tx: f32 = 21000.0; let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; @@ -113,10 +120,6 @@ impl Configuration { } } - pub fn keys_path(&self) -> String { - self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) - } - pub fn spec(&self) -> Spec { match self.chain().as_str() { "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(), @@ -245,7 +248,7 @@ impl Configuration { .collect::>() .into_iter() }).collect::>(); - let account_service = AccountService::new_in(Path::new(&self.keys_path())); + let account_service = AccountService::with_security(Path::new(&self.keys_path()), self.keys_iterations()); if let Some(ref unlocks) = self.args.flag_unlock { for d in unlocks.split(',') { let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| { @@ -263,23 +266,23 @@ impl Configuration { self.args.flag_rpcapi.clone().unwrap_or(self.args.flag_jsonrpc_apis.clone()) } - pub fn rpc_cors(&self) -> Option { - self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone()) + pub fn rpc_cors(&self) -> Vec { + let cors = self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone()); + cors.map_or_else(Vec::new, |c| c.split(',').map(|s| s.to_owned()).collect()) } - - fn geth_ipc_path() -> &'static str { - if cfg!(target_os = "macos") { - "$HOME/Library/Ethereum/geth.ipc" - } else { - "$HOME/.ethereum/geth.ipc" - } + + fn geth_ipc_path() -> String { + path::ethereum::with_default("geth.ipc").to_str().unwrap().to_owned() + } + + pub fn keys_iterations(&self) -> u32 { + self.args.flag_keys_iterations } pub fn ipc_settings(&self) -> IpcConfiguration { IpcConfiguration { enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off), - socket_addr: if self.args.flag_geth { Self::geth_ipc_path().to_owned() } else { self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone()) } - .replace("$HOME", env::home_dir().unwrap().to_str().unwrap()), + socket_addr: self.ipc_path(), apis: self.args.flag_ipcapi.clone().unwrap_or(self.args.flag_ipc_apis.clone()), } } @@ -296,6 +299,37 @@ impl Configuration { rpc_port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port), } } + + pub fn directories(&self) -> Directories { + let db_path = Configuration::replace_home( + &self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path)); + ::std::fs::create_dir_all(&db_path).unwrap_or_else(|e| die_with_io_error("main", e)); + + let keys_path = Configuration::replace_home(&self.args.flag_keys_path); + ::std::fs::create_dir_all(&db_path).unwrap_or_else(|e| die_with_io_error("main", e)); + + Directories { + keys: keys_path, + db: db_path, + } + } + + pub fn keys_path(&self) -> String { + self.directories().keys + } + + pub fn path(&self) -> String { + self.directories().db + } + + fn replace_home(arg: &str) -> String { + arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + } + + fn ipc_path(&self) -> String { + if self.args.flag_geth { Self::geth_ipc_path() } + else { Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) } + } } #[cfg(test)] @@ -338,7 +372,7 @@ mod tests { assert_eq!(net.rpc_enabled, true); assert_eq!(net.rpc_interface, "all".to_owned()); assert_eq!(net.rpc_port, 8000); - assert_eq!(conf.rpc_cors(), Some("*".to_owned())); + assert_eq!(conf.rpc_cors(), vec!["*".to_owned()]); assert_eq!(conf.rpc_apis(), "web3,eth".to_owned()); } diff --git a/parity/main.rs b/parity/main.rs index ded07505c..dd70d39cc 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -219,7 +219,7 @@ fn flush_stdout() { fn execute_account_cli(conf: Configuration) { use util::keys::store::SecretStore; use rpassword::read_password; - let mut secret_store = SecretStore::new_in(Path::new(&conf.keys_path())); + let mut secret_store = SecretStore::with_security(Path::new(&conf.keys_path()), conf.keys_iterations()); if conf.args.cmd_new { println!("Please note that password is NOT RECOVERABLE."); print!("Type password: "); diff --git a/parity/rpc.rs b/parity/rpc.rs index a48af6401..e1782e9b6 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -41,7 +41,7 @@ pub struct HttpConfiguration { pub interface: String, pub port: u16, pub apis: String, - pub cors: Option, + pub cors: Vec, } pub struct IpcConfiguration { @@ -139,11 +139,11 @@ pub fn setup_http_rpc_server( pub fn setup_http_rpc_server( dependencies: &Arc, url: &SocketAddr, - cors_domain: Option, + cors_domains: Vec, apis: Vec<&str>, ) -> RpcServer { let server = setup_rpc_server(apis, dependencies); - let start_result = server.start_http(url, cors_domain); + let start_result = server.start_http(url, cors_domains); let deps = dependencies.clone(); match start_result { Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err), diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 326634ab2..c4de059bf 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -13,7 +13,7 @@ log = "0.3" serde = "0.7.0" serde_json = "0.7.0" jsonrpc-core = "2.0" -jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" } +jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git", branch = "multiple_cors_domains" } ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index d4998fdc3..7d9818615 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -59,9 +59,11 @@ impl RpcServer { } /// Start http server asynchronously and returns result with `Server` handle on success or an error. - pub fn start_http(&self, addr: &SocketAddr, cors_domain: Option) -> Result { - let cors_domain = cors_domain.to_owned(); - Server::start(addr, self.handler.clone(), cors_domain.map(jsonrpc_http_server::AccessControlAllowOrigin::Value)) + pub fn start_http(&self, addr: &SocketAddr, cors_domains: Vec) -> Result { + let cors_domains = cors_domains.into_iter() + .map(jsonrpc_http_server::AccessControlAllowOrigin::Value) + .collect(); + Server::start(addr, self.handler.clone(), cors_domains) } /// Start ipc server asynchronously and returns result with `Server` handle on success or an error. diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 51946b97b..6fddf7b4f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -123,8 +123,8 @@ impl EthClient fn uncle(&self, id: UncleId) -> Result { let client = take_weak!(self.client); - match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.hash())).map(|diff| (diff, u))) { - Some((difficulty, uncle)) => { + match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.parent_hash().clone())).map(|diff| (diff, u))) { + Some((parent_difficulty, uncle)) => { let block = Block { hash: OptionalValue::Value(uncle.hash()), parent_hash: uncle.parent_hash, @@ -139,7 +139,7 @@ impl EthClient logs_bloom: uncle.log_bloom, timestamp: U256::from(uncle.timestamp), difficulty: uncle.difficulty, - total_difficulty: difficulty, + total_difficulty: uncle.difficulty + parent_difficulty, receipts_root: uncle.receipts_root, extra_data: Bytes::new(uncle.extra_data), seal_fields: uncle.seal.into_iter().map(Bytes::new).collect(), diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index cd4157fa9..1fbe15ca4 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -18,7 +18,7 @@ use util::{Address, H256, Bytes, U256, FixedHash, Uint}; use util::standard::*; -use ethcore::error::Error; +use ethcore::error::{Error, ExecutionError}; use ethcore::client::{BlockChainClient, Executed}; use ethcore::block::{ClosedBlock, IsBlock}; use ethcore::transaction::SignedTransaction; @@ -179,7 +179,7 @@ impl MinerService for TestMinerService { self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone()) } - fn call(&self, _chain: &BlockChainClient, _t: &SignedTransaction) -> Result { + fn call(&self, _chain: &BlockChainClient, _t: &SignedTransaction) -> Result { unimplemented!(); } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 14809fdc4..bd94fb9be 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1193,7 +1193,7 @@ impl ChainSync { let mut rlp_stream = RlpStream::new_list(route.blocks.len()); for block_hash in route.blocks { let mut hash_rlp = RlpStream::new_list(2); - let difficulty = chain.block_total_difficulty(BlockId::Hash(block_hash.clone())).expect("Mallformed block without a difficulty on the chain!"); + let difficulty = chain.block_total_difficulty(BlockId::Hash(block_hash.clone())).expect("Malformed block without a difficulty on the chain!"); hash_rlp.append(&block_hash); hash_rlp.append(&difficulty); rlp_stream.append_raw(&hash_rlp.out(), 1); @@ -1570,7 +1570,7 @@ mod tests { } #[test] - fn handles_peer_new_block_mallformed() { + fn handles_peer_new_block_malformed() { let mut client = TestBlockChainClient::new(); client.add_blocks(10, EachBlockWith::Uncle); diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index be9941589..f87b494a9 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -517,7 +517,7 @@ pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Displa /// Return single byte fn byte(&self, index: usize) -> u8; /// Get this Uint as slice of bytes - fn to_bytes(&self, bytes: &mut[u8]); + fn to_raw_bytes(&self, bytes: &mut[u8]); /// Create `Uint(10**n)` fn exp10(n: usize) -> Self; @@ -621,7 +621,7 @@ macro_rules! construct_uint { (arr[index / 8] >> (((index % 8)) * 8)) as u8 } - fn to_bytes(&self, bytes: &mut[u8]) { + fn to_raw_bytes(&self, bytes: &mut[u8]) { assert!($n_words * 8 == bytes.len()); let &$name(ref arr) = self; for i in 0..bytes.len() { @@ -780,7 +780,7 @@ macro_rules! construct_uint { where S: serde::Serializer { let mut hex = "0x".to_owned(); let mut bytes = [0u8; 8 * $n_words]; - self.to_bytes(&mut bytes); + self.to_raw_bytes(&mut bytes); let len = cmp::max((self.bits() + 7) / 8, 1); hex.push_str(bytes[bytes.len() - len..].to_hex().as_ref()); serializer.serialize_str(hex.as_ref()) @@ -1482,7 +1482,7 @@ mod tests { let hex = "8090a0b0c0d0e0f00910203040506077583a2cf8264910e1436bda32571012f0"; let uint = U256::from_str(hex).unwrap(); let mut bytes = [0u8; 32]; - uint.to_bytes(&mut bytes); + uint.to_raw_bytes(&mut bytes); let uint2 = U256::from(&bytes[..]); assert_eq!(uint, uint2); } diff --git a/util/src/hash.rs b/util/src/hash.rs index 69ed17c79..e1b82b14c 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -517,7 +517,7 @@ impl From for H256 { fn from(value: U256) -> H256 { unsafe { let mut ret: H256 = ::std::mem::uninitialized(); - value.to_bytes(&mut ret); + value.to_raw_bytes(&mut ret); ret } } @@ -527,7 +527,7 @@ impl<'_> From<&'_ U256> for H256 { fn from(value: &'_ U256) -> H256 { unsafe { let mut ret: H256 = ::std::mem::uninitialized(); - value.to_bytes(&mut ret); + value.to_raw_bytes(&mut ret); ret } } diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index d9268a95f..3f4100163 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -381,7 +381,7 @@ impl KeyFileContent { } } - /// Loads key from valid json, returns error and records warning if key is mallformed + /// Loads key from valid json, returns error and records warning if key is malformed pub fn load(json: &Json) -> Result { match Self::from_json(json) { Ok(key_file) => Ok(key_file), diff --git a/util/src/keys/geth_import.rs b/util/src/keys/geth_import.rs index 9886a61a8..56e73f790 100644 --- a/util/src/keys/geth_import.rs +++ b/util/src/keys/geth_import.rs @@ -20,6 +20,7 @@ use common::*; use keys::store::SecretStore; use keys::directory::KeyFileContent; use std::path::PathBuf; +use path; /// Enumerates all geth keys in the directory and returns collection of tuples `(accountId, filename)` pub fn enumerate_geth_keys(path: &Path) -> Result, ImportError> { @@ -98,30 +99,7 @@ pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: /// /// Based on https://github.com/ethereum/go-ethereum/blob/e553215/common/path.go#L75 pub fn keystore_dir() -> PathBuf { - #[cfg(target_os = "macos")] - fn data_dir(mut home: PathBuf) -> PathBuf { - home.push("Library"); - home.push("Ethereum"); - home - } - - #[cfg(windows)] - fn data_dir(mut home: PathBuf) -> PathBuf { - home.push("AppData"); - home.push("Roaming"); - home.push("Ethereum"); - home - } - - #[cfg(not(any(target_os = "macos", windows)))] - fn data_dir(mut home: PathBuf) -> PathBuf { - home.push(".ethereum"); - home - } - - let mut data_dir = data_dir(::std::env::home_dir().expect("Failed to get home dir")); - data_dir.push("keystore"); - data_dir + path::ethereum::with_default("keystore") } #[cfg(test)] diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index a879a4cd2..bf5edf3c9 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -73,6 +73,7 @@ pub enum SigningError { pub struct SecretStore { directory: KeyDirectory, unlocks: RwLock>, + key_iterations: u32, } struct AccountUnlock { @@ -128,10 +129,15 @@ impl AccountProvider for AccountService { impl AccountService { /// New account service with the keys store in specific location pub fn new_in(path: &Path) -> Self { - let secret_store = RwLock::new(SecretStore::new_in(path)); + AccountService::with_security(path, KEY_ITERATIONS) + } + + /// New account service with the keys store in specific location and configured security parameters + pub fn with_security(path: &Path, key_iterations: u32) -> Self { + let secret_store = RwLock::new(SecretStore::with_security(path, key_iterations)); secret_store.write().unwrap().try_import_existing(); AccountService { - secret_store: secret_store + secret_store: secret_store, } } @@ -157,10 +163,16 @@ impl AccountService { impl SecretStore { /// new instance of Secret Store in specific directory pub fn new_in(path: &Path) -> Self { + SecretStore::with_security(path, KEY_ITERATIONS) + } + + /// new instance of Secret Store in specific directory and configured security parameters + pub fn with_security(path: &Path, key_iterations: u32) -> Self { ::std::fs::create_dir_all(&path).expect("Cannot access requested key directory - critical"); SecretStore { directory: KeyDirectory::new(path), unlocks: RwLock::new(HashMap::new()), + key_iterations: key_iterations, } } @@ -206,6 +218,7 @@ impl SecretStore { SecretStore { directory: KeyDirectory::new(path.as_path()), unlocks: RwLock::new(HashMap::new()), + key_iterations: KEY_ITERATIONS, } } @@ -289,8 +302,8 @@ fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) (derived_right_bits.to_vec(), derived_left_bits.to_vec()) } -fn derive_key(password: &str, salt: &H256) -> (Bytes, Bytes) { - derive_key_iterations(password, salt, KEY_ITERATIONS) +fn derive_key(password: &str, salt: &H256, iterations: u32) -> (Bytes, Bytes) { + derive_key_iterations(password, salt, iterations) } fn derive_key_scrypt(password: &str, salt: &H256, n: u32, p: u32, r: u32) -> (Bytes, Bytes) { @@ -346,7 +359,7 @@ impl EncryptedHashMap for SecretStore { // two parts of derived key // DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits] - let (derived_left_bits, derived_right_bits) = derive_key(password, &salt); + let (derived_left_bits, derived_right_bits) = derive_key(password, &salt, self.key_iterations); let mut cipher_text = vec![0u8; value.as_slice().len()]; // aes-128-ctr with initial vector of iv @@ -361,7 +374,7 @@ impl EncryptedHashMap for SecretStore { iv, salt, mac, - KEY_ITERATIONS, + self.key_iterations, KEY_LENGTH)); key_file.id = key; if let Err(io_error) = self.directory.save(key_file) { diff --git a/util/src/lib.rs b/util/src/lib.rs index 530f2b4c5..a97282198 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -148,6 +148,7 @@ pub mod panics; pub mod keys; pub mod table; pub mod network_settings; +pub mod path; pub use common::*; pub use misc::*; diff --git a/util/src/path.rs b/util/src/path.rs new file mode 100644 index 000000000..3a8dcaaae --- /dev/null +++ b/util/src/path.rs @@ -0,0 +1,56 @@ +// 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 . + +//! Path utilities + +/// Default ethereum paths +pub mod ethereum { + use std::path::PathBuf; + + #[cfg(target_os = "macos")] + /// Default path for ethereum installation on Mac Os + pub fn default() -> PathBuf { + let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + home.push("Library"); + home.push("Ethereum"); + home + } + + #[cfg(windows)] + /// Default path for ethereum installation on Windows + pub fn default() -> PathBuf { + let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + home.push("AppData"); + home.push("Roaming"); + home.push("Ethereum"); + home + } + + #[cfg(not(any(target_os = "macos", windows)))] + /// Default path for ethereum installation on posix system which is not Mac OS + pub fn default() -> PathBuf { + let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + home.push(".ethereum"); + home + } + + /// Get the specific folder inside default ethereum installation + pub fn with_default(s: &str) -> PathBuf { + let mut pth = default(); + pth.push(s); + pth + } +} diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 80be6fd37..819e9d362 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -65,6 +65,8 @@ use std::collections::HashMap; use jsonrpc_core::{IoHandler, IoDelegate}; use router::auth::{Authorization, NoAuth, HttpBasicAuth}; +static DAPPS_DOMAIN : &'static str = ".parity"; + /// Webapps HTTP+RPC server build. pub struct ServerBuilder { handler: Arc, diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index 211c9f5eb..e9d255f95 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -21,6 +21,7 @@ mod url; mod redirect; pub mod auth; +use DAPPS_DOMAIN; use std::sync::Arc; use std::collections::HashMap; use url::Host; @@ -40,7 +41,7 @@ pub enum SpecialEndpoint { Rpc, Api, Utils, - None + None, } pub struct Router { @@ -165,8 +166,8 @@ fn extract_endpoint(url: &Option) -> (Option, SpecialEndpoint match *url { Some(ref url) => match url.host { - Host::Domain(ref domain) if domain.ends_with(apps::DAPPS_DOMAIN) => { - let len = domain.len() - apps::DAPPS_DOMAIN.len(); + Host::Domain(ref domain) if domain.ends_with(DAPPS_DOMAIN) => { + let len = domain.len() - DAPPS_DOMAIN.len(); let id = domain[0..len].to_owned(); (Some(EndpointPath {