diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..f679363b8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,12 @@ +# Contributing to Parity + +## License + +By contributing to Parity, you agree that your contributions will be +licensed under the [BSD License](LICENSE). + +At the top of every source code file you alter, after the initial +licence section, please append a second section that reads: + +Portions contributed by YOUR NAME are hereby placed under the BSD licence. + diff --git a/Cargo.toml b/Cargo.toml index fb52d14d5..ca2ad9c6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ rustc-serialize = "0.3" docopt = "0.6" docopt_macros = "0.6" ctrlc = { git = "https://github.com/tomusdrw/rust-ctrlc.git" } -clippy = "0.0.37" +clippy = "0.0.41" ethcore-util = { path = "util" } ethcore = { path = "ethcore" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index be7652e17..90d147a02 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -18,7 +18,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = "0.0.37" +clippy = "0.0.41" crossbeam = "0.1.5" lazy_static = "0.1" diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json index 301441958..e01c4bb3f 100644 --- a/ethcore/res/ethereum/frontier.json +++ b/ethcore/res/ethereum/frontier.json @@ -3,7 +3,7 @@ "engineName": "Ethash", "params": { "accountStartNonce": "0x00", - "frontierCompatibilityModeLimit": "0xf4240", + "frontierCompatibilityModeLimit": "0xf4240fff", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index 84a6200fd..7ab6a58f4 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -3,7 +3,7 @@ "engineName": "Ethash", "params": { "accountStartNonce": "0x00", - "frontierCompatibilityModeLimit": "0xf4240", + "frontierCompatibilityModeLimit": "0xf4240fff", "maximumExtraDataSize": "0x20", "tieBreakingGas": false, "minGasLimit": "0x1388", diff --git a/ethcore/src/account_diff.rs b/ethcore/src/account_diff.rs index 6c7e6573e..c02b7ec7b 100644 --- a/ethcore/src/account_diff.rs +++ b/ethcore/src/account_diff.rs @@ -72,14 +72,14 @@ impl AccountDiff { pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option { match (pre, post) { (None, Some(x)) => Some(AccountDiff { - balance: Diff::Born(x.balance.clone()), - nonce: Diff::Born(x.nonce.clone()), + balance: Diff::Born(x.balance), + nonce: Diff::Born(x.nonce), code: Diff::Born(x.code.clone()), storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Born(v.clone()))).collect(), }), (Some(x), None) => Some(AccountDiff { - balance: Diff::Died(x.balance.clone()), - nonce: Diff::Died(x.nonce.clone()), + balance: Diff::Died(x.balance), + nonce: Diff::Died(x.nonce), code: Diff::Died(x.code.clone()), storage: x.storage.iter().map(|(k, v)| (k.clone(), Diff::Died(v.clone()))).collect(), }), @@ -88,8 +88,8 @@ impl AccountDiff { .filter(|k| pre.storage.get(k).unwrap_or(&H256::new()) != post.storage.get(k).unwrap_or(&H256::new())) .collect(); let r = AccountDiff { - balance: Diff::new(pre.balance.clone(), post.balance.clone()), - nonce: Diff::new(pre.nonce.clone(), post.nonce.clone()), + balance: Diff::new(pre.balance, post.balance), + nonce: Diff::new(pre.nonce, post.nonce), code: Diff::new(pre.code.clone(), post.code.clone()), storage: storage.into_iter().map(|k| (k.clone(), Diff::new( diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 764b76588..9240ff800 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -23,24 +23,6 @@ use extras::*; use transaction::*; use views::*; -/// Uniquely identifies block. -pub enum BlockId { - /// Block's sha3. - /// Querying by hash is always faster. - Hash(H256), - /// Block number within canon blockchain. - Number(BlockNumber) -} - -/// Uniquely identifies transaction. -pub enum TransactionId { - /// Transaction's sha3. - Hash(H256), - /// Block id and transaction index within this block. - /// Querying by block position is always faster. - Location(BlockId, usize) -} - /// Represents a tree route between `from` block and `to` block: pub struct TreeRoute { /// A vector of hashes of all blocks, ordered from `from` to `to`. @@ -129,18 +111,8 @@ pub trait BlockProvider { } /// Get transaction with given transaction hash. - fn transaction(&self, id: TransactionId) -> Option { - match id { - TransactionId::Hash(ref hash) => self.transaction_address(hash), - TransactionId::Location(BlockId::Hash(hash), index) => Some(TransactionAddress { - block_hash: hash, - index: index - }), - TransactionId::Location(BlockId::Number(number), index) => self.block_hash(number).map(|hash| TransactionAddress { - block_hash: hash, - index: index - }) - }.and_then(|address| self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index))) + fn transaction(&self, address: &TransactionAddress) -> Option { + self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)) } /// Get a list of transactions for a given block. @@ -887,7 +859,7 @@ mod tests { let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); for t in transactions { - assert_eq!(bc.transaction(TransactionId::Hash(t.hash())).unwrap(), t); + assert_eq!(bc.transaction(&bc.transaction_address(&t.hash()).unwrap()).unwrap(), t); } } } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 26535c46c..09f7417e8 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -19,7 +19,7 @@ use util::*; use util::panics::*; use rocksdb::{Options, DB, DBCompactionStyle}; -use blockchain::{BlockChain, BlockProvider, CacheSize, TransactionId}; +use blockchain::{BlockChain, BlockProvider, CacheSize}; use views::BlockView; use error::*; use header::BlockNumber; @@ -33,8 +33,33 @@ use env_info::LastHashes; use verification::*; use block::*; use transaction::LocalizedTransaction; +use extras::TransactionAddress; pub use blockchain::TreeRoute; +/// Uniquely identifies block. +#[derive(Debug, PartialEq, Clone)] +pub enum BlockId { + /// Block's sha3. + /// Querying by hash is always faster. + Hash(H256), + /// Block number within canon blockchain. + Number(BlockNumber), + /// Earliest block (genesis). + Earliest, + /// Latest mined block. + Latest +} + +/// Uniquely identifies transaction. +#[derive(Debug, PartialEq, Clone)] +pub enum TransactionId { + /// Transaction's sha3. + Hash(H256), + /// Block id and transaction index within this block. + /// Querying by block position is always faster. + Location(BlockId, usize) +} + /// General block status #[derive(Debug, Eq, PartialEq)] pub enum BlockStatus { @@ -71,41 +96,25 @@ impl fmt::Display for BlockChainInfo { /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { - /// Get raw block header data by block header hash. - fn block_header(&self, hash: &H256) -> Option; + /// Get raw block header data by block id. + fn block_header(&self, id: BlockId) -> Option; - /// Get raw block body data by block header hash. + /// Get raw block body data by block id. /// Block body is an RLP list of two items: uncles and transactions. - fn block_body(&self, hash: &H256) -> Option; + fn block_body(&self, id: BlockId) -> Option; /// Get raw block data by block header hash. - fn block(&self, hash: &H256) -> Option; + fn block(&self, id: BlockId) -> Option; /// Get block status by block header hash. - fn block_status(&self, hash: &H256) -> BlockStatus; + fn block_status(&self, id: BlockId) -> BlockStatus; /// Get block total difficulty. - fn block_total_difficulty(&self, hash: &H256) -> Option; + fn block_total_difficulty(&self, id: BlockId) -> Option; /// Get address code. fn code(&self, address: &Address) -> Option; - /// Get raw block header data by block number. - fn block_header_at(&self, n: BlockNumber) -> Option; - - /// Get raw block body data by block number. - /// Block body is an RLP list of two items: uncles and transactions. - fn block_body_at(&self, n: BlockNumber) -> Option; - - /// Get raw block data by block number. - fn block_at(&self, n: BlockNumber) -> Option; - - /// Get block status by block number. - fn block_status_at(&self, n: BlockNumber) -> BlockStatus; - - /// Get block total difficulty. - fn block_total_difficulty_at(&self, n: BlockNumber) -> Option; - /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; @@ -133,7 +142,7 @@ pub trait BlockChainClient : Sync + Send { /// Get the best block header. fn best_block_header(&self) -> Bytes { - self.block_header(&self.chain_info().best_block_hash).unwrap() + self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() } } @@ -170,7 +179,7 @@ pub struct Client { } const HISTORY: u64 = 1000; -const CLIENT_DB_VER_STR: &'static str = "2.0"; +const CLIENT_DB_VER_STR: &'static str = "2.1"; impl Client { /// Create a new client with given spec and DB path. @@ -307,12 +316,11 @@ impl Client { self.report.write().unwrap().accrue_block(&block); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); ret += 1; - - if self.block_queue.read().unwrap().queue_info().is_empty() { - io.send(NetworkIoMessage::User(SyncMessage::BlockVerified)).unwrap(); - } } self.block_queue.write().unwrap().mark_as_good(&good_blocks); + if !good_blocks.is_empty() && self.block_queue.read().unwrap().queue_info().is_empty() { + io.send(NetworkIoMessage::User(SyncMessage::BlockVerified)).unwrap(); + } ret } @@ -340,68 +348,70 @@ impl Client { pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { self.chain.write().unwrap().configure_cache(pref_cache_size, max_cache_size); } + + fn block_hash(chain: &BlockChain, id: BlockId) -> Option { + match id { + BlockId::Hash(hash) => Some(hash), + BlockId::Number(number) => chain.block_hash(number), + BlockId::Earliest => chain.block_hash(0), + BlockId::Latest => Some(chain.best_block_hash()) + } + } } impl BlockChainClient for Client { - fn block_header(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block(hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec()) + fn block_header(&self, id: BlockId) -> Option { + let chain = self.chain.read().unwrap(); + Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) } - fn block_body(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block(hash).map(|bytes| { - let rlp = Rlp::new(&bytes); - let mut body = RlpStream::new(); - body.append_raw(rlp.at(1).as_raw(), 1); - body.append_raw(rlp.at(2).as_raw(), 1); - body.out() + fn block_body(&self, id: BlockId) -> Option { + let chain = self.chain.read().unwrap(); + Self::block_hash(&chain, id).and_then(|hash| { + chain.block(&hash).map(|bytes| { + let rlp = Rlp::new(&bytes); + let mut body = RlpStream::new_list(2); + body.append_raw(rlp.at(1).as_raw(), 1); + body.append_raw(rlp.at(2).as_raw(), 1); + body.out() + }) }) } - fn block(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block(hash) + fn block(&self, id: BlockId) -> Option { + let chain = self.chain.read().unwrap(); + Self::block_hash(&chain, id).and_then(|hash| { + chain.block(&hash) + }) } - fn block_status(&self, hash: &H256) -> BlockStatus { - if self.chain.read().unwrap().is_known(&hash) { - BlockStatus::InChain - } else { - self.block_queue.read().unwrap().block_status(hash) + fn block_status(&self, id: BlockId) -> BlockStatus { + let chain = self.chain.read().unwrap(); + match Self::block_hash(&chain, id) { + Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain, + Some(hash) => self.block_queue.read().unwrap().block_status(&hash), + None => BlockStatus::Unknown } } - - fn block_total_difficulty(&self, hash: &H256) -> Option { - self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty) + + fn block_total_difficulty(&self, id: BlockId) -> Option { + let chain = self.chain.read().unwrap(); + Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) } fn code(&self, address: &Address) -> Option { self.state().code(address) } - fn block_header_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h)) - } - - fn block_body_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_body(&h)) - } - - fn block_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block(&h)) - } - - fn block_status_at(&self, n: BlockNumber) -> BlockStatus { - match self.chain.read().unwrap().block_hash(n) { - Some(h) => self.block_status(&h), - None => BlockStatus::Unknown - } - } - - fn block_total_difficulty_at(&self, n: BlockNumber) -> Option { - self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_total_difficulty(&h)) - } - fn transaction(&self, id: TransactionId) -> Option { - self.chain.read().unwrap().transaction(id) + let chain = self.chain.read().unwrap(); + match id { + TransactionId::Hash(ref hash) => chain.transaction_address(hash), + TransactionId::Location(id, index) => Self::block_hash(&chain, id).map(|hash| TransactionAddress { + block_hash: hash, + index: index + }) + }.and_then(|address| chain.transaction(&address)) } fn tree_route(&self, from: &H256, to: &H256) -> Option { @@ -421,7 +431,7 @@ impl BlockChainClient for Client { if self.chain.read().unwrap().is_known(&header.hash()) { return Err(ImportError::AlreadyInChain); } - if self.block_status(&header.parent_hash) == BlockStatus::Unknown { + if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { return Err(ImportError::UnknownParent); } self.block_queue.write().unwrap().import_block(bytes) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index e931080b2..c45b22102 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -274,7 +274,7 @@ mod tests { use block::*; use engine::*; use tests::helpers::*; - use super::*; + use super::{Ethash}; use super::super::new_morden; #[test] diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index 11c20ddbe..0d1dcd8d5 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -24,7 +24,7 @@ pub mod ethash; /// Export the denominations module. pub mod denominations; -pub use self::ethash::*; +pub use self::ethash::{Ethash}; pub use self::denominations::*; use super::spec::*; diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index 8b8197526..92d5434d0 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -391,10 +391,7 @@ impl Interpreter { instructions::SLOAD => { InstructionCost::Gas(U256::from(schedule.sload_gas)) }, - instructions::MSTORE => { - InstructionCost::GasMem(default_gas, try!(self.mem_needed_const(stack.peek(0), 32))) - }, - instructions::MLOAD => { + instructions::MSTORE | instructions::MLOAD => { InstructionCost::GasMem(default_gas, try!(self.mem_needed_const(stack.peek(0), 32))) }, instructions::MSTORE8 => { @@ -736,8 +733,7 @@ impl Interpreter { }, instructions::CALLVALUE => { stack.push(match params.value { - ActionValue::Transfer(val) => val, - ActionValue::Apparent(val) => val, + ActionValue::Transfer(val) | ActionValue::Apparent(val) => val }); }, instructions::CALLDATALOAD => { diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index d0daf33e7..3eadef15a 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -84,7 +84,7 @@ impl Ext for FakeExt { } fn balance(&self, address: &Address) -> U256 { - self.balances.get(address).unwrap().clone() + *self.balances.get(address).unwrap() } fn blockhash(&self, number: &U256) -> H256 { @@ -94,10 +94,10 @@ impl Ext for FakeExt { fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { self.calls.insert(FakeCall { call_type: FakeCallType::CREATE, - gas: gas.clone(), + gas: *gas, sender_address: None, receive_address: None, - value: Some(value.clone()), + value: Some(*value), data: code.to_vec(), code_address: None }); @@ -115,14 +115,14 @@ impl Ext for FakeExt { self.calls.insert(FakeCall { call_type: FakeCallType::CALL, - gas: gas.clone(), + gas: *gas, sender_address: Some(sender_address.clone()), receive_address: Some(receive_address.clone()), value: value, data: data.to_vec(), code_address: Some(code_address.clone()) }); - MessageCallResult::Success(gas.clone()) + MessageCallResult::Success(*gas) } fn extcode(&self, address: &Address) -> Bytes { @@ -898,7 +898,7 @@ fn test_calls(factory: super::Factory) { let mut ext = FakeExt::new(); ext.balances = { let mut s = HashMap::new(); - s.insert(params.address.clone(), params.gas.clone()); + s.insert(params.address.clone(), params.gas); s }; diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 558e477c7..4ad84497f 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -45,10 +45,9 @@ impl OriginInfo { OriginInfo { address: params.address.clone(), origin: params.origin.clone(), - gas_price: params.gas_price.clone(), + gas_price: params.gas_price, value: match params.value { - ActionValue::Transfer(val) => val, - ActionValue::Apparent(val) => val, + ActionValue::Transfer(val) | ActionValue::Apparent(val) => val } } } @@ -133,8 +132,8 @@ impl<'a> Ext for Externalities<'a> { sender: self.origin_info.address.clone(), origin: self.origin_info.origin.clone(), gas: *gas, - gas_price: self.origin_info.gas_price.clone(), - value: ActionValue::Transfer(value.clone()), + gas_price: self.origin_info.gas_price, + value: ActionValue::Transfer(*value), code: Some(code.to_vec()), data: None, }; @@ -164,11 +163,11 @@ impl<'a> Ext for Externalities<'a> { let mut params = ActionParams { sender: sender_address.clone(), address: receive_address.clone(), - value: ActionValue::Apparent(self.origin_info.value.clone()), + value: ActionValue::Apparent(self.origin_info.value), code_address: code_address.clone(), origin: self.origin_info.origin.clone(), gas: *gas, - gas_price: self.origin_info.gas_price.clone(), + gas_price: self.origin_info.gas_price, code: self.state.code(code_address), data: Some(data.to_vec()), }; diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index f6b5751a7..b5f28444a 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -115,7 +115,7 @@ declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} -declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} +//declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 762f47db4..d2690051c 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -43,8 +43,8 @@ impl PodAccount { /// NOTE: This will silently fail unless the account is fully cached. pub fn from_account(acc: &Account) -> PodAccount { PodAccount { - balance: acc.balance().clone(), - nonce: acc.nonce().clone(), + balance: *acc.balance(), + nonce: *acc.nonce(), storage: acc.storage_overlay().iter().fold(BTreeMap::new(), |mut m, (k, &(_, ref v))| {m.insert(k.clone(), v.clone()); m}), code: acc.code().unwrap().to_vec(), } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 8f95dd361..5e68efae9 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -20,7 +20,6 @@ use util::*; use util::panics::*; use spec::Spec; use error::*; -use std::env; use client::Client; /// Message type for external and internal events @@ -44,16 +43,14 @@ pub struct ClientService { impl ClientService { /// Start the service in a separate thread. - pub fn start(spec: Spec, net_config: NetworkConfiguration) -> Result { + pub fn start(spec: Spec, net_config: NetworkConfiguration, db_path: &Path) -> Result { let panic_handler = PanicHandler::new_in_arc(); let mut net_service = try!(NetworkService::start(net_config)); panic_handler.forward_from(&net_service); info!("Starting {}", net_service.host_info()); info!("Configured for {} using {} engine", spec.name, spec.engine_name); - let mut dir = env::home_dir().unwrap(); - dir.push(".parity"); - let client = try!(Client::new(spec, &dir, net_service.io().channel())); + let client = try!(Client::new(spec, db_path, net_service.io().channel())); panic_handler.forward_from(client.deref()); let client_io = Arc::new(ClientIoHandler { client: client.clone() @@ -136,7 +133,8 @@ mod tests { #[test] fn it_can_be_started() { let spec = get_test_spec(); - let service = ClientService::start(spec, NetworkConfiguration::new()); + let temp_path = RandomTempPath::new(); + let service = ClientService::start(spec, NetworkConfiguration::new(), &temp_path.as_path()); assert!(service.is_ok()); } } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index e30f703ae..00886b89c 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -153,12 +153,12 @@ impl State { /// Get the balance of account `a`. pub fn balance(&self, a: &Address) -> U256 { - self.get(a, false).as_ref().map_or(U256::zero(), |account| account.balance().clone()) + self.get(a, false).as_ref().map_or(U256::zero(), |account| *account.balance()) } /// Get the nonce of account `a`. pub fn nonce(&self, a: &Address) -> U256 { - self.get(a, false).as_ref().map_or(U256::zero(), |account| account.nonce().clone()) + self.get(a, false).as_ref().map_or(U256::zero(), |account| *account.nonce()) } /// Mutate storage of account `address` so that it is `value` for `key`. diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 697647187..d025b4b78 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use client::{BlockChainClient,Client}; +use client::{BlockChainClient, Client, BlockId}; use tests::helpers::*; use common::*; @@ -44,7 +44,7 @@ fn imports_good_block() { client.flush_queue(); client.import_verified_blocks(&IoChannel::disconnected()); - let block = client.block_header_at(1).unwrap(); + let block = client.block_header(BlockId::Number(1)).unwrap(); assert!(!block.is_empty()); } @@ -53,7 +53,7 @@ fn query_none_block() { let dir = RandomTempPath::new(); let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); - let non_existant = client.block_header_at(188); + let non_existant = client.block_header(BlockId::Number(188)); assert!(non_existant.is_none()); } @@ -61,7 +61,7 @@ fn query_none_block() { fn query_bad_block() { let client_result = get_test_client_with_blocks(vec![get_bad_state_dummy_block()]); let client = client_result.reference(); - let bad_block:Option = client.block_header_at(1); + let bad_block:Option = client.block_header(BlockId::Number(1)); assert!(bad_block.is_none()); } @@ -76,11 +76,24 @@ fn returns_chain_info() { assert_eq!(info.best_block_hash, block.header().hash()); } +#[test] +fn returns_block_body() { + let dummy_block = get_good_dummy_block(); + let client_result = get_test_client_with_blocks(vec![dummy_block.clone()]); + let client = client_result.reference(); + let block = BlockView::new(&dummy_block); + let body = client.block_body(BlockId::Hash(block.header().hash())).unwrap(); + let body = Rlp::new(&body); + assert_eq!(body.item_count(), 2); + assert_eq!(body.at(0).as_raw()[..], block.rlp().at(1).as_raw()[..]); + assert_eq!(body.at(1).as_raw()[..], block.rlp().at(2).as_raw()[..]); +} + #[test] fn imports_block_sequence() { let client_result = generate_dummy_client(6); let client = client_result.reference(); - let block = client.block_header_at(5).unwrap(); + let block = client.block_header(BlockId::Number(5)).unwrap(); assert!(!block.is_empty()); } diff --git a/install-deps.sh b/install-deps.sh index 409f10d21..774d18720 100755 --- a/install-deps.sh +++ b/install-deps.sh @@ -570,7 +570,7 @@ function run_installer() sudo apt-add-repository -y ppa:ethcore/ethcore sudo apt-get -f -y install sudo apt-get update -qq - sudo apt-get install -qq -y librocksdb-dev + sudo apt-get install -qq -y librocksdb-dev librocksdb } function linux_rocksdb_installer() @@ -669,7 +669,7 @@ function run_installer() function build_parity() { info "Downloading Parity..." - git clone git@github.com:ethcore/parity + git clone https://github.com/ethcore/parity cd parity git submodule init git submodule update @@ -688,7 +688,7 @@ function run_installer() info "- Run tests with:" info " ${b}cargo test --release --features ethcore/json-tests -p ethcore${reset}" info "- Install the client with:" - info " ${b}sudo cp parity/target/release/parity${reset}" + info " ${b}sudo cp parity/target/release/parity${reset} /usr/local/bin" echo } diff --git a/parity/main.rs b/parity/main.rs index 036edefd7..62b73ca47 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -55,16 +55,19 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity [options] [ ... ] + parity [options] [ --no-bootstrap | ... ] Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file or frontier, mainnet, morden, or testnet [default: frontier]. + -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] + --no-bootstrap Don't bother trying to connect to any nodes initially. --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. --public-address URL Specify the IP/port on which peers may connect [default: 0.0.0.0:30304]. --address URL Equivalent to --listen-address URL --public-address URL. --upnp Use UPnP to try to figure out the correct network settings. + --node-key KEY Specify node secret key as hex string. --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in bytes [default: 262144]. @@ -75,7 +78,7 @@ Options: -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. -", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option); +", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option, flag_node_key: Option); fn setup_log(init: &str) { let mut builder = LogBuilder::new(); @@ -129,7 +132,11 @@ impl Configuration { } } - fn get_spec(&self) -> Spec { + fn path(&self) -> String { + self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + } + + fn spec(&self) -> Spec { match self.args.flag_chain.as_ref() { "frontier" | "mainnet" => ethereum::new_frontier(), "morden" | "testnet" => ethereum::new_morden(), @@ -138,14 +145,16 @@ impl Configuration { } } - fn get_init_nodes(&self, spec: &Spec) -> Vec { - match self.args.arg_enode.len() { - 0 => spec.nodes().clone(), - _ => self.args.arg_enode.clone(), + fn init_nodes(&self, spec: &Spec) -> Vec { + if self.args.flag_no_bootstrap { Vec::new() } else { + match self.args.arg_enode.len() { + 0 => spec.nodes().clone(), + _ => self.args.arg_enode.clone(), + } } } - fn get_net_addresses(&self) -> (SocketAddr, SocketAddr) { + fn net_addresses(&self) -> (SocketAddr, SocketAddr) { let listen_address; let public_address; @@ -183,7 +192,7 @@ fn main() { return; } - let spec = conf.get_spec(); + let spec = conf.spec(); // Setup logging setup_log(&conf.args.flag_logging); @@ -193,13 +202,14 @@ fn main() { // Configure network let mut net_settings = NetworkConfiguration::new(); net_settings.nat_enabled = conf.args.flag_upnp; - net_settings.boot_nodes = conf.get_init_nodes(&spec); - let (listen, public) = conf.get_net_addresses(); + net_settings.boot_nodes = conf.init_nodes(&spec); + let (listen, public) = conf.net_addresses(); net_settings.listen_address = listen; net_settings.public_address = public; + net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); // Build client - let mut service = ClientService::start(spec, net_settings).unwrap(); + let mut service = ClientService::start(spec, net_settings, &Path::new(&conf.path())).unwrap(); let client = service.client().clone(); client.configure_cache(conf.args.flag_cache_pref_size, conf.args.flag_cache_max_size); @@ -251,7 +261,7 @@ impl Informant { let sync_info = sync.status(); if let (_, &Some(ref last_cache_info), &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { - println!("[ {} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, {} downloaded, {}+{} queued ···// {} ({}) bl {} ({}) ex ]", + println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// {} ({}) bl {} ({}) ex ]", chain_info.best_block_number, chain_info.best_block_hash, (report.blocks_imported - last_report.blocks_imported) / dur, @@ -260,7 +270,7 @@ impl Informant { sync_info.num_active_peers, sync_info.num_peers, - sync_info.blocks_received, + sync_info.last_imported_block_number.unwrap_or(chain_info.best_block_number), queue_info.unverified_queue_size, queue_info.verified_queue_size, diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 66688466c..c506d44b3 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -9,13 +9,13 @@ authors = ["Ethcore Result { + match (self.client.block(id.clone()), self.client.block_total_difficulty(id)) { + (Some(bytes), Some(total_difficulty)) => { + let block_view = BlockView::new(&bytes); + let view = block_view.header_view(); + let block = Block { + hash: OptionalValue::Value(view.sha3()), + parent_hash: view.parent_hash(), + uncles_hash: view.uncles_hash(), + author: view.author(), + miner: view.author(), + state_root: view.state_root(), + transactions_root: view.transactions_root(), + receipts_root: view.receipts_root(), + number: OptionalValue::Value(U256::from(view.number())), + gas_used: view.gas_used(), + gas_limit: view.gas_limit(), + logs_bloom: view.log_bloom(), + timestamp: U256::from(view.timestamp()), + difficulty: view.difficulty(), + total_difficulty: total_difficulty, + uncles: vec![], + transactions: { + if include_txs { + BlockTransactions::Full(block_view.localized_transactions().into_iter().map(From::from).collect()) + } else { + BlockTransactions::Hashes(block_view.transaction_hashes()) + } + }, + extra_data: Bytes::default() + }; + to_value(&block) + }, + _ => Ok(Value::Null) + } + } + + fn transaction(&self, id: TransactionId) -> Result { + match self.client.transaction(id) { + Some(t) => to_value(&Transaction::from(t)), + None => Ok(Value::Null) + } + } } impl Eth for EthClient { @@ -110,7 +153,7 @@ impl Eth for EthClient { fn block_transaction_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(&hash) { + .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), None => Ok(Value::Null) }) @@ -118,7 +161,7 @@ impl Eth for EthClient { fn block_uncles_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.block(&hash) { + .and_then(|(hash,)| match self.client.block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), None => Ok(Value::Null) }) @@ -130,62 +173,29 @@ impl Eth for EthClient { .and_then(|(address, _block_number)| to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new))) } - fn block(&self, params: Params) -> Result { + fn block_by_hash(&self, params: Params) -> Result { from_params::<(H256, bool)>(params) - .and_then(|(hash, include_txs)| match (self.client.block(&hash), self.client.block_total_difficulty(&hash)) { - (Some(bytes), Some(total_difficulty)) => { - let block_view = BlockView::new(&bytes); - let view = block_view.header_view(); - let block = Block { - hash: OptionalValue::Value(view.sha3()), - parent_hash: view.parent_hash(), - uncles_hash: view.uncles_hash(), - author: view.author(), - miner: view.author(), - state_root: view.state_root(), - transactions_root: view.transactions_root(), - receipts_root: view.receipts_root(), - number: OptionalValue::Value(U256::from(view.number())), - gas_used: view.gas_used(), - gas_limit: view.gas_limit(), - logs_bloom: view.log_bloom(), - timestamp: U256::from(view.timestamp()), - difficulty: view.difficulty(), - total_difficulty: total_difficulty, - uncles: vec![], - transactions: { - if include_txs { - BlockTransactions::Full(block_view.localized_transactions().into_iter().map(From::from).collect()) - } else { - BlockTransactions::Hashes(block_view.transaction_hashes()) - } - }, - extra_data: Bytes::default() - }; - to_value(&block) - }, - _ => Ok(Value::Null) - }) + .and_then(|(hash, include_txs)| self.block(BlockId::Hash(hash), include_txs)) + } + + fn block_by_number(&self, params: Params) -> Result { + from_params::<(BlockNumber, bool)>(params) + .and_then(|(number, include_txs)| self.block(number.into(), include_txs)) } fn transaction_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.transaction(TransactionId::Hash(hash)) { - Some(t) => to_value(&Transaction::from(t)), - None => Ok(Value::Null) - }) + .and_then(|(hash,)| self.transaction(TransactionId::Hash(hash))) } fn transaction_by_block_hash_and_index(&self, params: Params) -> Result { from_params::<(H256, Index)>(params) - .and_then(|(hash, index)| match self.client.transaction(TransactionId::Location(BlockId::Hash(hash), index.value())) { - Some(t) => to_value(&Transaction::from(t)), - None => Ok(Value::Null) - }) + .and_then(|(hash, index)| self.transaction(TransactionId::Location(BlockId::Hash(hash), index.value()))) } - fn transaction_by_block_number_and_index(&self, _params: Params) -> Result { - unimplemented!() + fn transaction_by_block_number_and_index(&self, params: Params) -> Result { + from_params::<(BlockNumber, Index)>(params) + .and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value()))) } } diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 640af1f82..d2aeb0f9e 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -50,8 +50,11 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns content of the storage at given address. fn storage_at(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns block with given index / hash. - fn block(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns block with given hash. + fn block_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns block with given number. + fn block_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns the number of transactions sent from given address at given time (block number). fn transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -135,8 +138,8 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_sendTransaction", Eth::send_transaction); delegate.add_method("eth_call", Eth::call); delegate.add_method("eth_estimateGas", Eth::estimate_gas); - delegate.add_method("eth_getBlockByHash", Eth::block); - delegate.add_method("eth_getBlockByNumber", Eth::block); + delegate.add_method("eth_getBlockByHash", Eth::block_by_hash); + delegate.add_method("eth_getBlockByNumber", Eth::block_by_number); delegate.add_method("eth_getTransactionByHash", Eth::transaction_by_hash); delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_by_block_hash_and_index); delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_by_block_number_and_index); diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index bfe20f177..b524d8450 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -16,6 +16,7 @@ use serde::{Deserialize, Deserializer, Error}; use serde::de::Visitor; +use ethcore::client::BlockId; /// Represents rpc api block number param. #[derive(Debug, PartialEq)] @@ -53,8 +54,20 @@ impl Visitor for BlockNumberVisitor { } } +impl Into for BlockNumber { + fn into(self) -> BlockId { + match self { + BlockNumber::Num(n) => BlockId::Number(n), + BlockNumber::Earliest => BlockId::Earliest, + BlockNumber::Latest => BlockId::Latest, + BlockNumber::Pending => BlockId::Latest // TODO: change this once blockid support pending + } + } +} + #[cfg(test)] mod tests { + use ethcore::client::BlockId; use super::*; use serde_json; @@ -64,5 +77,13 @@ mod tests { let deserialized: Vec = serde_json::from_str(s).unwrap(); assert_eq!(deserialized, vec![BlockNumber::Num(10), BlockNumber::Num(10), BlockNumber::Latest, BlockNumber::Earliest, BlockNumber::Pending]) } + + #[test] + fn block_number_into() { + assert_eq!(BlockId::Number(100), BlockNumber::Num(100).into()); + assert_eq!(BlockId::Earliest, BlockNumber::Earliest.into()); + assert_eq!(BlockId::Latest, BlockNumber::Latest.into()); + assert_eq!(BlockId::Latest, BlockNumber::Pending.into()); + } } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 75853e0ab..8eb6a1bee 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore { self.have_common_block = true; self.last_imported_block = Some(number); @@ -491,7 +491,7 @@ impl ChainSync { for (rh, rd) in hashes { let h = try!(rh); let d = try!(rd); - match io.chain().block_status(&h) { + match io.chain().block_status(BlockId::Hash(h.clone())) { BlockStatus::InChain => { trace!(target: "sync", "New block hash already in chain {:?}", h); }, @@ -583,7 +583,7 @@ impl ChainSync { trace!(target: "sync", "Starting sync with better chain"); self.request_headers_by_hash(io, peer_id, &peer_latest, 1, 0, false); } - else if self.state == SyncState::Blocks { + else if self.state == SyncState::Blocks && io.chain().block_status(BlockId::Hash(peer_latest)) == BlockStatus::Unknown { self.request_blocks(io, peer_id); } } @@ -607,7 +607,7 @@ impl ChainSync { if self.have_common_block && !self.headers.is_empty() && self.headers.range_iter().next().unwrap().0 == self.current_base_block() + 1 { for (start, ref items) in self.headers.range_iter() { - if needed_bodies.len() > MAX_BODIES_TO_REQUEST { + if needed_bodies.len() >= MAX_BODIES_TO_REQUEST { break; } let mut index: BlockNumber = 0; @@ -654,7 +654,7 @@ impl ChainSync { continue; } let mut block = prev; - while block < next && headers.len() <= MAX_HEADERS_TO_REQUEST { + while block < next && headers.len() < MAX_HEADERS_TO_REQUEST { if !self.downloading_headers.contains(&(block as BlockNumber)) { headers.push(block as BlockNumber); self.downloading_headers.insert(block as BlockNumber); @@ -877,7 +877,7 @@ impl ChainSync { // id is a hash let hash: H256 = try!(r.val_at(0)); trace!(target: "sync", "-> GetBlockHeaders (hash: {}, max: {}, skip: {}, reverse:{})", hash, max_headers, skip, reverse); - match io.chain().block_header(&hash) { + match io.chain().block_header(BlockId::Hash(hash)) { Some(hdr) => From::from(HeaderView::new(&hdr).number()), None => last } @@ -897,7 +897,7 @@ impl ChainSync { let mut data = Bytes::new(); let inc = (skip + 1) as BlockNumber; while number <= last && number > 0 && count < max_count { - if let Some(mut hdr) = io.chain().block_header_at(number) { + if let Some(mut hdr) = io.chain().block_header(BlockId::Number(number)) { data.append(&mut hdr); count += 1; } @@ -929,7 +929,7 @@ impl ChainSync { let mut added = 0usize; let mut data = Bytes::new(); for i in 0..count { - if let Some(mut hdr) = io.chain().block_body(&try!(r.val_at::(i))) { + if let Some(mut hdr) = io.chain().block_body(BlockId::Hash(try!(r.val_at::(i)))) { data.append(&mut hdr); added += 1; } @@ -1045,7 +1045,7 @@ impl ChainSync { fn check_resume(&mut self, io: &mut SyncIo) { if !io.chain().queue_info().is_full() && self.state == SyncState::Waiting { - self.state = SyncState::Idle; + self.state = SyncState::Blocks; self.continue_sync(io); } } @@ -1060,7 +1060,8 @@ 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(&block_hash).expect("Mallformed block without a difficulty on the chain!"); + let difficulty = chain.block_total_difficulty(BlockId::Hash(block_hash.clone())).expect("Mallformed block without a difficulty on the chain!"); + hash_rlp.append(&block_hash); hash_rlp.append(&difficulty); rlp_stream.append_raw(&hash_rlp.out(), 1); @@ -1076,7 +1077,7 @@ impl ChainSync { /// creates latest block rlp for the given client fn create_latest_block_rlp(chain: &BlockChainClient) -> Bytes { let mut rlp_stream = RlpStream::new_list(2); - rlp_stream.append_raw(&chain.block(&chain.chain_info().best_block_hash).expect("Creating latest block when there is none"), 1); + rlp_stream.append_raw(&chain.block(BlockId::Hash(chain.chain_info().best_block_hash)).expect("Creating latest block when there is none"), 1); rlp_stream.append(&chain.chain_info().total_difficulty); rlp_stream.out() } @@ -1088,10 +1089,10 @@ impl ChainSync { let latest_hash = chain_info.best_block_hash; let latest_number = chain_info.best_block_number; self.peers.iter().filter(|&(_, peer_info)| - match io.chain().block_status(&peer_info.latest) + match io.chain().block_status(BlockId::Hash(peer_info.latest.clone())) { BlockStatus::InChain => { - let peer_number = HeaderView::new(&io.chain().block_header(&peer_info.latest).unwrap()).number(); + let peer_number = HeaderView::new(&io.chain().block_header(BlockId::Hash(peer_info.latest.clone())).unwrap()).number(); peer_info.latest != latest_hash && latest_number > peer_number && latest_number - peer_number < MAX_PEER_LAG_PROPAGATION }, _ => false @@ -1478,4 +1479,4 @@ mod tests { let result = sync.on_peer_new_block(&mut io, 0, &UntrustedRlp::new(&data)); assert!(result.is_ok()); } -} \ No newline at end of file +} diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index c70bac4ca..a07f85a7f 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -40,7 +40,7 @@ pub trait RangeCollection { fn get_tail(&mut self, key: &K) -> Range; /// Remove all elements < `start` in the range that contains `start` - 1 fn remove_head(&mut self, start: &K); - /// Remove all elements >= `start` in the range that contains `start` + /// Remove all elements >= `start` in the range that contains `start` fn remove_tail(&mut self, start: &K); /// Remove all elements >= `tail` fn insert_item(&mut self, key: K, value: V); @@ -168,6 +168,7 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + fn insert_item(&mut self, key: K, value: V) { assert!(!self.have_item(&key)); + // todo: fix warning let lower = match self.binary_search_by(|&(k, _)| k.cmp(&key).reverse()) { Ok(index) => index, Err(index) => index, diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 6526d8500..f560f4ca6 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient}; +use ethcore::client::{BlockChainClient, BlockId}; use io::SyncIo; use chain::{SyncState}; use super::helpers::*; @@ -27,7 +27,7 @@ fn two_peers() { net.peer_mut(1).chain.add_blocks(1000, false); net.peer_mut(2).chain.add_blocks(1000, false); net.sync(); - assert!(net.peer(0).chain.block_at(1000).is_some()); + assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); } @@ -60,7 +60,7 @@ fn empty_blocks() { net.peer_mut(2).chain.add_blocks(5, n % 2 == 0); } net.sync(); - assert!(net.peer(0).chain.block_at(1000).is_some()); + assert!(net.peer(0).chain.block(BlockId::Number(1000)).is_some()); assert_eq!(net.peer(0).chain.blocks.read().unwrap().deref(), net.peer(1).chain.blocks.read().unwrap().deref()); } @@ -148,4 +148,4 @@ fn propagade_blocks() { assert!(!net.peer(0).queue.is_empty()); // NEW_BLOCK_PACKET assert_eq!(0x07, net.peer(0).queue[0].packet_id); -} \ No newline at end of file +} diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index f8c08dc93..d8cd5e54a 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo}; +use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId}; use ethcore::block_queue::BlockQueueInfo; use ethcore::header::{Header as BlockHeader, BlockNumber}; use ethcore::error::*; @@ -23,7 +23,6 @@ use io::SyncIo; use chain::{ChainSync}; use ethcore::receipt::Receipt; use ethcore::transaction::LocalizedTransaction; -use ethcore::blockchain::TransactionId; pub struct TestBlockChainClient { pub blocks: RwLock>, @@ -77,10 +76,19 @@ impl TestBlockChainClient { let index = blocks_read.len() - delta; blocks_read[&index].clone() } + + fn block_hash(&self, id: BlockId) -> Option { + match id { + BlockId::Hash(hash) => Some(hash), + BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), + BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), + BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() + } + } } impl BlockChainClient for TestBlockChainClient { - fn block_total_difficulty(&self, _h: &H256) -> Option { + fn block_total_difficulty(&self, _id: BlockId) -> Option { Some(U256::zero()) } @@ -92,51 +100,28 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn block_header(&self, h: &H256) -> Option { - self.blocks.read().unwrap().get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec()) + fn block_header(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) } - fn block_body(&self, h: &H256) -> Option { - self.blocks.read().unwrap().get(h).map(|r| { + fn block_body(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { let mut stream = RlpStream::new_list(2); stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); stream.out() - }) + })) } - fn block(&self, h: &H256) -> Option { - self.blocks.read().unwrap().get(h).cloned() + fn block(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) } - fn block_status(&self, h: &H256) -> BlockStatus { - match self.blocks.read().unwrap().get(h) { - Some(_) => BlockStatus::InChain, - None => BlockStatus::Unknown - } - } - - fn block_total_difficulty_at(&self, _number: BlockNumber) -> Option { - unimplemented!(); - } - - fn block_header_at(&self, n: BlockNumber) -> Option { - self.numbers.read().unwrap().get(&(n as usize)).and_then(|h| self.block_header(h)) - } - - fn block_body_at(&self, n: BlockNumber) -> Option { - self.numbers.read().unwrap().get(&(n as usize)).and_then(|h| self.block_body(h)) - } - - fn block_at(&self, n: BlockNumber) -> Option { - self.numbers.read().unwrap().get(&(n as usize)).map(|h| self.blocks.read().unwrap().get(h).unwrap().clone()) - } - - fn block_status_at(&self, n: BlockNumber) -> BlockStatus { - if (n as usize) < self.blocks.read().unwrap().len() { - BlockStatus::InChain - } else { - BlockStatus::Unknown + fn block_status(&self, id: BlockId) -> BlockStatus { + match id { + BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, + BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, + _ => BlockStatus::Unknown } } diff --git a/util/Cargo.toml b/util/Cargo.toml index 733b08701..b1e9bbc1e 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -26,7 +26,7 @@ crossbeam = "0.2" slab = { git = "https://github.com/arkpar/slab.git" } sha3 = { path = "sha3" } serde = "0.6.7" -clippy = "0.0.37" +clippy = "0.0.41" json-tests = { path = "json-tests" } target_info = "0.1.0" igd = "0.4.2" diff --git a/util/benches/trie.rs b/util/benches/trie.rs index 2c07dbc08..8c573e170 100644 --- a/util/benches/trie.rs +++ b/util/benches/trie.rs @@ -17,7 +17,6 @@ #![feature(test)] extern crate test; -extern crate rand; extern crate ethcore_util; #[macro_use] extern crate log; diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 405646887..596265cd0 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -74,7 +74,6 @@ impl From<::secp256k1::Error> for CryptoError { match e { ::secp256k1::Error::InvalidMessage => CryptoError::InvalidMessage, ::secp256k1::Error::InvalidPublicKey => CryptoError::InvalidPublic, - ::secp256k1::Error::InvalidSignature => CryptoError::InvalidSignature, ::secp256k1::Error::InvalidSecretKey => CryptoError::InvalidSecret, _ => CryptoError::InvalidSignature, } diff --git a/util/src/hash.rs b/util/src/hash.rs index 75c39720e..2e6c565b4 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -296,7 +296,7 @@ macro_rules! impl_hash { try!(write!(f, "{:02x}", i)); } try!(write!(f, "…")); - for i in &self.0[$size - 4..$size] { + for i in &self.0[$size - 2..$size] { try!(write!(f, "{:02x}", i)); } Ok(()) @@ -647,7 +647,7 @@ mod tests { fn hash() { let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); - assert_eq!(format!("{}", h), "0123…89abcdef"); + assert_eq!(format!("{}", h), "0123…cdef"); assert_eq!(format!("{:?}", h), "0123456789abcdef"); assert_eq!(h.hex(), "0123456789abcdef"); assert!(h == h); diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index d9d7b29cf..7b810639b 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -47,10 +47,10 @@ impl Clone for JournalDB { } } -const LAST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; +const LATEST_ERA_KEY : [u8; 4] = [ b'l', b'a', b's', b't' ]; const VERSION_KEY : [u8; 4] = [ b'j', b'v', b'e', b'r' ]; -const DB_VERSION: u32 = 1; +const DB_VERSION: u32 = 2; impl JournalDB { /// Create a new instance given a `backing` database. @@ -87,7 +87,7 @@ impl JournalDB { /// Check if this database has any commits pub fn is_empty(&self) -> bool { - self.backing.get(&LAST_ERA_KEY).expect("Low level database error").is_none() + self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() } /// Commit all recent insert operations and historical removals from the old era @@ -144,6 +144,7 @@ impl JournalDB { r.append(&inserts); r.append(&removes); try!(batch.put(&last, r.as_raw())); + try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); } // apply old commits' details @@ -181,7 +182,6 @@ impl JournalDB { try!(batch.delete(&h)); deletes += 1; } - try!(batch.put(&LAST_ERA_KEY, &encode(&end_era))); trace!("JournalDB: delete journal for time #{}.{}, (canon was {}): {} entries", end_era, index, canon_id, deletes); } @@ -228,8 +228,8 @@ impl JournalDB { fn read_counters(db: &DB) -> HashMap { let mut res = HashMap::new(); - if let Some(val) = db.get(&LAST_ERA_KEY).expect("Low-level database error.") { - let mut era = decode::(&val) + 1; + if let Some(val) = db.get(&LATEST_ERA_KEY).expect("Low-level database error.") { + let mut era = decode::(&val); loop { let mut index = 0usize; while let Some(rlp_data) = db.get({ @@ -245,10 +245,10 @@ impl JournalDB { } index += 1; }; - if index == 0 { + if index == 0 || era == 0 { break; } - era += 1; + era -= 1; } } trace!("Recovered {} counters", res.len()); @@ -426,4 +426,32 @@ mod tests { jdb.commit(2, &b"2a".sha3(), Some((1, b"1a".sha3()))).unwrap(); assert!(jdb.exists(&foo)); } + + #[test] + fn reopen() { + use rocksdb::DB; + let mut dir = ::std::env::temp_dir(); + dir.push(H32::random().hex()); + + let foo = { + let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); + // history is 1 + let foo = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + foo + }; + + { + let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); + jdb.remove(&foo); + jdb.commit(1, &b"1".sha3(), Some((0, b"0".sha3()))).unwrap(); + } + + { + let mut jdb = JournalDB::new(DB::open_default(dir.to_str().unwrap()).unwrap()); + assert!(jdb.exists(&foo)); + jdb.commit(2, &b"2".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert!(!jdb.exists(&foo)); + } + } } diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 32370b88d..3e914761d 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -211,7 +211,7 @@ impl Discovery { } let mut ret:Vec<&NodeId> = Vec::new(); - for (_, nodes) in found { + for nodes in found.values() { for n in nodes { if ret.len() < BUCKET_SIZE as usize /* && n->endpoint && n->endpoint.isAllowed() */ { ret.push(n); diff --git a/util/src/network/host.rs b/util/src/network/host.rs index fb1e8e1df..c1423dbb3 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -412,7 +412,7 @@ impl Host where Message: Send + Sync + Clone { let mut to_kill = Vec::new(); for e in self.connections.write().unwrap().iter_mut() { if let ConnectionEntry::Session(ref mut s) = *e.lock().unwrap().deref_mut() { - if !s.keep_alive() { + if !s.keep_alive(io) { s.disconnect(DisconnectReason::PingTimeout); to_kill.push(s.token()); } diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 8e9a3a9ff..c4ebe7a2a 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -180,7 +180,7 @@ impl Session { } /// Keep this session alive. Returns false if ping timeout happened - pub fn keep_alive(&mut self) -> bool { + pub fn keep_alive(&mut self, io: &IoContext) -> bool where Message: Send + Sync + Clone { let timed_out = if let Some(pong) = self.pong_time_ns { pong - self.ping_time_ns > PING_TIMEOUT_SEC * 1000_000_000 } else { @@ -191,6 +191,7 @@ impl Session { if let Err(e) = self.send_ping() { debug!("Error sending ping message: {:?}", e); } + io.update_registration(self.token()).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); } !timed_out } @@ -324,7 +325,7 @@ impl Session { let mut rlp = RlpStream::new(); rlp.append(&(PACKET_DISCONNECT as u32)); rlp.begin_list(1); - rlp.append(&(reason.clone() as u32)); + rlp.append(&(reason as u32)); self.connection.send_packet(&rlp.out()).ok(); NetworkError::Disconnect(reason) } diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 7126e868d..463d5cb2f 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -408,7 +408,7 @@ impl Decodable for Vec { fn decode(decoder: &D) -> Result where D: Decoder { decoder.read_value(| bytes | { let mut res = vec![]; - res.extend(bytes); + res.extend_from_slice(bytes); Ok(res) }) } diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index b6cc81137..e7884a177 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -293,7 +293,7 @@ impl<'a> Iterator for TrieDBIterator<'a> { fn next(&mut self) -> Option { let b = match self.trail.last_mut() { - Some(ref mut b) => { b.increment(); b.clone() }, + Some(mut b) => { b.increment(); b.clone() }, None => return None }; match (b.status, b.node) { @@ -309,9 +309,8 @@ impl<'a> Iterator for TrieDBIterator<'a> { self.trail.pop(); self.next() }, - (Status::At, Node::Leaf(_, v)) => Some((self.key(), v)), + (Status::At, Node::Leaf(_, v)) | (Status::At, Node::Branch(_, Some(v))) => Some((self.key(), v)), (Status::At, Node::Extension(_, d)) => self.descend_next(d), - (Status::At, Node::Branch(_, Some(v))) => Some((self.key(), v)), (Status::At, Node::Branch(_, _)) => self.next(), (Status::AtChild(i), Node::Branch(children, _)) if children[i].len() > 0 => { match i {