diff --git a/.travis.yml b/.travis.yml index 2663d0d8e..7589697af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,13 @@ language: rust branches: only: - master + - /^beta-.*$/ + - /^stable-.*$/ matrix: fast_finish: true include: - rust: nightly - env: FEATURES="--features ethcore/json-tests" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" + env: FEATURES="--features ethcore/json-tests" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" cache: apt: true directories: @@ -30,6 +32,7 @@ script: - cargo build --release --verbose ${FEATURES} - cargo test --release --verbose ${FEATURES} ${TARGETS} - cargo bench --no-run ${FEATURES} ${TARGETS} +- tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity after_success: | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. && @@ -46,10 +49,18 @@ after_success: | cargo doc --no-deps --verbose ${KCOV_FEATURES} ${TARGETS} && echo '' > target/doc/index.html && pip install --user ghp-import && - /home/travis/.local/bin/ghp-import -n target/doc - #&& - #git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages + /home/travis/.local/bin/ghp-import -n target/doc && + git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages env: global: - secure: 3sUjNi9mhdL5h1GTm8LONnDN/SYvUHT+WSkMl93h3nYiLCQXk8eZaPS98AS7oOaTsfW4UvnwckVFCFl49ttInsv4cd/TkAxmrJHe6kPyS9/4NWUdmP8BjicbBvL/ioSdXMECMEYzPDLV+I3KhtC2LcB6ceDEl/XwMOJlzbGf7RbtcXGVQgMLqSYY1YKjQA4vbT5nFgIS/sZu3Z9yFgN0GafnihKcizqoHhdJjs/zxmX+qJepnC6o3V6KcFnS7QHhM1JOr85twE6S422UlvNaEb5ovwLPqmOl5+fA+6shbx4AxFTY6E9Iors+OVY/JliFhrqOdCt0i2P1FUHN4kbGZQkf0rphN/ZOI2uKNFTOyXiPvppfo/ZemKmcqkwkqP9+lf5QqYmtE6hsAYagxn49xJZILl8tAYbdqxF5gxa+TEVrfsBFtz/Sv3q8QhKQNPAmjEcKyMatyEreLUIFEpFTGIco8jN4eXeSoLRdJ+Z75ihttfQWhNfUDgNL30iQLy0AgFSsh/cyb5M8y9lxrGDzDTogvaiKGwr/V45sPkcXWCkmOgMdINqBB6ZtdL3bGHdyjmYj+y3btjf3aP11k++BL0fXIaKn25aS/p/9iyGb1FyGCM03o4ZRQ3YhTOvfMRfRGf6nWbaMx9upv8o5ShSdysewhrnh3082r7u896ny1Ho= - secure: 0/FeVvFl3AhBW0TCPoujY9zOAYoUNMlAz3XjC04vlc4Ksfx0lGU3KFi97LlALxMWV0lfwQc7ixSe2vTgQVQuLVSU9XEW40fQgEjJlmLca2RcRx1kfzJDypuWSiCME7MWmLPH0ac4COdTDS1z5WGggv5YB7GQPCzFvcmOOaPYtF29ngCtkyB2HmNkY/W3omHFEk7Si6bsmOSHZiOAhivPl6ixnGpFyTEKPyraMMqPIj5rbEGkzgeLTiXf2ur143n/tnSr8tmP1MfQi9yS8/ONidMqnxUeuLkeNnb82zj9pVJhVXq0xF44WXJ8Za1jm0ByiTakgqpm8Juk822qjvtNulJ1XZW/fyZQZaN1dy3uq5Ud3W8wS9M7VIVl8CoXozzDpIsdPeUAtkAxeHBsZqL1vAH2yC1YJA7HPySMYzCjYqkJ2r62xYk0gXmNXphfU+F/X/rHzHsTMJPONJ54HQwu12m7zVlKIYBGHgEXg/HAM/g4ljUzl6WWR/nHH/tQM8ND/8FpHluJSZJWacq/1QNhVdTq2x6cqws2fs5A7nVpccR9+6RRgYgv6+YS2LxvFzByuZveGGoKif+uMECXN876j40araUqU528Yz9i8bHJlnM3coRBndaLNWByLcUyXCB9r9IUosUu41rr+L2mVzkSDm0GicuNCzqvzYQ9Q6QY4uQ= + +deploy: + provider: releases + api_key: + secure: "t+oGT/4lsy7IScw5s86Dpntl5Nyck4qG6nhHwMScc6FYzwLldgwgJaafL8Ej+HG+b7nFLriN+Snoa4YQ5o74X5ZlSWubVREOYQlL/fq7vcPB0DwAZ0Jufq1QW2R1M+3SwwF1eAwTv2W3G7A2K7dxjCVvENcy/gdxnZ36NeUPsqaCC9UcI2Yc7+4jyQwvx6ZfBvQeu+HbKENA0eUNs2ZQOID/1IPy0LJBvSyxAQYsysXdjTzGdNu4+Iba20E8uWYe4fAbgz+gwGarXg1L6D6gKyMlWkViqWjvXWBuDJJqMQZ3rw41AwZOoh3mKd2Lc0l6l4oZcEqPuob0yKTNjz1tuJy9xKTC2F2bDzsvUgk1IRfMK5ukXXXS09ZCZWuA9/GtnsqJ1xGTiwX+DhQzpVBHaBiseSNlYE1YN/3jNyGY+iSts1qut+1BwE7swmcTLsAPoAy8Ue+f7ErNoCg1lm71vq7VO2DLn7x2NqHyHUEuJ+7olDHSdE84G7d9otDRu/+TfMOw7GXwTaha6yJRInuNsnj4CFMLNVvYACzCC2idB7f7nUZoSFi9jf18S9fCMPVmazMrFj4g95HWrVHkjpV5zRTeUdTWw6DJl6pC9HFqORHdCvLv4Rc4dm5r3CmOcAQ0ZuiccV2oKzw4/Wic96daae8M5f5KSQ/WTr+h0wXZKp0=" + skip_cleanup: true + file: parity${ARCHIVE_SUFFIX}.tar.gz + on: + tags: true diff --git a/README.md b/README.md index f442338db..c223921f1 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,9 @@ [coveralls-image]: https://coveralls.io/repos/github/ethcore/parity/badge.svg?branch=master&t=Fk0OuQ [coveralls-url]: https://coveralls.io/r/ethcore/parity?branch=master - ### Building from source -##### Ubuntu 14.04 and later +##### Ubuntu 14.04 ```bash # install rocksdb @@ -22,10 +21,8 @@ apt-get install -y --force-yes librocksdb curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes # install nightly and make it default -multirust update nightly && multirust default nightly - -# export rust LIBRARY_PATH -export LIBRARY_PATH=/usr/local/lib +multirust update nightly +multirust default nightly # download and build parity git clone https://github.com/ethcore/parity @@ -33,7 +30,31 @@ cd parity cargo build --release ``` -##### OSX +##### Linux + +```bash +# install rocksdb +git clone --tag v4.1 --depth=1 https://github.com/facebook/rocksdb.git +cd rocksdb +make shared_lib +sudo cp -a librocksdb.so* /usr/lib +sudo ldconfig +cd .. + +# install rust nightly +curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes + +# install nightly and make it default +sudo multirust update nightly +sudo multirust default nightly + +# download and build parity +git clone https://github.com/ethcore/parity +cd parity +cargo build --release +``` + +##### OSX with Homebrew ```bash # install rocksdb && multirust @@ -44,9 +65,6 @@ brew install multirust # install nightly and make it default multirust update nightly && multirust default nightly -# export rust LIBRARY_PATH -export LIBRARY_PATH=/usr/local/lib - # download and build parity git clone https://github.com/ethcore/parity cd parity diff --git a/doc.sh b/doc.sh new file mode 100755 index 000000000..2fd5ac20f --- /dev/null +++ b/doc.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# generate documentation only for partiy and ethcore libraries + +cargo doc --no-deps --verbose -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index d9c80f3a3..be7652e17 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -10,12 +10,10 @@ authors = ["Ethcore "] log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" -flate2 = "0.2" rocksdb = "0.3" heapsize = "0.2.0" rust-crypto = "0.2.34" time = "0.1" -#interpolate_idents = { git = "https://github.com/SkylerLipthay/interpolate_idents" } ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index 409637d6f..63f86b171 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -1,3 +1,5 @@ +//! Single account in the system. + use util::*; use pod_account::*; @@ -19,6 +21,7 @@ pub struct Account { } impl Account { + #[cfg(test)] /// General constructor. pub fn new(balance: U256, nonce: U256, storage: HashMap, code: Bytes) -> Account { Account { @@ -31,6 +34,8 @@ impl Account { } } + #[cfg(test)] + #[cfg(feature = "json-tests")] /// General constructor. pub fn from_pod(pod: PodAccount) -> Account { Account { @@ -81,15 +86,8 @@ impl Account { } } - /// Reset this account to the status of a not-yet-initialised contract. - /// NOTE: Account should have `init_code()` called on it later. - pub fn reset_code(&mut self) { - self.code_hash = None; - self.code_cache = vec![]; - } - /// Set this account's code to the given code. - /// NOTE: Account should have been created with `new_contract()` or have `reset_code()` called on it. + /// NOTE: Account should have been created with `new_contract()` pub fn init_code(&mut self, code: Bytes) { assert!(self.code_hash.is_none()); self.code_cache = code; @@ -113,6 +111,7 @@ impl Account { /// return the nonce associated with this account. pub fn nonce(&self) -> &U256 { &self.nonce } + #[cfg(test)] /// return the code hash associated with this account. pub fn code_hash(&self) -> H256 { self.code_hash.clone().unwrap_or(SHA3_EMPTY) @@ -129,6 +128,7 @@ impl Account { } } + #[cfg(test)] /// Provide a byte array which hashes to the `code_hash`. returns the hash as a result. pub fn note_code(&mut self, code: Bytes) -> Result<(), H256> { let h = code.sha3(); @@ -163,18 +163,14 @@ impl Account { } } - /// return the storage root associated with this account. - pub fn base_root(&self) -> &H256 { &self.storage_root } - + #[cfg(test)] /// Determine whether there are any un-`commit()`-ed storage-setting operations. pub fn storage_is_clean(&self) -> bool { self.storage_overlay.borrow().iter().find(|&(_, &(f, _))| f == Filth::Dirty).is_none() } + #[cfg(test)] /// return the storage root associated with this account or None if it has been altered via the overlay. pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} } - /// return the storage root associated with this account or None if it has been altered via the overlay. - pub fn recent_storage_root(&self) -> &H256 { &self.storage_root } - /// return the storage overlay. pub fn storage_overlay(&self) -> Ref> { self.storage_overlay.borrow() } diff --git a/ethcore/src/account_diff.rs b/ethcore/src/account_diff.rs index 1843c4381..86faf40de 100644 --- a/ethcore/src/account_diff.rs +++ b/ethcore/src/account_diff.rs @@ -1,15 +1,18 @@ +//! Diff between two accounts. + use util::*; +#[cfg(test)] use pod_account::*; #[derive(Debug,Clone,PartialEq,Eq)] /// Change in existance type. // TODO: include other types of change. pub enum Existance { - /// TODO [Gav Wood] Please document me + /// Item came into existance. Born, - /// TODO [Gav Wood] Please document me + /// Item stayed in existance. Alive, - /// TODO [Gav Wood] Please document me + /// Item went out of existance. Died, } @@ -25,20 +28,20 @@ impl fmt::Display for Existance { } #[derive(Debug,Clone,PartialEq,Eq)] -/// TODO [Gav Wood] Please document me +/// Account diff. pub struct AccountDiff { - /// TODO [Gav Wood] Please document me - pub balance: Diff, // Allowed to be Same - /// TODO [Gav Wood] Please document me + /// Change in balance, allowed to be `Diff::Same`. + pub balance: Diff, + /// Change in nonce, allowed to be `Diff::Same`. pub nonce: Diff, // Allowed to be Same - /// TODO [Gav Wood] Please document me + /// Change in code, allowed to be `Diff::Same`. pub code: Diff, // Allowed to be Same - /// TODO [Gav Wood] Please document me - pub storage: BTreeMap>,// Not allowed to be Same + /// Change in storage, values are not allowed to be `Diff::Same`. + pub storage: BTreeMap>, } impl AccountDiff { - /// TODO [Gav Wood] Please document me + /// Get `Existance` projection. pub fn existance(&self) -> Existance { match self.balance { Diff::Born(_) => Existance::Born, @@ -47,7 +50,9 @@ impl AccountDiff { } } - /// TODO [Gav Wood] Please document me + #[cfg(test)] + /// Determine difference between two optionally existant `Account`s. Returns None + /// if they are the same. pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option { match (pre, post) { (None, Some(x)) => Some(AccountDiff { diff --git a/ethcore/src/basic_types.rs b/ethcore/src/basic_types.rs index 3d6fc2609..49a5c9556 100644 --- a/ethcore/src/basic_types.rs +++ b/ethcore/src/basic_types.rs @@ -1,3 +1,5 @@ +//! Ethcore basic typenames. + use util::*; /// Type for a 2048-bit log-bloom, as used by our blocks. @@ -6,10 +8,10 @@ pub type LogBloom = H2048; /// Constant 2048-bit datum for 0. Often used as a default. pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); -/// TODO [Gav Wood] Please document me +/// Semantic boolean for when a seal/signature is included. pub enum Seal { - /// TODO [Gav Wood] Please document me + /// The seal/signature is included. With, - /// TODO [Gav Wood] Please document me + /// The seal/signature is not included. Without, } diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index f8e8ef16f..a2de89d13 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -1,3 +1,5 @@ +//! Blockchain block. + #![allow(ptr_arg)] // Because of &LastHashes -> &Vec<_> use common::*; @@ -18,7 +20,7 @@ pub struct Block { } impl Block { - /// Returns true iff the given bytes form a valid encoding of a block in RLP. + /// Returns true if the given bytes form a valid encoding of a block in RLP. // TODO: implement Decoder for this and have this use that. pub fn is_good(b: &[u8]) -> bool { /* @@ -71,16 +73,15 @@ pub struct ExecutedBlock { /// A set of references to `ExecutedBlock` fields that are publicly accessible. pub struct BlockRefMut<'a> { - /// TODO [Gav Wood] Please document me + /// Block header. pub header: &'a Header, - /// TODO [Gav Wood] Please document me + /// Block transactions. pub transactions: &'a Vec, - /// TODO [Gav Wood] Please document me + /// Block uncles. pub uncles: &'a Vec
, - - /// TODO [Gav Wood] Please document me + /// Transaction receipts. pub receipts: &'a Vec, - /// TODO [Gav Wood] Please document me + /// State. pub state: &'a mut State, } @@ -394,4 +395,4 @@ mod tests { assert_eq!(orig_db.keys(), db.keys()); assert!(orig_db.keys().iter().filter(|k| orig_db.get(k.0) != db.get(k.0)).next() == None); } -} \ No newline at end of file +} diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index dabe047e9..1fe31ba19 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -9,6 +9,7 @@ use engine::Engine; use views::*; use header::*; use service::*; +use client::BlockStatus; /// Block queue status #[derive(Debug)] @@ -41,7 +42,7 @@ pub struct BlockQueue { deleting: Arc, ready_signal: Arc, empty: Arc, - processing: HashSet + processing: RwLock> } struct UnVerifiedBlock { @@ -106,7 +107,7 @@ impl BlockQueue { verification: verification.clone(), verifiers: verifiers, deleting: deleting.clone(), - processing: HashSet::new(), + processing: RwLock::new(HashSet::new()), empty: empty.clone(), } } @@ -196,11 +197,22 @@ impl BlockQueue { } } + /// Check if the block is currently in the queue + pub fn block_status(&self, hash: &H256) -> BlockStatus { + if self.processing.read().unwrap().contains(&hash) { + return BlockStatus::Queued; + } + if self.verification.lock().unwrap().bad.contains(&hash) { + return BlockStatus::Bad; + } + BlockStatus::Unknown + } + /// Add a block to the queue. pub fn import_block(&mut self, bytes: Bytes) -> ImportResult { let header = BlockView::new(&bytes).header(); let h = header.hash(); - if self.processing.contains(&h) { + if self.processing.read().unwrap().contains(&h) { return Err(ImportError::AlreadyQueued); } { @@ -217,7 +229,7 @@ impl BlockQueue { match verify_block_basic(&header, &bytes, self.engine.deref().deref()) { Ok(()) => { - self.processing.insert(h.clone()); + self.processing.write().unwrap().insert(h.clone()); self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes }); self.more_to_verify.notify_all(); Ok(h) @@ -235,10 +247,12 @@ impl BlockQueue { let mut verification_lock = self.verification.lock().unwrap(); let mut verification = verification_lock.deref_mut(); verification.bad.insert(hash.clone()); + self.processing.write().unwrap().remove(&hash); let mut new_verified = VecDeque::new(); for block in verification.verified.drain(..) { if verification.bad.contains(&block.header.parent_hash) { verification.bad.insert(block.header.hash()); + self.processing.write().unwrap().remove(&block.header.hash()); } else { new_verified.push_back(block); @@ -247,6 +261,15 @@ impl BlockQueue { verification.verified = new_verified; } + /// Mark given block as processed + pub fn mark_as_good(&mut self, hashes: &[H256]) { + let mut processing = self.processing.write().unwrap(); + for h in hashes { + processing.remove(&h); + } + //TODO: reward peers + } + /// Removes up to `max` verified blocks from the queue pub fn drain(&mut self, max: usize) -> Vec { let mut verification = self.verification.lock().unwrap(); @@ -254,7 +277,6 @@ impl BlockQueue { let mut result = Vec::with_capacity(count); for _ in 0..count { let block = verification.verified.pop_front().unwrap(); - self.processing.remove(&block.header.hash()); result.push(block); } self.ready_signal.reset(); @@ -294,6 +316,7 @@ mod tests { use block_queue::*; use tests::helpers::*; use error::*; + use views::*; fn get_test_queue() -> BlockQueue { let spec = get_test_spec(); @@ -339,11 +362,14 @@ mod tests { #[test] fn returns_ok_for_drained_duplicates() { let mut queue = get_test_queue(); - if let Err(e) = queue.import_block(get_good_dummy_block()) { + let block = get_good_dummy_block(); + let hash = BlockView::new(&block).header().hash().clone(); + if let Err(e) = queue.import_block(block) { panic!("error importing block that is valid by definition({:?})", e); } queue.flush(); queue.drain(10); + queue.mark_as_good(&[ hash ]); if let Err(e) = queue.import_block(get_good_dummy_block()) { panic!("error importing block that has already been drained ({:?})", e); diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 1dea65ae7..e2ed54c19 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -1,4 +1,4 @@ -//! Fast access to blockchain data. +//! Blockchain database. use util::*; use rocksdb::{DB, WriteBatch, Writable}; @@ -8,33 +8,27 @@ use transaction::*; use views::*; /// Represents a tree route between `from` block and `to` block: -/// -/// - `blocks` - a vector of hashes of all blocks, ordered from `from` to `to`. -/// -/// - `ancestor` - best common ancestor of these blocks. -/// -/// - `index` - an index where best common ancestor would be. pub struct TreeRoute { - /// TODO [debris] Please document me + /// A vector of hashes of all blocks, ordered from `from` to `to`. pub blocks: Vec, - /// TODO [debris] Please document me + /// Best common ancestor of these blocks. pub ancestor: H256, - /// TODO [debris] Please document me + /// An index where best common ancestor would be. pub index: usize } /// Represents blockchain's in-memory cache size in bytes. #[derive(Debug)] pub struct CacheSize { - /// TODO [debris] Please document me + /// Blocks cache size. pub blocks: usize, - /// TODO [debris] Please document me + /// BlockDetails cache size. pub block_details: usize, - /// TODO [debris] Please document me + /// Transaction addresses cache size. pub transaction_addresses: usize, - /// TODO [debris] Please document me + /// Logs cache size. pub block_logs: usize, - /// TODO [debris] Please document me + /// Blooms cache size. pub blocks_blooms: usize } diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 00d0bbeb5..297f734b5 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -63,7 +63,8 @@ impl Builtin { } } -/// TODO [Gav Wood] Please document me +/// Copy a bunch of bytes to a destination; if the `src` is too small to fill `dest`, +/// leave the rest unchanged. pub fn copy_to(src: &[u8], dest: &mut[u8]) { // NICE: optimise for i in 0..min(src.len(), dest.len()) { diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index ee9b658d8..03c03ab49 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -1,3 +1,5 @@ +//! Blockchain database client. + use util::*; use rocksdb::{Options, DB}; use blockchain::{BlockChain, BlockProvider, CacheSize}; @@ -13,9 +15,10 @@ use service::NetSyncMessage; use env_info::LastHashes; use verification::*; use block::*; +pub use blockchain::TreeRoute; /// General block status -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub enum BlockStatus { /// Part of the blockchain. InChain, @@ -48,8 +51,6 @@ impl fmt::Display for BlockChainInfo { } } -/// TODO [arkpar] Please document me -pub type TreeRoute = ::blockchain::TreeRoute; /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -114,18 +115,18 @@ pub trait BlockChainClient : Sync + Send { } #[derive(Default, Clone, Debug, Eq, PartialEq)] -/// TODO [Gav Wood] Please document me +/// Report on the status of a client. pub struct ClientReport { - /// TODO [Gav Wood] Please document me + /// How many blocks have been imported so far. pub blocks_imported: usize, - /// TODO [Gav Wood] Please document me + /// How many transactions have been applied so far. pub transactions_applied: usize, - /// TODO [Gav Wood] Please document me + /// How much gas has been processed so far. pub gas_processed: U256, } impl ClientReport { - /// TODO [Gav Wood] Please document me + /// Alter internal reporting to reflect the additional `block` has been processed. pub fn accrue_block(&mut self, block: &PreVerifiedBlock) { self.blocks_imported += 1; self.transactions_applied += block.transactions.len(); @@ -204,6 +205,7 @@ impl Client { let mut bad = HashSet::new(); let _import_lock = self.import_lock.lock(); let blocks = self.block_queue.write().unwrap().drain(128); + let mut good_blocks = Vec::with_capacity(128); for block in blocks { if bad.contains(&block.header.parent_hash) { self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); @@ -256,6 +258,8 @@ impl Client { break; } + good_blocks.push(header.hash().clone()); + self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { @@ -269,6 +273,7 @@ impl Client { trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); ret += 1; } + self.block_queue.write().unwrap().mark_as_good(&good_blocks); ret } @@ -323,7 +328,11 @@ impl BlockChainClient for Client { } fn block_status(&self, hash: &H256) -> BlockStatus { - if self.chain.read().unwrap().is_known(&hash) { BlockStatus::InChain } else { BlockStatus::Unknown } + if self.chain.read().unwrap().is_known(&hash) { + BlockStatus::InChain + } else { + self.block_queue.read().unwrap().block_status(hash) + } } fn block_total_difficulty(&self, hash: &H256) -> Option { @@ -370,6 +379,9 @@ 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 { + return Err(ImportError::UnknownParent); + } self.block_queue.write().unwrap().import_block(bytes) } diff --git a/ethcore/src/engine.rs b/ethcore/src/engine.rs index 1fb6ef0ca..7017989e7 100644 --- a/ethcore/src/engine.rs +++ b/ethcore/src/engine.rs @@ -31,17 +31,16 @@ pub trait Engine : Sync + Send { /// Some intrinsic operation parameters; by default they take their value from the `spec()`'s `engine_params`. fn maximum_extra_data_size(&self) -> usize { decode(&self.spec().engine_params.get("maximumExtraDataSize").unwrap()) } - /// TODO [Gav Wood] Please document me + /// Maximum number of uncles a block is allowed to declare. fn maximum_uncle_count(&self) -> usize { 2 } - /// TODO [Gav Wood] Please document me + /// The nonce with which accounts begin. fn account_start_nonce(&self) -> U256 { decode(&self.spec().engine_params.get("accountStartNonce").unwrap()) } - /// Block transformation functions, before and after the transactions. + /// Block transformation functions, before the transactions. fn on_new_block(&self, _block: &mut ExecutedBlock) {} - /// TODO [Gav Wood] Please document me + /// Block transformation functions, after the transactions. fn on_close_block(&self, _block: &mut ExecutedBlock) {} - // TODO: consider including State in the params for verification functions. /// Phase 1 quick block verification. Only does checks that are cheap. `block` (the header's full block) /// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import. fn verify_block_basic(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) } @@ -58,7 +57,7 @@ pub trait Engine : Sync + Send { // TODO: Add flags for which bits of the transaction to check. // TODO: consider including State in the params. fn verify_transaction_basic(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) } - /// TODO [Gav Wood] Please document me + /// Verify a particular transaction is valid. fn verify_transaction(&self, _t: &Transaction, _header: &Header) -> Result<(), Error> { Ok(()) } /// Don't forget to call Super::populateFromParent when subclassing & overriding. @@ -67,11 +66,13 @@ pub trait Engine : Sync + Send { // TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic // from Spec into here and removing the Spec::builtins field. - /// TODO [Gav Wood] Please document me + /// Determine whether a particular address is a builtin contract. fn is_builtin(&self, a: &Address) -> bool { self.spec().builtins.contains_key(a) } - /// TODO [Gav Wood] Please document me + /// Determine the code execution cost of the builtin contract with address `a`. + /// Panics if `is_builtin(a)` is not true. fn cost_of_builtin(&self, a: &Address, input: &[u8]) -> U256 { self.spec().builtins.get(a).unwrap().cost(input.len()) } - /// TODO [Gav Wood] Please document me + /// Execution the builtin contract `a` on `input` and return `output`. + /// Panics if `is_builtin(a)` is not true. fn execute_builtin(&self, a: &Address, input: &[u8], output: &mut [u8]) { self.spec().builtins.get(a).unwrap().execute(input, output); } // TODO: sealing stuff - though might want to leave this for later. diff --git a/ethcore/src/env_info.rs b/ethcore/src/env_info.rs index 8b037036e..7c0516d2a 100644 --- a/ethcore/src/env_info.rs +++ b/ethcore/src/env_info.rs @@ -24,13 +24,6 @@ pub struct EnvInfo { pub gas_used: U256, } -impl EnvInfo { - /// Create empty env_info initialized with zeros - pub fn new() -> EnvInfo { - EnvInfo::default() - } -} - impl Default for EnvInfo { fn default() -> Self { EnvInfo { @@ -97,4 +90,4 @@ r#" assert_eq!(default_env_info.difficulty, x!(0)); } -} \ No newline at end of file +} diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 4ca988679..2d6753e95 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -5,22 +5,22 @@ use header::BlockNumber; use basic_types::LogBloom; #[derive(Debug, PartialEq, Eq)] -/// TODO [Gav Wood] Please document me +/// Error indicating an expected value was not found. pub struct Mismatch { - /// TODO [Gav Wood] Please document me + /// Value expected. pub expected: T, - /// TODO [Gav Wood] Please document me + /// Value found. pub found: T, } #[derive(Debug, PartialEq, Eq)] -/// TODO [Gav Wood] Please document me +/// Error indicating value found is outside of a valid range. pub struct OutOfBounds { - /// TODO [Gav Wood] Please document me + /// Minimum allowed value. pub min: Option, - /// TODO [Gav Wood] Please document me + /// Maximum allowed value. pub max: Option, - /// TODO [Gav Wood] Please document me + /// Value found. pub found: T, } @@ -29,11 +29,10 @@ pub struct OutOfBounds { pub enum ExecutionError { /// Returned when there gas paid for transaction execution is /// lower than base gas required. - /// TODO [Gav Wood] Please document me NotEnoughBaseGas { - /// TODO [Gav Wood] Please document me + /// Absolute minimum gas required. required: U256, - /// TODO [Gav Wood] Please document me + /// Gas provided. got: U256 }, /// Returned when block (gas_used + gas) > gas_limit. @@ -41,26 +40,26 @@ pub enum ExecutionError { /// If gas =< gas_limit, upstream may try to execute the transaction /// in next block. BlockGasLimitReached { - /// TODO [Gav Wood] Please document me + /// Gas limit of block for transaction. gas_limit: U256, - /// TODO [Gav Wood] Please document me + /// Gas used in block prior to transaction. gas_used: U256, - /// TODO [Gav Wood] Please document me + /// Amount of gas in block. gas: U256 }, /// Returned when transaction nonce does not match state nonce. InvalidNonce { - /// TODO [Gav Wood] Please document me + /// Nonce expected. expected: U256, - /// TODO [Gav Wood] Please document me + /// Nonce found. got: U256 }, /// Returned when cost of transaction (value + gas_price * gas) exceeds /// current sender balance. NotEnoughCash { - /// TODO [Gav Wood] Please document me + /// Minimum required balance. required: U512, - /// TODO [Gav Wood] Please document me + /// Actual balance. got: U512 }, /// Returned when internal evm error occurs. @@ -68,76 +67,82 @@ pub enum ExecutionError { } #[derive(Debug)] -/// TODO [Gav Wood] Please document me +/// Errors concerning transaction proessing. pub enum TransactionError { - /// TODO [Gav Wood] Please document me + /// Transaction's gas limit (aka gas) is invalid. InvalidGasLimit(OutOfBounds), } #[derive(Debug, PartialEq, Eq)] -/// TODO [arkpar] Please document me +/// Errors concerning block processing. pub enum BlockError { - /// TODO [Gav Wood] Please document me + /// Block has too many uncles. TooManyUncles(OutOfBounds), - /// TODO [Gav Wood] Please document me - UncleWrongGeneration, - /// TODO [Gav Wood] Please document me + /// Extra data is of an invalid length. ExtraDataOutOfBounds(OutOfBounds), - /// TODO [arkpar] Please document me + /// Seal is incorrect format. InvalidSealArity(Mismatch), - /// TODO [arkpar] Please document me + /// Block has too much gas used. TooMuchGasUsed(OutOfBounds), - /// TODO [arkpar] Please document me + /// Uncles hash in header is invalid. InvalidUnclesHash(Mismatch), - /// TODO [arkpar] Please document me + /// An uncle is from a generation too old. UncleTooOld(OutOfBounds), - /// TODO [arkpar] Please document me + /// An uncle is from the same generation as the block. UncleIsBrother(OutOfBounds), - /// TODO [arkpar] Please document me + /// An uncle is already in the chain. UncleInChain(H256), - /// TODO [arkpar] Please document me + /// An uncle has a parent not in the chain. UncleParentNotInChain(H256), - /// TODO [arkpar] Please document me + /// State root header field is invalid. InvalidStateRoot(Mismatch), - /// TODO [arkpar] Please document me + /// Gas used header field is invalid. InvalidGasUsed(Mismatch), - /// TODO [arkpar] Please document me + /// Transactions root header field is invalid. InvalidTransactionsRoot(Mismatch), - /// TODO [arkpar] Please document me + /// Difficulty is out of range; this can be used as an looser error prior to getting a definitive + /// value for difficulty. This error needs only provide bounds of which it is out. + DifficultyOutOfBounds(OutOfBounds), + /// Difficulty header field is invalid; this is a strong error used after getting a definitive + /// value for difficulty (which is provided). InvalidDifficulty(Mismatch), - /// TODO [arkpar] Please document me + /// Seal element of type H256 (max_hash for Ethash, but could be something else for + /// other seal engines) is out of bounds. + MismatchedH256SealElement(Mismatch), + /// Proof-of-work aspect of seal, which we assume is a 256-bit value, is invalid. + InvalidProofOfWork(OutOfBounds), + /// Gas limit header field is invalid. InvalidGasLimit(OutOfBounds), - /// TODO [arkpar] Please document me - InvalidReceiptsStateRoot(Mismatch), - /// TODO [arkpar] Please document me + /// Receipts trie root header field is invalid. + InvalidReceiptsRoot(Mismatch), + /// Timestamp header field is invalid. InvalidTimestamp(OutOfBounds), - /// TODO [arkpar] Please document me + /// Log bloom header field is invalid. InvalidLogBloom(Mismatch), - /// TODO [arkpar] Please document me - InvalidEthashDifficulty(Mismatch), - /// TODO [arkpar] Please document me - InvalidBlockNonce(Mismatch), - /// TODO [arkpar] Please document me + /// Parent hash field of header is invalid; this is an invalid error indicating a logic flaw in the codebase. + /// TODO: remove and favour an assert!/panic!. InvalidParentHash(Mismatch), - /// TODO [arkpar] Please document me + /// Number field of header is invalid. InvalidNumber(Mismatch), /// Block number isn't sensible. RidiculousNumber(OutOfBounds), - /// TODO [arkpar] Please document me + /// Parent given is unknown. UnknownParent(H256), - /// TODO [Gav Wood] Please document me + /// Uncle parent given is unknown. UnknownUncleParent(H256), } #[derive(Debug)] -/// TODO [arkpar] Please document me +/// Import to the block queue result pub enum ImportError { - /// TODO [arkpar] Please document me + /// Bad block detected Bad(Option), - /// TODO [arkpar] Please document me + /// Already in the block chain AlreadyInChain, - /// TODO [arkpar] Please document me + /// Already in the block queue AlreadyQueued, + /// Unknown parent + UnknownParent, } impl From for ImportError { @@ -152,15 +157,15 @@ pub type ImportResult = Result; #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum Error { - /// TODO [Gav Wood] Please document me + /// Error concerning a utility. Util(UtilError), - /// TODO [Gav Wood] Please document me + /// Error concerning block processing. Block(BlockError), - /// TODO [Gav Wood] Please document me + /// Unknown engine given. UnknownEngineName(String), - /// TODO [Gav Wood] Please document me + /// Error concerning EVM code execution. Execution(ExecutionError), - /// TODO [Gav Wood] Please document me + /// Error concerning transaction processing. Transaction(TransactionError), } diff --git a/ethcore/src/ethereum/denominations.rs b/ethcore/src/ethereum/denominations.rs index 093be89a7..2ab66431d 100644 --- a/ethcore/src/ethereum/denominations.rs +++ b/ethcore/src/ethereum/denominations.rs @@ -1,22 +1,22 @@ use util::*; #[inline] -/// TODO [debris] Please document me +/// 1 Ether in Wei pub fn ether() -> U256 { U256::exp10(18) } #[inline] -/// TODO [debris] Please document me +/// 1 Finney in Wei pub fn finney() -> U256 { U256::exp10(15) } #[inline] -/// TODO [debris] Please document me +/// 1 Szabo in Wei pub fn szabo() -> U256 { U256::exp10(12) } #[inline] -/// TODO [debris] Please document me +/// 1 Shannon in Wei pub fn shannon() -> U256 { U256::exp10(9) } #[inline] -/// TODO [debris] Please document me +/// 1 Wei in Wei pub fn wei() -> U256 { U256::exp10(0) } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index ce40c5f42..e9aedc128 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -21,7 +21,7 @@ pub struct Ethash { } impl Ethash { - /// TODO [arkpar] Please document me + /// Create a new boxed instance of Ethash engine pub fn new_boxed(spec: Spec) -> Box { Box::new(Ethash { spec: spec, @@ -110,16 +110,18 @@ impl Engine for Ethash { try!(UntrustedRlp::new(&header.seal[0]).as_val::()); try!(UntrustedRlp::new(&header.seal[1]).as_val::()); + // TODO: consider removing these lines. let min_difficulty = decode(self.spec().engine_params.get("minimumDifficulty").unwrap()); if header.difficulty < min_difficulty { - return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: min_difficulty, found: header.difficulty }))) + return Err(From::from(BlockError::DifficultyOutOfBounds(OutOfBounds { min: Some(min_difficulty), max: None, found: header.difficulty }))) } + let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(quick_get_difficulty( &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64(), &Ethash::to_ethash(header.mix_hash())))); if difficulty < header.difficulty { - return Err(From::from(BlockError::InvalidEthashDifficulty(Mismatch { expected: header.difficulty, found: difficulty }))); + return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty }))); } Ok(()) } @@ -129,10 +131,10 @@ impl Engine for Ethash { let mix = Ethash::from_ethash(result.mix_hash); let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value)); if mix != header.mix_hash() { - return Err(From::from(BlockError::InvalidBlockNonce(Mismatch { expected: mix, found: header.mix_hash() }))); + return Err(From::from(BlockError::MismatchedH256SealElement(Mismatch { expected: mix, found: header.mix_hash() }))); } if difficulty < header.difficulty { - return Err(From::from(BlockError::InvalidEthashDifficulty(Mismatch { expected: header.difficulty, found: difficulty }))); + return Err(From::from(BlockError::InvalidProofOfWork(OutOfBounds { min: Some(header.difficulty), max: None, found: difficulty }))); } Ok(()) } diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index c32fc40c6..ec6cfe103 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -3,9 +3,9 @@ //! Contains all Ethereum network specific stuff, such as denominations and //! consensus specifications. -/// TODO [Gav Wood] Please document me +/// Export the ethash module. pub mod ethash; -/// TODO [Gav Wood] Please document me +/// Export the denominations module. pub mod denominations; pub use self::ethash::*; diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index b90ea5f97..f011f67a4 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -15,35 +15,35 @@ pub enum Error { /// `BadJumpDestination` is returned when execution tried to move /// to position that wasn't marked with JUMPDEST instruction BadJumpDestination { - /// TODO [Tomusdrw] Please document me + /// Position the code tried to jump to. destination: usize }, /// `BadInstructions` is returned when given instruction is not supported BadInstruction { - /// TODO [Tomusdrw] Please document me + /// Unrecognized opcode instruction: u8, }, /// `StackUnderflow` when there is not enough stack elements to execute instruction - /// First parameter says how many elements were needed and the second how many were actually on Stack StackUnderflow { - /// TODO [Tomusdrw] Please document me + /// Invoked instruction instruction: &'static str, - /// TODO [Tomusdrw] Please document me + /// How many stack elements was requested by instruction wanted: usize, - /// TODO [Tomusdrw] Please document me + /// How many elements were on stack on_stack: usize }, /// When execution would exceed defined Stack Limit OutOfStack { - /// TODO [Tomusdrw] Please document me + /// Invoked instruction instruction: &'static str, - /// TODO [Tomusdrw] Please document me - wanted: usize, - /// TODO [Tomusdrw] Please document me + /// How many stack elements instruction wanted to push + wanted: usize, + /// What was the stack limit limit: usize }, /// Returned on evm internal error. Should never be ignored during development. /// Likely to cause consensus issues. + #[allow(dead_code)] // created only by jit Internal, } diff --git a/ethcore/src/evm/factory.rs b/ethcore/src/evm/factory.rs index 9f76d25ec..bd9315e7f 100644 --- a/ethcore/src/evm/factory.rs +++ b/ethcore/src/evm/factory.rs @@ -1,25 +1,39 @@ //! Evm factory. +//! +//! TODO: consider spliting it into two separate files. +#[cfg(test)] use std::fmt; use evm::Evm; #[derive(Clone)] -/// TODO [Tomusdrw] Please document me +/// Type of EVM to use. pub enum VMType { - /// TODO [Tomusdrw] Please document me + /// JIT EVM + #[cfg(feature="jit")] Jit, - /// TODO [Tomusdrw] Please document me + /// RUST EVM Interpreter } +#[cfg(test)] impl fmt::Display for VMType { + #[cfg(feature="jit")] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", match *self { VMType::Jit => "JIT", VMType::Interpreter => "INT" }) } + #[cfg(not(feature="jit"))] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", match *self { + VMType::Interpreter => "INT" + }) + } } +#[cfg(test)] +#[cfg(feature = "json-tests")] impl VMType { /// Return all possible VMs (JIT, Interpreter) #[cfg(feature="jit")] @@ -41,10 +55,11 @@ pub struct Factory { impl Factory { /// Create fresh instance of VM + #[cfg(feature="jit")] pub fn create(&self) -> Box { match self.evm { VMType::Jit => { - Factory::jit() + Box::new(super::jit::JitEvm) }, VMType::Interpreter => { Box::new(super::interpreter::Interpreter) @@ -52,22 +67,23 @@ impl Factory { } } + /// Create fresh instance of VM + #[cfg(not(feature="jit"))] + pub fn create(&self) -> Box { + match self.evm { + VMType::Interpreter => { + Box::new(super::interpreter::Interpreter) + } + } + } + /// Create new instance of specific `VMType` factory + #[cfg(test)] pub fn new(evm: VMType) -> Factory { Factory { evm: evm } } - - #[cfg(feature = "jit")] - fn jit() -> Box { - Box::new(super::jit::JitEvm) - } - - #[cfg(not(feature = "jit"))] - fn jit() -> Box { - unimplemented!() - } } impl Default for Factory { /// Returns jitvm factory @@ -95,6 +111,18 @@ fn test_create_vm() { /// Create tests by injecting different VM factories #[macro_export] macro_rules! evm_test( + (ignorejit => $name_test: ident: $name_jit: ident, $name_int: ident) => { + #[test] + #[ignore] + #[cfg(feature = "jit")] + fn $name_jit() { + $name_test(Factory::new(VMType::Jit)); + } + #[test] + fn $name_int() { + $name_test(Factory::new(VMType::Interpreter)); + } + }; ($name_test: ident: $name_jit: ident, $name_int: ident) => { #[test] #[cfg(feature = "jit")] diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index f55b94adb..6516d9946 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -1,11 +1,10 @@ ///! Rust VM implementation use common::*; -use evm; use super::instructions as instructions; use super::instructions::Instruction; use std::marker::Copy; -use evm::{MessageCallResult, ContractCreateResult}; +use evm::{self, MessageCallResult, ContractCreateResult}; #[cfg(not(feature = "evm-debug"))] macro_rules! evm_debug { diff --git a/ethcore/src/evm/mod.rs b/ethcore/src/evm/mod.rs index 1426bc281..2ed9a1146 100644 --- a/ethcore/src/evm/mod.rs +++ b/ethcore/src/evm/mod.rs @@ -2,7 +2,6 @@ pub mod ext; pub mod evm; -/// TODO [Tomusdrw] Please document me pub mod interpreter; #[macro_use] pub mod factory; diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index d448ccb3a..0bc57433f 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -1,25 +1,45 @@ use common::*; use evm; use evm::{Ext, Schedule, Factory, VMType, ContractCreateResult, MessageCallResult}; +use std::fmt::Debug; struct FakeLogEntry { topics: Vec, data: Bytes } +#[derive(PartialEq, Eq, Hash, Debug)] +enum FakeCallType { + CALL, CREATE +} + +#[derive(PartialEq, Eq, Hash, Debug)] +struct FakeCall { + call_type: FakeCallType, + gas: U256, + sender_address: Option
, + receive_address: Option
, + value: Option, + data: Bytes, + code_address: Option
+} + /// Fake externalities test structure. /// /// Can't do recursive calls. #[derive(Default)] struct FakeExt { + sstore_clears: usize, + depth: usize, store: HashMap, - _balances: HashMap, blockhashes: HashMap, codes: HashMap, logs: Vec, _suicides: HashSet
, info: EnvInfo, - schedule: Schedule + schedule: Schedule, + balances: HashMap, + calls: HashSet } impl FakeExt { @@ -43,31 +63,50 @@ impl Ext for FakeExt { self.store.insert(key, value); } - fn exists(&self, _address: &Address) -> bool { - unimplemented!(); + fn exists(&self, address: &Address) -> bool { + self.balances.contains_key(address) } - fn balance(&self, _address: &Address) -> U256 { - unimplemented!(); + fn balance(&self, address: &Address) -> U256 { + self.balances.get(address).unwrap().clone() } fn blockhash(&self, number: &U256) -> H256 { self.blockhashes.get(number).unwrap_or(&H256::new()).clone() } - fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8]) -> ContractCreateResult { - unimplemented!(); + fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { + self.calls.insert(FakeCall { + call_type: FakeCallType::CREATE, + gas: gas.clone(), + sender_address: None, + receive_address: None, + value: Some(value.clone()), + data: code.to_vec(), + code_address: None + }); + ContractCreateResult::Failed } fn call(&mut self, - _gas: &U256, - _sender_address: &Address, - _receive_address: &Address, - _value: Option, - _data: &[u8], - _code_address: &Address, + gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option, + data: &[u8], + code_address: &Address, _output: &mut [u8]) -> MessageCallResult { - unimplemented!(); + + self.calls.insert(FakeCall { + call_type: FakeCallType::CALL, + gas: gas.clone(), + 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()) } fn extcode(&self, address: &Address) -> Bytes { @@ -98,11 +137,11 @@ impl Ext for FakeExt { } fn depth(&self) -> usize { - unimplemented!(); + self.depth } fn inc_sstore_clears(&mut self) { - unimplemented!(); + self.sstore_clears += 1; } } @@ -150,7 +189,7 @@ fn test_add(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_988)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").unwrap()); + assert_store(&ext, 0, "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"); } evm_test!{test_sha3: test_sha3_jit, test_sha3_int} @@ -170,7 +209,7 @@ fn test_sha3(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_961)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap()); + assert_store(&ext, 0, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); } evm_test!{test_address: test_address_jit, test_address_int} @@ -190,7 +229,7 @@ fn test_address(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap()); + assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"); } evm_test!{test_origin: test_origin_jit, test_origin_int} @@ -212,11 +251,10 @@ fn test_origin(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap()); + assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681"); } -// TODO [todr] Fails with Signal 11 on JIT -evm_test!{test_sender: test_sender_jit, test_sender_int} +evm_test!{ignorejit => test_sender: test_sender_jit, test_sender_int} fn test_sender(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let sender = Address::from_str("cd1722f2947def4cf144679da39c4c32bdc35681").unwrap(); @@ -235,7 +273,7 @@ fn test_sender(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap()); + assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681"); } evm_test!{test_extcodecopy: test_extcodecopy_jit, test_extcodecopy_int} @@ -270,7 +308,7 @@ fn test_extcodecopy(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_935)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("6005600055000000000000000000000000000000000000000000000000000000").unwrap()); + assert_store(&ext, 0, "6005600055000000000000000000000000000000000000000000000000000000"); } evm_test!{test_log_empty: test_log_empty_jit, test_log_empty_int} @@ -328,7 +366,7 @@ fn test_log_sender(factory: super::Factory) { assert_eq!(ext.logs[0].data, "ff00000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap()); } -evm_test!{test_blockhash: test_blockhash_jit, test_blockhash_int} +evm_test!{ignorejit => test_blockhash: test_blockhash_jit, test_blockhash_int} fn test_blockhash(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "600040600055".from_hex().unwrap(); @@ -369,7 +407,7 @@ fn test_calldataload(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_991)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23").unwrap()); + assert_store(&ext, 0, "23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23"); } @@ -390,7 +428,7 @@ fn test_author(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap()); + assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"); } evm_test!{test_timestamp: test_timestamp_jit, test_timestamp_int} @@ -410,7 +448,7 @@ fn test_timestamp(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap()); + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); } evm_test!{test_number: test_number_jit, test_number_int} @@ -430,7 +468,7 @@ fn test_number(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap()); + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); } evm_test!{test_difficulty: test_difficulty_jit, test_difficulty_int} @@ -450,7 +488,7 @@ fn test_difficulty(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap()); + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); } evm_test!{test_gas_limit: test_gas_limit_jit, test_gas_limit_int} @@ -470,6 +508,421 @@ fn test_gas_limit(factory: super::Factory) { }; assert_eq!(gas_left, U256::from(79_995)); - assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap()); + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234"); +} + +evm_test!{test_mul: test_mul_jit, test_mul_int} +fn test_mul(factory: super::Factory) { + let code = "65012365124623626543219002600055".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "000000000000000000000000000000000000000000000000734349397b853383"); + assert_eq!(gas_left, U256::from(79_983)); +} + +evm_test!{test_sub: test_sub_jit, test_sub_int} +fn test_sub(factory: super::Factory) { + let code = "65012365124623626543219003600055".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000012364ad0302"); + assert_eq!(gas_left, U256::from(79_985)); +} + +evm_test!{test_div: test_div_jit, test_div_int} +fn test_div(factory: super::Factory) { + let code = "65012365124623626543219004600055".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "000000000000000000000000000000000000000000000000000000000002e0ac"); + assert_eq!(gas_left, U256::from(79_983)); +} + +evm_test!{test_div_zero: test_div_zero_jit, test_div_zero_int} +fn test_div_zero(factory: super::Factory) { + let code = "6501236512462360009004600055".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_eq!(gas_left, U256::from(94_983)); +} + +evm_test!{test_mod: test_mod_jit, test_mod_int} +fn test_mod(factory: super::Factory) { + let code = "650123651246236265432290066000556501236512462360009006600155".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000076b4b"); + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_eq!(gas_left, U256::from(74_966)); +} + +evm_test!{test_smod: test_smod_jit, test_smod_int} +fn test_smod(factory: super::Factory) { + let code = "650123651246236265432290076000556501236512462360009007600155".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000076b4b"); + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_eq!(gas_left, U256::from(74_966)); +} + +evm_test!{test_sdiv: test_sdiv_jit, test_sdiv_int} +fn test_sdiv(factory: super::Factory) { + let code = "650123651246236265432290056000556501236512462360009005600155".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "000000000000000000000000000000000000000000000000000000000002e0ac"); + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_eq!(gas_left, U256::from(74_966)); +} + +evm_test!{test_exp: test_exp_jit, test_exp_int} +fn test_exp(factory: super::Factory) { + let code = "6016650123651246230a6000556001650123651246230a6001556000650123651246230a600255".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "90fd23767b60204c3d6fc8aec9e70a42a3f127140879c133a20129a597ed0c59"); + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000012365124623"); + assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000001"); + assert_eq!(gas_left, U256::from(39_923)); +} + +evm_test!{test_comparison: test_comparison_jit, test_comparison_int} +fn test_comparison(factory: super::Factory) { + let code = "601665012365124623818181811060005511600155146002556415235412358014600355".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000001"); + assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000001"); + assert_eq!(gas_left, U256::from(49_952)); +} + +evm_test!{test_signed_comparison: test_signed_comparison_jit, test_signed_comparison_int} +fn test_signed_comparison(factory: super::Factory) { + let code = "60106000036010818112600055136001556010601060000381811260025513600355".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000001"); + assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000001"); + assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_eq!(gas_left, U256::from(49_940)); +} + +evm_test!{test_bitops: test_bitops_jit, test_bitops_int} +fn test_bitops(factory: super::Factory) { + let code = "60ff610ff08181818116600055176001551860025560008015600355198015600455600555".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(150_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "00000000000000000000000000000000000000000000000000000000000000f0"); + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000fff"); + assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000f0f"); + assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000001"); + assert_store(&ext, 4, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_store(&ext, 5, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + assert_eq!(gas_left, U256::from(44_937)); +} + +evm_test!{test_addmod_mulmod: test_addmod_mulmod_jit, test_addmod_mulmod_int} +fn test_addmod_mulmod(factory: super::Factory) { + let code = "60ff60f060108282820860005509600155600060f0601082828208196002550919600355".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000001"); + assert_store(&ext, 1, "000000000000000000000000000000000000000000000000000000000000000f"); + assert_store(&ext, 2, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + assert_store(&ext, 3, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + assert_eq!(gas_left, U256::from(19_914)); +} + +evm_test!{test_byte: test_byte_jit, test_byte_int} +fn test_byte(factory: super::Factory) { + let code = "60f061ffff1a600055610fff601f1a600155".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); + assert_store(&ext, 1, "00000000000000000000000000000000000000000000000000000000000000ff"); + assert_eq!(gas_left, U256::from(74_976)); +} + +evm_test!{test_signextend: test_signextend_jit, test_signextend_int} +fn test_signextend(factory: super::Factory) { + let code = "610fff60020b60005560ff60200b600155".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000fff"); + assert_store(&ext, 1, "00000000000000000000000000000000000000000000000000000000000000ff"); + assert_eq!(gas_left, U256::from(59_972)); +} + +#[test] // JIT just returns out of gas +fn test_badinstruction_int() { + let factory = super::Factory::new(VMType::Interpreter); + let code = "af".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let err = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap_err() + }; + + match err { + evm::Error::BadInstruction { instruction: 0xaf } => (), + _ => assert!(false, "Expected bad instruction") + } +} + +evm_test!{test_pop: test_pop_jit, test_pop_int} +fn test_pop(factory: super::Factory) { + let code = "60f060aa50600055".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "00000000000000000000000000000000000000000000000000000000000000f0"); + assert_eq!(gas_left, U256::from(79_989)); +} + +evm_test!{test_extops: test_extops_jit, test_extops_int} +fn test_extops(factory: super::Factory) { + let code = "5a6001555836553a600255386003553460045560016001526016590454600555".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(150_000); + params.gas_price = U256::from(0x32); + params.value = ActionValue::Transfer(U256::from(0x99)); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000004"); // PC / CALLDATASIZE + assert_store(&ext, 1, "00000000000000000000000000000000000000000000000000000000000249ee"); // GAS + assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000032"); // GASPRICE + assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000020"); // CODESIZE + assert_store(&ext, 4, "0000000000000000000000000000000000000000000000000000000000000099"); // CALLVALUE + assert_store(&ext, 5, "0000000000000000000000000000000000000000000000000000000000000032"); + assert_eq!(gas_left, U256::from(29_898)); +} + +evm_test!{test_jumps: test_jumps_jit, test_jumps_int} +fn test_jumps(factory: super::Factory) { + let code = "600160015560066000555b60016000540380806000551560245760015402600155600a565b".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(150_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_eq!(ext.sstore_clears, 1); + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); // 5! + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000078"); // 5! + assert_eq!(gas_left, U256::from(54_117)); +} + + +evm_test!{test_calls: test_calls_jit, test_calls_int} +fn test_calls(factory: super::Factory) { + let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap(); + + let address = Address::from(0x155); + let code_address = Address::from(0x998); + let mut params = ActionParams::default(); + params.gas = U256::from(150_000); + params.code = Some(code); + params.address = address.clone(); + let mut ext = FakeExt::new(); + ext.balances = { + let mut s = HashMap::new(); + s.insert(params.address.clone(), params.gas.clone()); + s + }; + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_set_contains(&ext.calls, &FakeCall { + call_type: FakeCallType::CALL, + gas: U256::from(2556), + sender_address: Some(address.clone()), + receive_address: Some(code_address.clone()), + value: Some(U256::from(0x50)), + data: vec!(), + code_address: Some(code_address.clone()) + }); + assert_set_contains(&ext.calls, &FakeCall { + call_type: FakeCallType::CALL, + gas: U256::from(2556), + sender_address: Some(address.clone()), + receive_address: Some(address.clone()), + value: Some(U256::from(0x50)), + data: vec!(), + code_address: Some(code_address.clone()) + }); + assert_eq!(gas_left, U256::from(91_405)); + assert_eq!(ext.calls.len(), 2); +} + +fn assert_set_contains(set: &HashSet, val: &T) { + let contains = set.contains(val); + if !contains { + println!("Set: {:?}", set); + println!("Elem: {:?}", val); + } + assert!(contains, "Element not found in HashSet"); +} + +fn assert_store(ext: &FakeExt, pos: u64, val: &str) { + assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap()); } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index d824ccc2c..b67b71306 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -129,7 +129,7 @@ impl<'a> Executive<'a> { let mut substate = Substate::new(); - let res = match *t.action() { + let res = match t.action { Action::Create => { let new_address = contract_address(&sender, &nonce); let params = ActionParams { @@ -399,7 +399,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(0x100u64)); - let info = EnvInfo::new(); + let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); let mut substate = Substate::new(); @@ -458,7 +458,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(100)); - let info = EnvInfo::new(); + let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); let mut substate = Substate::new(); @@ -512,7 +512,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(100)); - let info = EnvInfo::new(); + let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); let mut substate = Substate::new(); @@ -564,7 +564,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(100)); - let info = EnvInfo::new(); + let info = EnvInfo::default(); let engine = TestEngine::new(1024, factory); let mut substate = Substate::new(); @@ -624,7 +624,7 @@ mod tests { state.init_code(&address_b, code_b.clone()); state.add_balance(&sender, &U256::from(100_000)); - let info = EnvInfo::new(); + let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); let mut substate = Substate::new(); @@ -668,7 +668,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.init_code(&address, code.clone()); - let info = EnvInfo::new(); + let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); let mut substate = Substate::new(); @@ -694,7 +694,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(18)); - let mut info = EnvInfo::new(); + let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0, factory); @@ -721,7 +721,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); - let mut info = EnvInfo::new(); + let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0, factory); @@ -746,7 +746,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(17)); - let mut info = EnvInfo::new(); + let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0, factory); @@ -772,7 +772,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(17)); - let mut info = EnvInfo::new(); + let mut info = EnvInfo::default(); info.gas_used = U256::from(20_000); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0, factory); @@ -799,7 +799,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from(100_017)); - let mut info = EnvInfo::new(); + let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let engine = TestEngine::new(0, factory); @@ -833,7 +833,7 @@ mod tests { let mut state_result = get_temp_state(); let mut state = state_result.reference_mut(); state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); - let info = EnvInfo::new(); + let info = EnvInfo::default(); let engine = TestEngine::new(0, factory); let mut substate = Substate::new(); diff --git a/ethcore/src/extras.rs b/ethcore/src/extras.rs index 4459826cc..4c54c6b27 100644 --- a/ethcore/src/extras.rs +++ b/ethcore/src/extras.rs @@ -1,3 +1,5 @@ +//! Blockchain DB extras. + use util::*; use header::BlockNumber; use rocksdb::{DB, Writable}; @@ -5,21 +7,21 @@ use rocksdb::{DB, Writable}; /// Represents index of extra data in database #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] pub enum ExtrasIndex { - /// TODO [debris] Please document me + /// Block details index BlockDetails = 0, - /// TODO [debris] Please document me + /// Block hash index BlockHash = 1, - /// TODO [debris] Please document me + /// Transaction address index TransactionAddress = 2, - /// TODO [debris] Please document me + /// Block log blooms index BlockLogBlooms = 3, - /// TODO [debris] Please document me + /// Block blooms index BlocksBlooms = 4 } /// trait used to write Extras data to db pub trait ExtrasWritable { - /// TODO [debris] Please document me + /// Write extra data to db fn put_extras(&self, hash: &K, value: &T) where T: ExtrasIndexable + Encodable, K: ExtrasSliceConvertable; @@ -27,12 +29,12 @@ pub trait ExtrasWritable { /// trait used to read Extras data from db pub trait ExtrasReadable { - /// TODO [debris] Please document me + /// Read extra data from db fn get_extras(&self, hash: &K) -> Option where T: ExtrasIndexable + Decodable, K: ExtrasSliceConvertable; - /// TODO [debris] Please document me + /// Check if extra data exists in the db fn extras_exists(&self, hash: &K) -> bool where T: ExtrasIndexable, K: ExtrasSliceConvertable; @@ -66,9 +68,9 @@ impl ExtrasReadable for DB { /// Implementations should convert arbitrary type to database key slice pub trait ExtrasSliceConvertable { - /// TODO [Gav Wood] Please document me + /// Convert self, with `i` (the index), to a 264-bit extras DB key. fn to_extras_slice(&self, i: ExtrasIndex) -> H264; - /// TODO [debris] Please document me + /// Interpret self as a 256-bit hash, if natively `H256`. fn as_h256(&self) -> Option<&H256> { None } } @@ -96,7 +98,7 @@ impl ExtrasSliceConvertable for BlockNumber { /// Types implementing this trait can be indexed in extras database pub trait ExtrasIndexable { - /// TODO [debris] Please document me + /// Returns this data index fn extras_index() -> ExtrasIndex; } @@ -109,13 +111,13 @@ impl ExtrasIndexable for H256 { /// Familial details concerning a block #[derive(Debug, Clone)] pub struct BlockDetails { - /// TODO [debris] Please document me + /// Block number pub number: BlockNumber, - /// TODO [debris] Please document me + /// Total difficulty of the block and all its parents pub total_difficulty: U256, - /// TODO [debris] Please document me + /// Parent block hash pub parent: H256, - /// TODO [debris] Please document me + /// List of children block hashes pub children: Vec } @@ -157,7 +159,7 @@ impl Encodable for BlockDetails { /// Log blooms of certain block #[derive(Clone)] pub struct BlockLogBlooms { - /// TODO [debris] Please document me + /// List of log blooms for the block pub blooms: Vec } @@ -191,7 +193,7 @@ impl Encodable for BlockLogBlooms { /// Neighboring log blooms on certain level pub struct BlocksBlooms { - /// TODO [debris] Please document me + /// List of block blooms. pub blooms: [H2048; 16] } @@ -239,9 +241,9 @@ impl Encodable for BlocksBlooms { /// Represents address of certain transaction within block #[derive(Clone)] pub struct TransactionAddress { - /// TODO [debris] Please document me + /// Block hash pub block_hash: H256, - /// TODO [debris] Please document me + /// Transaction index within the block pub index: u64 } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index c6c18bf4b..b188a6bcf 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -1,3 +1,5 @@ +//! Block header. + use util::*; use basic_types::*; use time::now_utc; @@ -11,50 +13,49 @@ pub type BlockNumber = u64; /// which is non-specific. /// /// Doesn't do all that much on its own. -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct Header { // TODO: make all private. - /// TODO [Gav Wood] Please document me + /// Parent hash. pub parent_hash: H256, - /// TODO [arkpar] Please document me + /// Block timestamp. pub timestamp: u64, - /// TODO [debris] Please document me + /// Block number. pub number: BlockNumber, - /// TODO [Gav Wood] Please document me + /// Block author. pub author: Address, - /// TODO [debris] Please document me + /// Transactions root. pub transactions_root: H256, - /// TODO [debris] Please document me + /// Block uncles hash. pub uncles_hash: H256, - /// TODO [Gav Wood] Please document me + /// Block extra data. pub extra_data: Bytes, - /// TODO [debris] Please document me + /// State root. pub state_root: H256, - /// TODO [debris] Please document me + /// Block receipts root. pub receipts_root: H256, - /// TODO [debris] Please document me + /// Block bloom. pub log_bloom: LogBloom, - /// TODO [debris] Please document me + /// Gas used for contracts execution. pub gas_used: U256, - /// TODO [Gav Wood] Please document me + /// Block gas limit. pub gas_limit: U256, - /// TODO [debris] Please document me + /// Block difficulty. pub difficulty: U256, - /// TODO [arkpar] Please document me + /// Block seal. pub seal: Vec, - /// TODO [arkpar] Please document me + /// The memoized hash of the RLP representation *including* the seal fields. pub hash: RefCell>, - /// TODO [Gav Wood] Please document me + /// The memoized hash of the RLP representation *without* the seal fields. pub bare_hash: RefCell>, } -impl Header { - /// Create a new, default-valued, header. - pub fn new() -> Header { +impl Default for Header { + fn default() -> Self { Header { parent_hash: ZERO_H256.clone(), timestamp: 0, @@ -77,51 +78,58 @@ impl Header { bare_hash: RefCell::new(None), } } +} - /// TODO [Gav Wood] Please document me +impl Header { + /// Create a new, default-valued, header. + pub fn new() -> Self { + Self::default() + } + + /// Get the number field of the header. pub fn number(&self) -> BlockNumber { self.number } - /// TODO [Gav Wood] Please document me + /// Get the timestamp field of the header. pub fn timestamp(&self) -> u64 { self.timestamp } - /// TODO [Gav Wood] Please document me + /// Get the author field of the header. pub fn author(&self) -> &Address { &self.author } - /// TODO [Gav Wood] Please document me + /// Get the extra data field of the header. pub fn extra_data(&self) -> &Bytes { &self.extra_data } - /// TODO [Gav Wood] Please document me + /// Get the state root field of the header. pub fn state_root(&self) -> &H256 { &self.state_root } - /// TODO [Gav Wood] Please document me + /// Get the receipts root field of the header. pub fn receipts_root(&self) -> &H256 { &self.receipts_root } - /// TODO [Gav Wood] Please document me + /// Get the gas limit field of the header. pub fn gas_limit(&self) -> &U256 { &self.gas_limit } - /// TODO [Gav Wood] Please document me + /// Get the difficulty field of the header. pub fn difficulty(&self) -> &U256 { &self.difficulty } - /// TODO [Gav Wood] Please document me + /// Get the seal field of the header. pub fn seal(&self) -> &Vec { &self.seal } // TODO: seal_at, set_seal_at &c. - /// TODO [Gav Wood] Please document me + /// Set the number field of the header. pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } - /// TODO [Gav Wood] Please document me + /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } - /// TODO [Gav Wood] Please document me + /// Set the timestamp field of the header to the current time. pub fn set_timestamp_now(&mut self) { self.timestamp = now_utc().to_timespec().sec as u64; self.note_dirty(); } - /// TODO [Gav Wood] Please document me + /// Set the author field of the header. pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } } - /// TODO [Gav Wood] Please document me + /// Set the extra data field of the header. pub fn set_extra_data(&mut self, a: Bytes) { if a != self.extra_data { self.extra_data = a; self.note_dirty(); } } - /// TODO [Gav Wood] Please document me + /// Set the gas used field of the header. pub fn set_gas_used(&mut self, a: U256) { self.gas_used = a; self.note_dirty(); } - /// TODO [Gav Wood] Please document me + /// Set the gas limit field of the header. pub fn set_gas_limit(&mut self, a: U256) { self.gas_limit = a; self.note_dirty(); } - /// TODO [Gav Wood] Please document me + /// Set the difficulty field of the header. pub fn set_difficulty(&mut self, a: U256) { self.difficulty = a; self.note_dirty(); } - /// TODO [Gav Wood] Please document me + /// Set the seal field of the header. pub fn set_seal(&mut self, a: Vec) { self.seal = a; self.note_dirty(); } /// Get the hash of this header (sha3 of the RLP). @@ -155,7 +163,7 @@ impl Header { } // TODO: make these functions traity - /// TODO [Gav Wood] Please document me + /// Place this header into an RLP stream `s`, optionally `with_seal`. pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) { s.begin_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 }); s.append(&self.parent_hash); @@ -178,14 +186,14 @@ impl Header { } } - /// TODO [Gav Wood] Please document me + /// Get the RLP of this header, optionally `with_seal`. pub fn rlp(&self, with_seal: Seal) -> Bytes { let mut s = RlpStream::new(); self.stream_rlp(&mut s, with_seal); s.out() } - /// TODO [debris] Please document me + /// Get the SHA3 (Keccak) of this header, optionally `with_seal`. pub fn rlp_sha3(&self, with_seal: Seal) -> H256 { self.rlp(with_seal).sha3() } } diff --git a/ethcore/src/tests/chain.rs b/ethcore/src/json_tests/chain.rs similarity index 96% rename from ethcore/src/tests/chain.rs rename to ethcore/src/json_tests/chain.rs index 4d1835033..6ee7e9f9e 100644 --- a/ethcore/src/tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -3,7 +3,7 @@ use client::{BlockChainClient,Client}; use pod_state::*; use block::Block; use ethereum; -use super::helpers::*; +use tests::helpers::*; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); @@ -15,12 +15,12 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { { let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.clone()); - flush(format!("FAIL\n")); + flushln!("FAIL"); fail = true; true } else {false}; - flush(format!(" - {}...", name)); + flush!(" - {}...", name); let blocks: Vec<(Bytes, bool)> = test["blocks"].as_array().unwrap().iter().map(|e| (xjson!(&e["rlp"]), e.find("blockHeader").is_some())).collect(); let mut spec = match era { @@ -50,7 +50,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { } } if !fail { - flush(format!("ok\n")); + flushln!("ok"); } } println!("!!! {:?} tests from failed.", failed.len()); diff --git a/ethcore/src/tests/client.rs b/ethcore/src/json_tests/client.rs similarity index 98% rename from ethcore/src/tests/client.rs rename to ethcore/src/json_tests/client.rs index 56b6e7db0..1d09ed079 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/json_tests/client.rs @@ -1,6 +1,6 @@ use client::{BlockChainClient,Client}; use super::test_common::*; -use super::helpers::*; +use tests::helpers::*; #[test] fn created() { @@ -75,4 +75,4 @@ fn can_collect_garbage() { let client = client_result.reference(); client.tick(); assert!(client.cache_info().blocks < 100 * 1024); -} \ No newline at end of file +} diff --git a/ethcore/src/tests/executive.rs b/ethcore/src/json_tests/executive.rs similarity index 100% rename from ethcore/src/tests/executive.rs rename to ethcore/src/json_tests/executive.rs diff --git a/ethcore/src/tests/homestead_chain.rs b/ethcore/src/json_tests/homestead_chain.rs similarity index 98% rename from ethcore/src/tests/homestead_chain.rs rename to ethcore/src/json_tests/homestead_chain.rs index 5691f3a19..1962da1bc 100644 --- a/ethcore/src/tests/homestead_chain.rs +++ b/ethcore/src/json_tests/homestead_chain.rs @@ -1,6 +1,6 @@ use super::test_common::*; -use super::helpers::*; use super::chain::json_chain_test; +use tests::helpers::*; fn do_json_test(json_data: &[u8]) -> Vec { json_chain_test(json_data, ChainEra::Homestead) diff --git a/ethcore/src/tests/homestead_state.rs b/ethcore/src/json_tests/homestead_state.rs similarity index 98% rename from ethcore/src/tests/homestead_state.rs rename to ethcore/src/json_tests/homestead_state.rs index f0f7cd21e..474d56f8a 100644 --- a/ethcore/src/tests/homestead_state.rs +++ b/ethcore/src/json_tests/homestead_state.rs @@ -1,5 +1,5 @@ use super::test_common::*; -use super::helpers::*; +use tests::helpers::*; use super::state::json_chain_test; fn do_json_test(json_data: &[u8]) -> Vec { diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs new file mode 100644 index 000000000..b5d6779bc --- /dev/null +++ b/ethcore/src/json_tests/mod.rs @@ -0,0 +1,10 @@ +#[macro_use] +mod test_common; + +mod transaction; +mod executive; +mod state; +mod client; +mod chain; +mod homestead_state; +mod homestead_chain; diff --git a/ethcore/src/tests/state.rs b/ethcore/src/json_tests/state.rs similarity index 99% rename from ethcore/src/tests/state.rs rename to ethcore/src/json_tests/state.rs index 34b24de3b..fa8da9329 100644 --- a/ethcore/src/tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -1,5 +1,5 @@ use super::test_common::*; -use super::helpers::*; +use tests::helpers::*; use pod_state::*; use state_diff::*; use ethereum; @@ -19,19 +19,19 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { ChainEra::Homestead => ethereum::new_homestead_test(), }.to_engine().unwrap(); - flush(format!("\n")); + flushln!(""); for (name, test) in json.as_object().unwrap() { let mut fail = false; { let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.clone()); - flush(format!("FAIL\n")); + flushln!("FAIL"); fail = true; true } else {false}; - flush(format!(" - {}...", name)); + flush!(" - {}...", name); let t = Transaction::from_json(&test["transaction"]); let env = EnvInfo::from_json(&test["env"]); @@ -73,7 +73,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { } } if !fail { - flush(format!("ok\n")); + flushln!("ok"); } // TODO: Add extra APIs for output //if fail_unless(out == r.) diff --git a/ethcore/src/tests/test_common.rs b/ethcore/src/json_tests/test_common.rs similarity index 86% rename from ethcore/src/tests/test_common.rs rename to ethcore/src/json_tests/test_common.rs index fd88ae96a..87e7b979e 100644 --- a/ethcore/src/tests/test_common.rs +++ b/ethcore/src/json_tests/test_common.rs @@ -12,7 +12,6 @@ macro_rules! declare_test { #[ignore] #[test] #[allow(non_snake_case)] - #[cfg(feature="json-tests")] fn $id() { test!($name); } @@ -21,7 +20,6 @@ macro_rules! declare_test { #[cfg(feature = "test-heavy")] #[test] #[allow(non_snake_case)] - #[cfg(feature="json-tests")] fn $id() { test!($name); } @@ -29,7 +27,6 @@ macro_rules! declare_test { ($id: ident, $name: expr) => { #[test] #[allow(non_snake_case)] - #[cfg(feature="json-tests")] fn $id() { test!($name); } diff --git a/ethcore/src/tests/transaction.rs b/ethcore/src/json_tests/transaction.rs similarity index 100% rename from ethcore/src/tests/transaction.rs rename to ethcore/src/json_tests/transaction.rs diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 0652d964e..3df01d898 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -2,157 +2,113 @@ #![feature(cell_extras)] #![feature(augmented_assignments)] #![feature(plugin)] -//#![plugin(interpolate_idents)] #![plugin(clippy)] #![allow(needless_range_loop, match_bool)] -//! Ethcore's ethereum implementation +//! Ethcore library //! -//! ### Rust version -//! - beta +//! ### Rust version: //! - nightly //! //! ### Supported platforms: //! - OSX -//! - Linux/Ubuntu +//! - Linux //! -//! ### Dependencies: -//! - RocksDB 3.13 -//! - LLVM 3.7 (optional, required for `jit`) -//! - evmjit (optional, required for `jit`) +//! ### Building: //! -//! ### Dependencies Installation +//! - Ubuntu 14.04 and later: //! -//! - OSX -//! -//! - rocksdb //! ```bash -//! brew install rocksdb +//! # install rocksdb +//! add-apt-repository "deb http://ppa.launchpad.net/giskou/librocksdb/ubuntu trusty main" +//! apt-get update +//! apt-get install -y --force-yes librocksdb +//! +//! # install multirust +//! curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh -s -- --yes +//! +//! # install nightly and make it default +//! multirust update nightly && multirust default nightly +//! +//! # export rust LIBRARY_PATH +//! export LIBRARY_PATH=/usr/local/lib +//! +//! # download and build parity +//! git clone https://github.com/ethcore/parity +//! cd parity +//! cargo build --release //! ``` +//! +//! - OSX: //! -//! - llvm +//! ```bash +//! # install rocksdb && multirust +//! brew update +//! brew install rocksdb +//! brew install multirust //! -//! - download llvm 3.7 from http://llvm.org/apt/ +//! # install nightly and make it default +//! multirust update nightly && multirust default nightly //! -//! ```bash -//! cd llvm-3.7.0.src -//! mkdir build && cd $_ -//! cmake -G "Unix Makefiles" .. -DCMAKE_C_FLAGS_RELEASE= -DCMAKE_CXX_FLAGS_RELEASE= -DCMAKE_INSTALL_PREFIX=/usr/local/Cellar/llvm/3.7 -DCMAKE_BUILD_TYPE=Release -//! make && make install -//! ``` -//! - evmjit +//! # export rust LIBRARY_PATH +//! export LIBRARY_PATH=/usr/local/lib //! -//! - download from https://github.com/debris/evmjit -//! -//! ```bash -//! cd evmjit -//! mkdir build && cd $_ -//! cmake -DLLVM_DIR=/usr/local/lib/llvm-3.7/share/llvm/cmake .. -//! make && make install -//! ``` -//! -//! - Linux/Ubuntu -//! -//! - rocksdb -//! -//! ```bash -//! wget https://github.com/facebook/rocksdb/archive/rocksdb-3.13.tar.gz -//! tar xvf rocksdb-3.13.tar.gz && cd rocksdb-rocksdb-3.13 && make shared_lib -//! sudo make install -//! ``` -//! -//! - llvm -//! -//! - install using packages from http://llvm.org/apt/ -//! -//! - evmjit -//! -//! - download from https://github.com/debris/evmjit -//! -//! ```bash -//! cd evmjit -//! mkdir build && cd $_ -//! cmake .. && make -//! sudo make install -//! sudo ldconfig -//! ``` -#[macro_use] -extern crate log; +//! # download and build parity +//! git clone https://github.com/ethcore/parity +//! cd parity +//! cargo build --release +//! ``` + +#[macro_use] extern crate log; +#[macro_use] extern crate ethcore_util as util; +#[macro_use] extern crate lazy_static; extern crate rustc_serialize; -extern crate flate2; extern crate rocksdb; extern crate heapsize; extern crate crypto; extern crate time; extern crate env_logger; extern crate num_cpus; -#[cfg(feature = "jit" )] -extern crate evmjit; -#[macro_use] -extern crate ethcore_util as util; extern crate crossbeam; -#[macro_use] -extern crate lazy_static; -// NOTE: Add doc parser exception for these pub declarations. +#[cfg(feature = "jit" )] extern crate evmjit; -/// TODO [Gav Wood] Please document me -pub mod common; -/// TODO [Tomusdrw] Please document me -pub mod basic_types; -#[macro_use] -pub mod evm; +pub mod block; +pub mod blockchain; +pub mod block_queue; +pub mod client; pub mod error; -/// TODO [Gav Wood] Please document me -pub mod log_entry; -/// TODO [Gav Wood] Please document me -pub mod env_info; -/// TODO [Gav Wood] Please document me -pub mod pod_account; -/// TODO [Gav Wood] Please document me -pub mod pod_state; -/// TODO [Gav Wood] Please document me -pub mod account_diff; -/// TODO [Gav Wood] Please document me -pub mod state_diff; -/// TODO [Gav Wood] Please document me -pub mod engine; -/// TODO [Gav Wood] Please document me -pub mod state; -/// TODO [Gav Wood] Please document me -pub mod account; -pub mod action_params; -/// TODO [debris] Please document me +pub mod ethereum; pub mod header; -/// TODO [Gav Wood] Please document me -pub mod transaction; -/// TODO [Gav Wood] Please document me -pub mod receipt; -/// TODO [Gav Wood] Please document me -pub mod null_engine; -/// TODO [Gav Wood] Please document me -pub mod builtin; -/// TODO [debris] Please document me +pub mod service; pub mod spec; pub mod views; -pub mod blockchain; -/// TODO [Gav Wood] Please document me -pub mod extras; -/// TODO [arkpar] Please document me -pub mod substate; -/// TODO [Gav Wood] Please document me -pub mod service; -pub mod executive; -pub mod externalities; -#[cfg(test)] +mod common; +mod basic_types; +#[macro_use] mod evm; +mod log_entry; +mod env_info; +mod pod_account; +mod pod_state; +mod account_diff; +mod state_diff; +mod engine; +mod state; +mod account; +mod action_params; +mod transaction; +mod receipt; +mod null_engine; +mod builtin; +mod extras; +mod substate; +mod executive; +mod externalities; +mod verification; + +#[cfg(test)] mod tests; - -/// TODO [arkpar] Please document me -pub mod client; -/// TODO [arkpar] Please document me -pub mod block; -/// TODO [arkpar] Please document me -pub mod verification; -pub mod block_queue; -pub mod ethereum; +#[cfg(test)] +#[cfg(feature="json-tests")] +mod json_tests; diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index 8141549a3..46faad797 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -1,14 +1,14 @@ use util::*; use basic_types::LogBloom; -/// A single log's entry. +/// A record of execution for a `LOG` operation. #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct LogEntry { - /// TODO [Gav Wood] Please document me + /// The address of the contract executing at the point of the `LOG` operation. pub address: Address, - /// TODO [Gav Wood] Please document me + /// The topics associated with the `LOG` operation. pub topics: Vec, - /// TODO [Gav Wood] Please document me + /// The data associated with the `LOG` operation. pub data: Bytes, } @@ -31,21 +31,6 @@ impl LogEntry { } } - /// Returns reference to address. - pub fn address(&self) -> &Address { - &self.address - } - - /// Returns reference to topics. - pub fn topics(&self) -> &Vec { - &self.topics - } - - /// Returns reference to data. - pub fn data(&self) -> &Bytes { - &self.data - } - /// Calculates the bloom of this log entry. pub fn bloom(&self) -> LogBloom { self.topics.iter().fold(LogBloom::from_bloomed(&self.address.sha3()), |b, t| b.with_bloomed(&t.sha3())) diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 97cfcb6fd..7bc886617 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -2,20 +2,22 @@ use util::*; use account::*; #[derive(Debug,Clone,PartialEq,Eq)] -/// Genesis account data. Does not have a DB overlay cache. +/// An account, expressed as Plain-Old-Data (hence the name). +/// Does not have a DB overlay cache, code hash or anything like that. pub struct PodAccount { - /// TODO [Gav Wood] Please document me + /// The balance of the account. pub balance: U256, - /// TODO [Gav Wood] Please document me + /// The nonce of the account. pub nonce: U256, - /// TODO [Gav Wood] Please document me + /// The code of the account. pub code: Bytes, - /// TODO [Gav Wood] Please document me + /// The storage of the account. pub storage: BTreeMap, } impl PodAccount { /// Construct new object. + #[cfg(test)] pub fn new(balance: U256, nonce: U256, code: Bytes, storage: BTreeMap) -> PodAccount { PodAccount { balance: balance, nonce: nonce, code: code, storage: storage } } diff --git a/ethcore/src/pod_state.rs b/ethcore/src/pod_state.rs index f37a327f8..69eca17b6 100644 --- a/ethcore/src/pod_state.rs +++ b/ethcore/src/pod_state.rs @@ -2,7 +2,7 @@ use util::*; use pod_account::*; #[derive(Debug,Clone,PartialEq,Eq,Default)] -/// TODO [Gav Wood] Please document me +/// State of all accounts in the system expressed in Plain Old Data. pub struct PodState (BTreeMap); impl PodState { @@ -10,6 +10,7 @@ impl PodState { pub fn new() -> PodState { Default::default() } /// Contruct a new object from the `m`. + #[cfg(test)] pub fn from(m: BTreeMap) -> PodState { PodState(m) } /// Get the underlying map. @@ -21,6 +22,8 @@ impl PodState { } /// Drain object to get the underlying map. + #[cfg(test)] + #[cfg(feature = "json-tests")] pub fn drain(self) -> BTreeMap { self.0 } } diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index b12cbab23..43f674aa9 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -5,18 +5,18 @@ use log_entry::LogEntry; /// Information describing execution of a transaction. #[derive(Default, Debug, Clone)] pub struct Receipt { - /// TODO [Gav Wood] Please document me + /// The state root after executing the transaction. pub state_root: H256, - /// TODO [Gav Wood] Please document me + /// The total gas used in the block following execution of the transaction. pub gas_used: U256, - /// TODO [Gav Wood] Please document me + /// The OR-wide combination of all logs' blooms for this transaction. pub log_bloom: LogBloom, - /// TODO [Gav Wood] Please document me + /// The logs stemming from this transaction. pub logs: Vec, } impl Receipt { - /// TODO [Gav Wood] Please document me + /// Create a new receipt. pub fn new(state_root: H256, gas_used: U256, logs: Vec) -> Receipt { Receipt { state_root: state_root, diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index f24758abb..fa530df70 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -1,3 +1,5 @@ +//! Creates and registers client and network services. + use util::*; use spec::Spec; use error::*; @@ -13,7 +15,7 @@ pub enum SyncMessage { BlockVerified, } -/// TODO [arkpar] Please document me +/// IO Message type used for Network service pub type NetSyncMessage = NetworkIoMessage; /// Client service setup. Creates and registers client and network services with the IO subsystem. @@ -109,4 +111,4 @@ mod tests { let service = ClientService::start(spec, NetworkConfiguration::new()); assert!(service.is_ok()); } -} \ No newline at end of file +} diff --git a/ethcore/src/spec.rs b/ethcore/src/spec.rs index d51246b23..50bbbb633 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec.rs @@ -1,21 +1,10 @@ +//! Parameters for a block chain. + use common::*; -use flate2::read::GzDecoder; use engine::*; use pod_state::*; use null_engine::*; -/// Converts file from base64 gzipped bytes to json -pub fn gzip64res_to_json(source: &[u8]) -> Json { - // there is probably no need to store genesis in based64 gzip, - // but that's what go does, and it was easy to load it this way - let data = source.from_base64().expect("Genesis block is malformed!"); - let data_ref: &[u8] = &data; - let mut decoder = GzDecoder::new(data_ref).expect("Gzip is invalid"); - let mut s: String = "".to_owned(); - decoder.read_to_string(&mut s).expect("Gzip is invalid"); - Json::from_str(&s).expect("Json is invalid") -} - /// Convert JSON value to equivalent RLP representation. // TODO: handle container types. fn json_to_rlp(json: &Json) -> Bytes { @@ -45,53 +34,50 @@ fn json_to_rlp_map(json: &Json) -> HashMap { /// chain and those to be interpreted by the active chain engine. #[derive(Debug)] pub struct Spec { - // User friendly spec name - /// TODO [Gav Wood] Please document me + /// User friendly spec name pub name: String, - // What engine are we using for this? - /// TODO [Gav Wood] Please document me + /// What engine are we using for this? pub engine_name: String, /// Known nodes on the network in enode format. pub nodes: Vec, - // Parameters concerning operation of the specific engine we're using. - // Name -> RLP-encoded value - /// TODO [Gav Wood] Please document me + /// Parameters concerning operation of the specific engine we're using. + /// Maps the parameter name to an RLP-encoded value. pub engine_params: HashMap, - // Builtin-contracts are here for now but would like to abstract into Engine API eventually. - /// TODO [Gav Wood] Please document me + /// Builtin-contracts we would like to see in the chain. + /// (In principle these are just hints for the engine since that has the last word on them.) pub builtins: BTreeMap, - // Genesis params. - /// TODO [Gav Wood] Please document me + /// The genesis block's parent hash field. pub parent_hash: H256, - /// TODO [Gav Wood] Please document me + /// The genesis block's author field. pub author: Address, - /// TODO [Gav Wood] Please document me + /// The genesis block's difficulty field. pub difficulty: U256, - /// TODO [Gav Wood] Please document me + /// The genesis block's gas limit field. pub gas_limit: U256, - /// TODO [Gav Wood] Please document me + /// The genesis block's gas used field. pub gas_used: U256, - /// TODO [Gav Wood] Please document me + /// The genesis block's timestamp field. pub timestamp: u64, /// Transactions root of the genesis block. Should be SHA3_NULL_RLP. pub transactions_root: H256, /// Receipts root of the genesis block. Should be SHA3_NULL_RLP. pub receipts_root: H256, - /// TODO [arkpar] Please document me + /// The genesis block's extra data field. pub extra_data: Bytes, - /// TODO [Gav Wood] Please document me - genesis_state: PodState, - /// TODO [Gav Wood] Please document me + /// The number of seal fields in the genesis block. pub seal_fields: usize, - /// TODO [Gav Wood] Please document me + /// Each seal field, expressed as RLP, concatenated. pub seal_rlp: Bytes, // May be prepopulated if we know this in advance. state_root_memo: RwLock>, + + // Genesis state as plain old data. + genesis_state: PodState, } #[allow(wrong_self_convention)] // because to_engine(self) should be to_engine(&self) @@ -117,7 +103,7 @@ impl Spec { /// Get the known knodes of the network in enode format. pub fn nodes(&self) -> &Vec { &self.nodes } - /// TODO [Gav Wood] Please document me + /// Get the header of the genesis block. pub fn genesis_header(&self) -> Header { Header { parent_hash: self.parent_hash.clone(), diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 58cdf85a2..ed7d29813 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -1,11 +1,15 @@ use common::*; use engine::Engine; use executive::Executive; +#[cfg(test)] +#[cfg(feature = "json-tests")] use pod_account::*; -use pod_state::*; +#[cfg(test)] +#[cfg(feature = "json-tests")] +use pod_state::PodState; //use state_diff::*; // TODO: uncomment once to_pod() works correctly. -/// TODO [Gav Wood] Please document me +/// Result type for the execution ("application") of a transaction. pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. @@ -20,6 +24,7 @@ pub struct State { impl State { /// Creates new state with empty state root + #[cfg(test)] pub fn new(mut db: JournalDB, account_start_nonce: U256) -> State { let mut root = H256::new(); { @@ -60,11 +65,6 @@ impl State { &self.root } - /// Expose the underlying database; good to use for calling `state.db().commit()`. - pub fn db(&mut self) -> &mut JournalDB { - &mut self.db - } - /// Create a new contract at address `contract`. If there is already an account at the address /// it will have its code reset, ready for `init_code()`. pub fn new_contract(&mut self, contract: &Address, balance: U256) { @@ -143,7 +143,6 @@ impl State { // let old = self.to_pod(); let e = try!(Executive::new(self, env_info, engine).transact(t)); - //println!("Executed: {:?}", e); // TODO uncomment once to_pod() works correctly. // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); @@ -153,16 +152,11 @@ impl State { Ok(receipt) } - /// TODO [debris] Please document me + /// Reverts uncommited changed. pub fn revert(&mut self, backup: State) { self.cache = backup.cache; } - /// Convert into a JSON representation. - pub fn as_json(&self) -> String { - unimplemented!(); - } - /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. #[allow(match_ref_pats)] @@ -195,6 +189,8 @@ impl State { Self::commit_into(&mut self.db, &mut self.root, self.cache.borrow_mut().deref_mut()); } + #[cfg(test)] + #[cfg(feature = "json-tests")] /// Populate the state from `accounts`. pub fn populate_from(&mut self, accounts: PodState) { for (add, acc) in accounts.drain().into_iter() { @@ -202,17 +198,8 @@ impl State { } } - /// Populate a PodAccount map from this state. - pub fn to_hashmap_pod(&self) -> HashMap { - // TODO: handle database rather than just the cache. - self.cache.borrow().iter().fold(HashMap::new(), |mut m, (add, opt)| { - if let Some(ref acc) = *opt { - m.insert(add.clone(), PodAccount::from_account(acc)); - } - m - }) - } - + #[cfg(test)] + #[cfg(feature = "json-tests")] /// Populate a PodAccount map from this state. pub fn to_pod(&self) -> PodState { // TODO: handle database rather than just the cache. diff --git a/ethcore/src/state_diff.rs b/ethcore/src/state_diff.rs index 12e2d76ca..ba9e6e816 100644 --- a/ethcore/src/state_diff.rs +++ b/ethcore/src/state_diff.rs @@ -1,12 +1,15 @@ use util::*; +#[cfg(test)] use pod_state::*; use account_diff::*; #[derive(Debug,Clone,PartialEq,Eq)] -/// TODO [Gav Wood] Please document me +/// Expression for the delta between two system states. Encoded the +/// delta of every altered account. pub struct StateDiff (BTreeMap); impl StateDiff { + #[cfg(test)] /// Calculate and return diff between `pre` state and `post` state. pub fn diff_pod(pre: &PodState, post: &PodState) -> StateDiff { StateDiff(pre.get().keys().merge(post.get().keys()).filter_map(|acc| AccountDiff::diff_pod(pre.get().get(acc), post.get().get(acc)).map(|d|(acc.clone(), d))).collect()) diff --git a/ethcore/src/substate.rs b/ethcore/src/substate.rs index 73ba267cd..a5c353351 100644 --- a/ethcore/src/substate.rs +++ b/ethcore/src/substate.rs @@ -1,3 +1,4 @@ +//! Execution environment substate. use common::*; /// State changes which should be applied in finalize, @@ -25,7 +26,7 @@ impl Substate { } } - /// TODO [Gav Wood] Please document me + /// Merge secondary substate `s` into self, accruing each element correspondingly. pub fn accrue(&mut self, s: Substate) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); @@ -57,4 +58,4 @@ mod tests { assert_eq!(sub_state.sstore_clears_count, x!(12)); assert_eq!(sub_state.suicides.len(), 1); } -} \ No newline at end of file +} diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 1923e9164..04d47cbd3 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -1,6 +1,7 @@ -use client::{BlockChainClient,Client}; +#[cfg(feature = "json-tests")] +use client::{BlockChainClient, Client}; use std::env; -use super::test_common::*; +use common::*; use std::path::PathBuf; use spec::*; use std::fs::{remove_dir_all}; @@ -8,6 +9,8 @@ use blockchain::{BlockChain}; use state::*; use rocksdb::*; + +#[cfg(feature = "json-tests")] pub enum ChainEra { Frontier, Homestead, @@ -43,10 +46,10 @@ impl Drop for RandomTempPath { } } -#[allow(dead_code)] +#[cfg(test)] pub struct GuardedTempResult { result: T, - temp: RandomTempPath + _temp: RandomTempPath } impl GuardedTempResult { @@ -111,6 +114,7 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&Transaction rlp.out() } +#[cfg(feature = "json-tests")] pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { let dir = RandomTempPath::new(); @@ -145,11 +149,12 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult client.import_verified_blocks(&IoChannel::disconnected()); GuardedTempResult::> { - temp: dir, + _temp: dir, result: client } } +#[cfg(feature = "json-tests")] pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { let dir = RandomTempPath::new(); let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); @@ -162,7 +167,7 @@ pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { - temp: dir, + _temp: dir, result: client } } @@ -175,7 +180,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult { - temp: temp, + _temp: temp, result: bc } } @@ -188,7 +193,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes } GuardedTempResult:: { - temp: temp, + _temp: temp, result: bc } } @@ -198,7 +203,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { let bc = BlockChain::new(&create_unverifiable_block(0, H256::zero()), temp.as_path()); GuardedTempResult:: { - temp: temp, + _temp: temp, result: bc } } @@ -208,7 +213,7 @@ pub fn get_temp_journal_db() -> GuardedTempResult { let db = DB::open_default(temp.as_str()).unwrap(); let journal_db = JournalDB::new(db); GuardedTempResult { - temp: temp, + _temp: temp, result: journal_db } } @@ -217,7 +222,7 @@ pub fn get_temp_state() -> GuardedTempResult { let temp = RandomTempPath::new(); let journal_db = get_temp_journal_db_in(temp.as_path()); GuardedTempResult { - temp: temp, + _temp: temp, result: State::new(journal_db, U256::from(0u8)) } } @@ -246,6 +251,7 @@ pub fn get_good_dummy_block() -> Bytes { create_test_block(&block_header) } +#[cfg(feature = "json-tests")] pub fn get_bad_state_dummy_block() -> Bytes { let mut block_header = Header::new(); let test_spec = get_test_spec(); diff --git a/ethcore/src/tests/mod.rs b/ethcore/src/tests/mod.rs index bda581eac..1630fabcd 100644 --- a/ethcore/src/tests/mod.rs +++ b/ethcore/src/tests/mod.rs @@ -1,11 +1 @@ -#[macro_use] -mod test_common; - -mod transaction; -mod executive; -mod state; -mod client; -mod chain; pub mod helpers; -mod homestead_state; -mod homestead_chain; \ No newline at end of file diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 24b617f67..00ea784d4 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -1,14 +1,16 @@ +//! Transaction data structure. + use util::*; use basic_types::*; use error::*; use evm::Schedule; #[derive(Debug, Clone)] -/// TODO [Gav Wood] Please document me +/// Transaction action type. pub enum Action { - /// TODO [Gav Wood] Please document me + /// Create creates new contract. Create, - /// TODO [debris] Please document me + /// Calls contract at given address. Call(Address), } @@ -20,25 +22,25 @@ impl Default for Action { /// or contract creation operation. #[derive(Default, Debug, Clone)] pub struct Transaction { - /// TODO [debris] Please document me + /// Nonce. pub nonce: U256, - /// TODO [debris] Please document me + /// Gas price. pub gas_price: U256, - /// TODO [debris] Please document me + /// Gas paid up front for transaction execution. pub gas: U256, - /// TODO [debris] Please document me + /// Action, can be either call or contract create. pub action: Action, - /// TODO [debris] Please document me + /// Transfered value. pub value: U256, - /// TODO [Gav Wood] Please document me + /// Transaction data. pub data: Bytes, // signature - /// TODO [Gav Wood] Please document me + /// The V field of the signature, either 27 or 28; helps describe the point on the curve. pub v: u8, - /// TODO [Gav Wood] Please document me + /// The R field of the signature; helps describe the point on the curve. pub r: U256, - /// TODO [debris] Please document me + /// The S field of the signature; helps describe the point on the curve. pub s: U256, hash: RefCell>, @@ -46,7 +48,9 @@ pub struct Transaction { } impl Transaction { - /// TODO [Gav Wood] Please document me + /// Create a new transaction. + #[cfg(test)] + #[cfg(feature = "json-tests")] pub fn new() -> Self { Transaction { nonce: x!(0), @@ -62,24 +66,9 @@ impl Transaction { sender: RefCell::new(None), } } - /// Create a new message-call transaction. - pub fn new_call(to: Address, value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction { - Transaction { - nonce: nonce, - gas_price: gas_price, - gas: gas, - action: Action::Call(to), - value: value, - data: data, - v: 0, - r: x!(0), - s: x!(0), - hash: RefCell::new(None), - sender: RefCell::new(None), - } - } /// Create a new contract-creation transaction. + #[cfg(test)] pub fn new_create(value: U256, data: Bytes, gas: U256, gas_price: U256, nonce: U256) -> Transaction { Transaction { nonce: nonce, @@ -96,19 +85,6 @@ impl Transaction { } } - /// Get the nonce of the transaction. - pub fn nonce(&self) -> &U256 { &self.nonce } - /// Get the gas price of the transaction. - pub fn gas_price(&self) -> &U256 { &self.gas_price } - /// Get the gas of the transaction. - pub fn gas(&self) -> &U256 { &self.gas } - /// Get the action of the transaction (Create or Call). - pub fn action(&self) -> &Action { &self.action } - /// Get the value of the transaction. - pub fn value(&self) -> &U256 { &self.value } - /// Get the data of the transaction. - pub fn data(&self) -> &Bytes { &self.data } - /// Append object into RLP stream, optionally with or without the signature. pub fn rlp_append_opt(&self, s: &mut RlpStream, with_seal: Seal) { s.begin_list(6 + match with_seal { Seal::With => 3, _ => 0 }); @@ -179,11 +155,6 @@ impl Transaction { } } - /// Note that some fields have changed. Resets the memoised hash. - pub fn note_dirty(&self) { - *self.hash.borrow_mut() = None; - } - /// 0 is `v` is 27, 1 if 28, and 4 otherwise. pub fn standard_v(&self) -> u8 { match self.v { 27 => 0, 28 => 1, _ => 4 } } @@ -216,6 +187,7 @@ impl Transaction { } /// Signs the transaction as coming from `sender`. + #[cfg(test)] pub fn signed(self, secret: &Secret) -> Transaction { let mut r = self; r.sign(secret); r } /// Get the transaction cost in gas for the given params. @@ -241,6 +213,9 @@ impl Transaction { } /// Do basic validation, checking for valid signature and minimum gas, + // TODO: consider use in block validation. + #[cfg(test)] + #[cfg(feature = "json-tests")] pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result { if require_low && !ec::is_low_s(&self.s) { return Err(Error::Util(UtilError::Crypto(CryptoError::InvalidSignature))); diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index 020f1b40f..efed43b84 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -154,7 +154,7 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> return Err(From::from(BlockError::InvalidStateRoot(Mismatch { expected: expected.state_root.clone(), found: got.state_root.clone() }))) } if expected.receipts_root != got.receipts_root { - return Err(From::from(BlockError::InvalidReceiptsStateRoot(Mismatch { expected: expected.receipts_root.clone(), found: got.receipts_root.clone() }))) + return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch { expected: expected.receipts_root.clone(), found: got.receipts_root.clone() }))) } Ok(()) } diff --git a/hook.sh b/hook.sh index a82f926b9..bb17f4e4f 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,3 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test" >> ./.git/hooks/pre-push +echo "#!/bin/sh\ncargo test -p ethcore" >> ./.git/hooks/pre-push chmod +x ./.git/hooks/pre-push diff --git a/install-deps.sh b/install-deps.sh new file mode 100755 index 000000000..b10d373b7 --- /dev/null +++ b/install-deps.sh @@ -0,0 +1,466 @@ +#!/usr/bin/env bash + +function run_installer() +{ + ####### Init vars + + HOMEBREW_PREFIX=/usr/local + HOMEBREW_CACHE=/Library/Caches/Homebrew + HOMEBREW_REPO=https://github.com/Homebrew/homebrew + OSX_REQUIERED_VERSION="10.7.0" + + + declare OS_TYPE + declare OSX_VERSION + declare GIT_PATH + declare RUBY_PATH + declare BREW_PATH + declare INSTALL_FILES="" + + errorMessages="" + isOsVersion=false + isGit=false + isRuby=false + isBrew=false + canContinue=true + depCount=0 + depFound=0 + + + + ####### Setup colors + + red=`tput setaf 1` + green=`tput setaf 2` + yellow=`tput setaf 3` + blue=`tput setaf 4` + magenta=`tput setaf 5` + cyan=`tput setaf 6` + white=`tput setaf 7` + b=`tput bold` + u=`tput sgr 0 1` + ul=`tput smul` + xl=`tput rmul` + stou=`tput smso` + xtou=`tput rmso` + dim=`tput dim` + reverse=`tput rev` + reset=`tput sgr0` + + + function head() { + echo "${blue}${b}==>${white} $1${reset}" + } + + function info() { + echo "${blue}${b}==>${reset} $1" + } + + function successHeading() { + echo "${green}${b}==> $1${reset}" + } + + function success() { + echo "${green}${b}==>${reset}${green} $1${reset}" + } + + function error() { + echo "${red}==> ${u}${b}${red}$1${reset}" + } + + function smallError() { + echo "${red}==>${reset} $1" + } + + function green() { + echo "${green}$1${reset}" + } + + function red() { + echo "${red}$1${reset}" + } + + function check() { + echo "${green}${bold} ✓${reset} $1${reset}" + } + + function uncheck() { + echo "${red}${bold} ✘${reset} $1${reset}" + } + + + + ####### Setup methods + + function wait_for_user() { + while : + do + read -p "${blue}==>${reset} $1 [Y/n] " imp + case $imp in + [yY] ) echo; break ;; + '' ) echo; break ;; + [nN] ) abortInstall "${red}==>${reset} Process stopped by user. To resume the install run the one-liner command again." ;; + * ) echo "Unrecognized option provided. Please provide either 'Y' or 'N'"; + esac + done + } + + + + function exe() { + echo "\$ $@"; "$@" + } + + function detectOS() { + if [[ "$OSTYPE" == "linux-gnu" ]] + then + OS_TYPE="linux" + get_linux_dependencies + elif [[ "$OSTYPE" == "darwin"* ]] + then + OS_TYPE="osx" + get_osx_dependencies + else + OS_TYPE="win" + abortInstall "${red}==>${reset} ${b}OS not supported:${reset} parity one-liner currently support OS X and Linux.\nFor instructions on installing parity on other platforms please visit ${u}${blue}http://ethcore.io/${reset}" + fi + + echo + + if [[ $depCount == $depFound ]] + then + green "Found all dependencies ($depFound/$depCount)" + else + if [[ $canContinue == true ]] + then + red "Some dependencies are missing ($depFound/$depCount)" + elif [[ $canContinue == false && $depFound == 0 ]] + then + red "All dependencies are missing and cannot be auto-installed ($depFound/$depCount)" + abortInstall "$errorMessages"; + elif [[ $canContinue == false ]] + then + red "Some dependencies which cannot be auto-installed are missing ($depFound/$depCount)" + abortInstall "$errorMessages"; + fi + fi + } + + function get_osx_dependencies() + { + macos_version + find_git + find_ruby + find_brew + } + + function macos_version() + { + declare -a reqVersion + declare -a localVersion + + depCount=$((depCount+1)) + OSX_VERSION=`/usr/bin/sw_vers -productVersion 2>/dev/null` + + if [ -z "$OSX_VERSION" ] + then + uncheck "OS X version not supported 🔥" + isOsVersion=false + canContinue=false + else + IFS='.' read -a localVersion <<< "$OSX_VERSION" + IFS='.' read -a reqVersion <<< "$OSX_REQUIERED_VERSION" + + if (( ${reqVersion[0]} <= ${localVersion[0]} )) && (( ${reqVersion[1]} <= ${localVersion[1]} )) + then + check "OS X Version ${OSX_VERSION}" + isOsVersion=true + depFound=$((depFound+1)) + return + else + uncheck "OS X version not supported" + isOsVersion=false + canContinue=false + fi + fi + + errorMessages+="${red}==>${reset} ${b}Mac OS version too old:${reset} eth requires OS X version ${red}$OSX_REQUIERED_VERSION${reset} at least in order to run.\n" + errorMessages+=" Please update the OS and reload the install process.\n" + } + + function find_eth() + { + ETH_PATH=`which eth 2>/dev/null` + + if [[ -f $ETH_PATH ]] + then + check "Found eth: $ETH_PATH" + echo "$($ETH_PATH -V)" + isEth=true + else + uncheck "Eth is missing" + isEth=false + fi + } + + function find_git() + { + depCount=$((depCount+1)) + + GIT_PATH=`which git 2>/dev/null` + + if [[ -f $GIT_PATH ]] + then + check "$($GIT_PATH --version)" + isGit=true + depFound=$((depFound+1)) + else + uncheck "Git is missing" + isGit=false + fi + } + + function find_ruby() + { + depCount=$((depCount+1)) + + RUBY_PATH=`which ruby 2>/dev/null` + + if [[ -f $RUBY_PATH ]] + then + RUBY_VERSION=`ruby -e "print RUBY_VERSION"` + check "Ruby ${RUBY_VERSION}" + isRuby=true + depFound=$((depFound+1)) + else + uncheck "Ruby is missing 🔥" + isRuby=false + canContinue=false + errorMessages+="${red}==>${reset} ${b}Couldn't find Ruby:${reset} Brew requires Ruby which could not be found.\n" + errorMessages+=" Please install Ruby using these instructions ${u}${blue}https://www.ruby-lang.org/en/documentation/installation/${reset}.\n" + fi + } + + function find_brew() + { + BREW_PATH=`which brew 2>/dev/null` + + if [[ -f $BREW_PATH ]] + then + check "$($BREW_PATH -v)" + isBrew=true + depFound=$((depFound+1)) + else + uncheck "Homebrew is missing" + isBrew=false + + INSTALL_FILES+="${blue}${dim}==> Homebrew:${reset}\n" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/bin/brew\n" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/Library\n" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/share/man/man1/brew.1\n" + fi + + depCount=$((depCount+1)) + } + + function install_brew() + { + if [[ $isBrew == false ]] + then + head "Installing Homebrew" + + if [[ $isRuby == true ]] + then + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + else + cd /usr + + if [[ ! -d $HOMEBREW_PREFIX ]] + then + sudo mkdir $HOMEBREW_PREFIX + sudo chmod g+rwx $HOMEBREW_PREFIX + fi + + if [[ ! -d $HOMEBREW_CACHE ]] + then + sudo mkdir $HOMEBREW_CACHE + sudo chmod g+rwx $HOMEBREW_CACHE + fi + + DEVELOPER_DIR=`/usr/bin/xcode-select -print-path 2>/dev/null` + + if [[ ! $(ls -A $DEVELOPER_DIR) || ! -f $DEVELOPER_DIR/usr/bin/git ]] + then + info "Installing the Command Line Tools (expect a GUI popup):" + sudo /usr/bin/xcode-select --install + + echo "Press any key when the installation has completed" + fi + + cd $HOMEBREW_PREFIX + + bash -o pipefail -c "curl -fsSL ${HOMEBREW_REPO}/tarball/master | tar xz -m --strip 1" + fi + + find_brew + echo + + if [[ $isBrew == false ]] + then + abortInstall "Couldn't install brew" + fi + fi + } + + function osx_installer() + { + osx_dependency_installer + + info "Updating brew" + exe brew update + echo + + info "Installing rocksdb" + exe brew install rocksdb + info "Installing multirust" + exe brew install multirust + sudo multirust update nightly + sudo multirust default nightly + echo + } + + function osx_dependency_installer() + { + if [[ $isGit == false ]]; + then + echo "Installing Git" + fi + + if [[ $isRuby == false ]]; + then + echo "Installing Ruby" + fi + + if [[ $isBrew == false ]]; + then + install_brew + fi + } + + function get_linux_dependencies() + { + find_apt + } + + function find_apt() + { + APT_PATH=`which apt-get 2>/dev/null` + + if [[ -f $APT_PATH ]] + then + check "apt-get" + echo "$($APT_PATH -v)" + isApt=true + else + uncheck "apt-get is missing" + isApt=false + fi + } + function linux_rocksdb_installer() + { + oldpwd=`pwd` + cd /tmp + exe git clone --branch v4.1 --depth=1 https://github.com/facebook/rocksdb.git + cd rocksdb + exe make shared_lib + sudo cp -a librocksdb.so* /usr/lib + sudo ldconfig + cd /tmp + rm -rf /tmp/rocksdb + cd $oldpwd + } + + function linux_installer() + { + info "Installing git" + sudo apt-get install -q -y git + echo + + info "Installing rocksdb" + linux_rocksdb_installer + echo + + info "Installing multirust" + curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes + sudo multirust update nightly + sudo multirust default nightly + echo + } + + function install() + { + echo + head "Installing Parity build dependencies" + + if [[ $OS_TYPE == "osx" ]] + then + osx_installer + elif [[ $OS_TYPE == "linux" ]] + then + linux_installer + fi + } + + function verify_installation() + { + info "Verifying installation" +# find_eth + +# if [[ $isEth == false ]] +# then +# abortInstall +# fi + } + + function abortInstall() + { + echo + error "Installation failed" + echo -e "$1" + echo + exit 0 + } + + function finish() + { +# echo +# successHeading "Installation successful!" +# head "Next steps" +# info "Run ${cyan}\`\`${reset} to get started.${reset}" +# echo + exit 0 + } + + # Check dependencies + head "Checking OS dependencies" + detectOS + + echo + head "In addition to the parity build dependencies, this script will install:" + echo "$INSTALL_FILES" + echo + + # Prompt user to continue or abort + wait_for_user "${b}OK,${reset} let's go!" + + # Install dependencies and eth + install + + # Check installation + verify_installation + + # Display goodby message + finish +} + +run_installer \ No newline at end of file diff --git a/install-parity.sh b/install-parity.sh new file mode 100755 index 000000000..848c25c6d --- /dev/null +++ b/install-parity.sh @@ -0,0 +1,475 @@ +#!/usr/bin/env bash + +function run_installer() +{ + ####### Init vars + + HOMEBREW_PREFIX=/usr/local + HOMEBREW_CACHE=/Library/Caches/Homebrew + HOMEBREW_REPO=https://github.com/Homebrew/homebrew + OSX_REQUIERED_VERSION="10.7.0" + + + declare OS_TYPE + declare OSX_VERSION + declare GIT_PATH + declare RUBY_PATH + declare BREW_PATH + declare INSTALL_FILES="" + + errorMessages="" + isOsVersion=false + isGit=false + isRuby=false + isBrew=false + canContinue=true + depCount=0 + depFound=0 + + + + ####### Setup colors + + red=`tput setaf 1` + green=`tput setaf 2` + yellow=`tput setaf 3` + blue=`tput setaf 4` + magenta=`tput setaf 5` + cyan=`tput setaf 6` + white=`tput setaf 7` + b=`tput bold` + u=`tput sgr 0 1` + ul=`tput smul` + xl=`tput rmul` + stou=`tput smso` + xtou=`tput rmso` + dim=`tput dim` + reverse=`tput rev` + reset=`tput sgr0` + + + function head() { + echo "${blue}${b}==>${white} $1${reset}" + } + + function info() { + echo "${blue}${b}==>${reset} $1" + } + + function successHeading() { + echo "${green}${b}==> $1${reset}" + } + + function success() { + echo "${green}${b}==>${reset}${green} $1${reset}" + } + + function error() { + echo "${red}==> ${u}${b}${red}$1${reset}" + } + + function smallError() { + echo "${red}==>${reset} $1" + } + + function green() { + echo "${green}$1${reset}" + } + + function red() { + echo "${red}$1${reset}" + } + + function check() { + echo "${green}${bold} ✓${reset} $1${reset}" + } + + function uncheck() { + echo "${red}${bold} ✘${reset} $1${reset}" + } + + + + ####### Setup methods + + function wait_for_user() { + while : + do + read -p "${blue}==>${reset} $1 [Y/n] " imp + case $imp in + [yY] ) echo; break ;; + '' ) echo; break ;; + [nN] ) abortInstall "${red}==>${reset} Process stopped by user. To resume the install run the one-liner command again." ;; + * ) echo "Unrecognized option provided. Please provide either 'Y' or 'N'"; + esac + done + } + + + + function exe() { + echo "\$ $@"; "$@" + } + + function detectOS() { + if [[ "$OSTYPE" == "linux-gnu" ]] + then + OS_TYPE="linux" + get_linux_dependencies + elif [[ "$OSTYPE" == "darwin"* ]] + then + OS_TYPE="osx" + get_osx_dependencies + else + OS_TYPE="win" + abortInstall "${red}==>${reset} ${b}OS not supported:${reset} parity one-liner currently support OS X and Linux.\nFor instructions on installing parity on other platforms please visit ${u}${blue}http://ethcore.io/${reset}" + fi + + echo + + if [[ $depCount == $depFound ]] + then + green "Found all dependencies ($depFound/$depCount)" + else + if [[ $canContinue == true ]] + then + red "Some dependencies are missing ($depFound/$depCount)" + elif [[ $canContinue == false && $depFound == 0 ]] + then + red "All dependencies are missing and cannot be auto-installed ($depFound/$depCount)" + abortInstall "$errorMessages"; + elif [[ $canContinue == false ]] + then + red "Some dependencies which cannot be auto-installed are missing ($depFound/$depCount)" + abortInstall "$errorMessages"; + fi + fi + } + + function get_osx_dependencies() + { + macos_version + find_git + find_ruby + find_brew + } + + function macos_version() + { + declare -a reqVersion + declare -a localVersion + + depCount=$((depCount+1)) + OSX_VERSION=`/usr/bin/sw_vers -productVersion 2>/dev/null` + + if [ -z "$OSX_VERSION" ] + then + uncheck "OS X version not supported 🔥" + isOsVersion=false + canContinue=false + else + IFS='.' read -a localVersion <<< "$OSX_VERSION" + IFS='.' read -a reqVersion <<< "$OSX_REQUIERED_VERSION" + + if (( ${reqVersion[0]} <= ${localVersion[0]} )) && (( ${reqVersion[1]} <= ${localVersion[1]} )) + then + check "OS X Version ${OSX_VERSION}" + isOsVersion=true + depFound=$((depFound+1)) + return + else + uncheck "OS X version not supported" + isOsVersion=false + canContinue=false + fi + fi + + errorMessages+="${red}==>${reset} ${b}Mac OS version too old:${reset} eth requires OS X version ${red}$OSX_REQUIERED_VERSION${reset} at least in order to run.\n" + errorMessages+=" Please update the OS and reload the install process.\n" + } + + function find_eth() + { + ETH_PATH=`which parity 2>/dev/null` + + if [[ -f $ETH_PATH ]] + then + check "Found parity: $ETH_PATH" + echo "$($ETH_PATH -V)" + isEth=true + else + uncheck "parity is missing" + isEth=false + fi + } + + function find_git() + { + depCount=$((depCount+1)) + + GIT_PATH=`which git 2>/dev/null` + + if [[ -f $GIT_PATH ]] + then + check "$($GIT_PATH --version)" + isGit=true + depFound=$((depFound+1)) + else + uncheck "Git is missing" + isGit=false + fi + } + + function find_ruby() + { + depCount=$((depCount+1)) + + RUBY_PATH=`which ruby 2>/dev/null` + + if [[ -f $RUBY_PATH ]] + then + RUBY_VERSION=`ruby -e "print RUBY_VERSION"` + check "Ruby ${RUBY_VERSION}" + isRuby=true + depFound=$((depFound+1)) + else + uncheck "Ruby is missing 🔥" + isRuby=false + canContinue=false + errorMessages+="${red}==>${reset} ${b}Couldn't find Ruby:${reset} Brew requires Ruby which could not be found.\n" + errorMessages+=" Please install Ruby using these instructions ${u}${blue}https://www.ruby-lang.org/en/documentation/installation/${reset}.\n" + fi + } + + function find_brew() + { + BREW_PATH=`which brew 2>/dev/null` + + if [[ -f $BREW_PATH ]] + then + check "$($BREW_PATH -v)" + isBrew=true + depFound=$((depFound+1)) + else + uncheck "Homebrew is missing" + isBrew=false + + INSTALL_FILES+="${blue}${dim}==> Homebrew:${reset}\n" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/bin/brew\n" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/Library\n" + INSTALL_FILES+=" ${blue}${dim}➜${reset} $HOMEBREW_PREFIX/share/man/man1/brew.1\n" + fi + + depCount=$((depCount+1)) + } + + function install_brew() + { + if [[ $isBrew == false ]] + then + head "Installing Homebrew" + + if [[ $isRuby == true ]] + then + ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + else + cd /usr + + if [[ ! -d $HOMEBREW_PREFIX ]] + then + sudo mkdir $HOMEBREW_PREFIX + sudo chmod g+rwx $HOMEBREW_PREFIX + fi + + if [[ ! -d $HOMEBREW_CACHE ]] + then + sudo mkdir $HOMEBREW_CACHE + sudo chmod g+rwx $HOMEBREW_CACHE + fi + + DEVELOPER_DIR=`/usr/bin/xcode-select -print-path 2>/dev/null` + + if [[ ! $(ls -A $DEVELOPER_DIR) || ! -f $DEVELOPER_DIR/usr/bin/git ]] + then + info "Installing the Command Line Tools (expect a GUI popup):" + sudo /usr/bin/xcode-select --install + + echo "Press any key when the installation has completed" + fi + + cd $HOMEBREW_PREFIX + + bash -o pipefail -c "curl -fsSL ${HOMEBREW_REPO}/tarball/master | tar xz -m --strip 1" + fi + + find_brew + echo + + if [[ $isBrew == false ]] + then + abortInstall "Couldn't install brew" + fi + fi + } + + function osx_installer() + { + osx_dependency_installer + + info "Adding ethcore repository" + exe brew tap ethcore/ethcore git@github.com:ethcore/homebrew-ethcore.git + echo + + info "Updating brew" + exe brew update + echo + + info "Installing parity" + if [[ $isEth == true ]] + then + exe brew reinstall parity + else + exe brew install parity + exe brew linkapps parity + fi + echo + } + + function osx_dependency_installer() + { + if [[ $isGit == false ]]; + then + echo "Installing Git" + fi + + if [[ $isRuby == false ]]; + then + echo "Installing Ruby" + fi + + if [[ $isBrew == false ]]; + then + install_brew + fi + } + + function get_linux_dependencies() + { + find_apt + } + + function find_apt() + { + APT_PATH=`which apt-get 2>/dev/null` + + if [[ -f $APT_PATH ]] + then + check "apt-get" + echo "$($APT_PATH -v)" + isApt=true + else + uncheck "apt-get is missing" + isApt=false + fi + } + function linux_rocksdb_installer() + { + oldpwd=`pwd` + cd /tmp + exe git clone --branch v4.1 --depth=1 https://github.com/facebook/rocksdb.git + cd rocksdb + exe make shared_lib + sudo cp -a librocksdb.so* /usr/lib + sudo ldconfig + cd /tmp + rm -rf /tmp/rocksdb + cd $oldpwd + } + + function linux_installer() + { + info "Installing git" + sudo apt-get install -q -y git + echo + + info "Installing rocksdb" + linux_rocksdb_installer + echo + + info "Installing multirust" + curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes + sudo multirust update nightly + sudo multirust default nightly + echo + + info "Installing parity" + wget --quiet --output-document=- http://ethcore.io/download/parity.deb | dpkg --install - + } + + function install() + { + echo + head "Installing Parity build dependencies" + + if [[ $OS_TYPE == "osx" ]] + then + osx_installer + elif [[ $OS_TYPE == "linux" ]] + then + linux_installer + fi + } + + function verify_installation() + { + info "Verifying installation" + find_eth + + if [[ $isEth == false ]] + then + abortInstall + fi + } + + function abortInstall() + { + echo + error "Installation failed" + echo -e "$1" + echo + exit 0 + } + + function finish() + { +# echo +# successHeading "Installation successful!" +# head "Next steps" +# info "Run ${cyan}\`\`${reset} to get started.${reset}" +# echo + exit 0 + } + + # Check dependencies + head "Checking OS dependencies" + detectOS + + echo + head "In addition to the parity build dependencies, this script will install:" + echo "$INSTALL_FILES" + echo + + # Prompt user to continue or abort + wait_for_user "${b}OK,${reset} let's go!" + + # Install dependencies and eth + install + + # Check installation + verify_installation + + # Display goodby message + finish +} + +run_installer diff --git a/sync/Cargo.toml b/sync/Cargo.toml index c3ae470fd..5f098bc26 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -13,4 +13,5 @@ ethcore = { path = ".." } clippy = "0.0.37" log = "0.3" env_logger = "0.3" +time = "0.1.34" diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 13158f95a..9752a5013 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -22,6 +22,7 @@ use range_collection::{RangeCollection, ToUsize, FromUsize}; use ethcore::error::*; use ethcore::block::Block; use io::SyncIo; +use time; impl ToUsize for BlockNumber { fn to_usize(&self) -> usize { @@ -61,6 +62,8 @@ const RECEIPTS_PACKET: u8 = 0x10; const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent +const CONNECTION_TIMEOUT_SEC: f64 = 30f64; + struct Header { /// Header data data: Bytes, @@ -138,6 +141,8 @@ struct PeerInfo { asking: PeerAsking, /// A set of block numbers being requested asking_blocks: Vec, + /// Request timestamp + ask_time: f64, } /// Blockchain sync handler. @@ -250,6 +255,7 @@ impl ChainSync { genesis: try!(r.val_at(4)), asking: PeerAsking::Nothing, asking_blocks: Vec::new(), + ask_time: 0f64, }; trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest, peer.genesis); @@ -408,6 +414,7 @@ impl ChainSync { trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h); let header_view = HeaderView::new(header_rlp.as_raw()); // TODO: Decompose block and add to self.headers and self.bodies instead + let mut unknown = false; if header_view.number() == From::from(self.last_imported_block + 1) { match io.chain().import_block(block_rlp.as_raw().to_vec()) { Err(ImportError::AlreadyInChain) => { @@ -416,6 +423,10 @@ impl ChainSync { Err(ImportError::AlreadyQueued) => { trace!(target: "sync", "New block already queued {:?}", h); }, + Err(ImportError::UnknownParent) => { + unknown = true; + trace!(target: "sync", "New block with unknown parent {:?}", h); + }, Ok(_) => { trace!(target: "sync", "New block queued {:?}", h); }, @@ -426,6 +437,9 @@ impl ChainSync { }; } else { + unknown = true; + } + if unknown { trace!(target: "sync", "New block unknown {:?}", h); //TODO: handle too many unknown blocks let difficulty: U256 = try!(r.val_at(1)); @@ -795,6 +809,7 @@ impl ChainSync { Ok(_) => { let mut peer = self.peers.get_mut(&peer_id).unwrap(); peer.asking = asking; + peer.ask_time = time::precise_time_s(); } } } @@ -969,6 +984,16 @@ impl ChainSync { }) } + /// Handle peer timeouts + pub fn maintain_peers(&self, io: &mut SyncIo) { + let tick = time::precise_time_s(); + for (peer_id, peer) in &self.peers { + if peer.asking != PeerAsking::Nothing && (tick - peer.ask_time) > CONNECTION_TIMEOUT_SEC { + io.disconnect_peer(*peer_id); + } + } + } + /// Maintain other peers. Send out any new blocks and transactions pub fn _maintain_sync(&mut self, _io: &mut SyncIo) { } diff --git a/sync/src/io.rs b/sync/src/io.rs index 4425a2555..8f415f582 100644 --- a/sync/src/io.rs +++ b/sync/src/io.rs @@ -9,6 +9,8 @@ use ethcore::service::SyncMessage; pub trait SyncIo { /// Disable a peer fn disable_peer(&mut self, peer_id: PeerId); + /// Disconnect peer + fn disconnect_peer(&mut self, peer_id: PeerId); /// Respond to current request with a packet. Can be called from an IO handler for incoming packet. fn respond(&mut self, packet_id: PacketId, data: Vec) -> Result<(), UtilError>; /// Send a packet to a peer. @@ -42,6 +44,10 @@ impl<'s, 'h> SyncIo for NetSyncIo<'s, 'h> { self.network.disable_peer(peer_id); } + fn disconnect_peer(&mut self, peer_id: PeerId) { + self.network.disconnect_peer(peer_id); + } + fn respond(&mut self, packet_id: PacketId, data: Vec) -> Result<(), UtilError>{ self.network.respond(packet_id, data) } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 09f3eb521..40b67dc5b 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -33,11 +33,13 @@ extern crate log; extern crate ethcore_util as util; extern crate ethcore; extern crate env_logger; +extern crate time; use std::ops::*; use std::sync::*; use ethcore::client::Client; use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId}; +use util::io::TimerToken; use chain::ChainSync; use ethcore::service::SyncMessage; use io::NetSyncIo; @@ -87,7 +89,8 @@ impl EthSync { } impl NetworkProtocolHandler for EthSync { - fn initialize(&self, _io: &NetworkContext) { + fn initialize(&self, io: &NetworkContext) { + io.register_timer(0, 1000).expect("Error registering sync timer"); } fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { @@ -101,6 +104,10 @@ impl NetworkProtocolHandler for EthSync { fn disconnected(&self, io: &NetworkContext, peer: &PeerId) { self.sync.write().unwrap().on_peer_aborting(&mut NetSyncIo::new(io, self.chain.deref()), *peer); } + + fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { + self.sync.write().unwrap().maintain_peers(&mut NetSyncIo::new(io, self.chain.deref())); + } } diff --git a/sync/src/service.rs b/sync/src/service.rs deleted file mode 100644 index 8c900d20a..000000000 --- a/sync/src/service.rs +++ /dev/null @@ -1,104 +0,0 @@ -use util::*; -use sync::*; -use spec::Spec; -use error::*; -use std::env; -use client::Client; - -/// Message type for external and internal events -#[derive(Clone)] -pub enum SyncMessage { - /// New block has been imported into the blockchain - NewChainBlock(Bytes), //TODO: use Cow - /// A block is ready - BlockVerified, -} - -/// TODO [arkpar] Please document me -pub type NetSyncMessage = NetworkIoMessage; - -/// Client service setup. Creates and registers client and network services with the IO subsystem. -pub struct ClientService { - net_service: NetworkService, - client: Arc, - sync: Arc, -} - -impl ClientService { - /// Start the service in a separate thread. - pub fn start(spec: Spec, net_config: NetworkConfiguration) -> Result { - let mut net_service = try!(NetworkService::start(net_config)); - 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"); - dir.push(H64::from(spec.genesis_header().hash()).hex()); - let client = try!(Client::new(spec, &dir, net_service.io().channel())); - let sync = EthSync::register(&mut net_service, client.clone()); - let client_io = Arc::new(ClientIoHandler { - client: client.clone() - }); - try!(net_service.io().register_handler(client_io)); - - Ok(ClientService { - net_service: net_service, - client: client, - sync: sync, - }) - } - - /// Get the network service. - pub fn add_node(&mut self, _enode: &str) { - unimplemented!(); - } - - /// TODO [arkpar] Please document me - pub fn io(&mut self) -> &mut IoService { - self.net_service.io() - } - - /// TODO [arkpar] Please document me - pub fn client(&self) -> Arc { - self.client.clone() - - } - - /// Get shared sync handler - pub fn sync(&self) -> Arc { - self.sync.clone() - } -} - -/// IO interface for the Client handler -struct ClientIoHandler { - client: Arc -} - -const CLIENT_TICK_TIMER: TimerToken = 0; -const CLIENT_TICK_MS: u64 = 5000; - -impl IoHandler for ClientIoHandler { - fn initialize(&self, io: &IoContext) { - io.register_timer(CLIENT_TICK_TIMER, CLIENT_TICK_MS).expect("Error registering client timer"); - } - - fn timeout(&self, _io: &IoContext, timer: TimerToken) { - if timer == CLIENT_TICK_TIMER { - self.client.tick(); - } - } - - #[allow(match_ref_pats)] - #[allow(single_match)] - fn message(&self, io: &IoContext, net_message: &NetSyncMessage) { - if let &UserMessage(ref message) = net_message { - match message { - &SyncMessage::BlockVerified => { - self.client.import_verified_blocks(&io.channel()); - }, - _ => {}, // ignore other messages - } - } - } -} - diff --git a/sync/src/tests.rs b/sync/src/tests.rs index 41516ef60..5b796e6f1 100644 --- a/sync/src/tests.rs +++ b/sync/src/tests.rs @@ -209,6 +209,9 @@ impl<'p> SyncIo for TestIo<'p> { fn disable_peer(&mut self, _peer_id: PeerId) { } + fn disconnect_peer(&mut self, _peer_id: PeerId) { + } + fn respond(&mut self, packet_id: PacketId, data: Vec) -> Result<(), UtilError> { self.queue.push_back(TestPacket { data: data, diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 050c07a66..f6c83081d 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -83,11 +83,12 @@ impl<'a> fmt::Display for PrettySlice<'a> { } } -/// TODO [Gav Wood] Please document me +/// Trait to allow a type to be pretty-printed in `format!`, where unoverridable +/// defaults cannot otherwise be avoided. pub trait ToPretty { - /// TODO [Gav Wood] Please document me + /// Convert a type into a derivative form in order to make `format!` print it prettily. fn pretty(&self) -> PrettySlice; - /// TODO [Gav Wood] Please document me + /// Express the object as a hex string. fn to_hex(&self) -> String { format!("{}", self.pretty()) } @@ -110,11 +111,11 @@ impl ToPretty for Bytes { } } -/// TODO [debris] Please document me +/// A byte collection reference that can either be a slice or a vector pub enum BytesRef<'a> { - /// TODO [debris] Please document me + /// This is a reference to a vector Flexible(&'a mut Bytes), - /// TODO [debris] Please document me + /// This is a reference to a slice Fixed(&'a mut [u8]) } @@ -144,11 +145,12 @@ pub type Bytes = Vec; /// Slice of bytes to underlying memory pub trait BytesConvertable { // TODO: rename to as_slice - /// TODO [Gav Wood] Please document me + /// Get the underlying byte-wise representation of the value. + /// Deprecated - use `as_slice` instead. fn bytes(&self) -> &[u8]; - /// TODO [Gav Wood] Please document me + /// Get the underlying byte-wise representation of the value. fn as_slice(&self) -> &[u8] { self.bytes() } - /// TODO [Gav Wood] Please document me + /// Get a copy of the underlying byte-wise representation. fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() } } diff --git a/util/src/chainfilter.rs b/util/src/chainfilter.rs index 64f9e7d39..ad7f965dc 100644 --- a/util/src/chainfilter.rs +++ b/util/src/chainfilter.rs @@ -49,9 +49,9 @@ use sha3::*; /// index. Their `BloomIndex` can be created from block number and given level. #[derive(Eq, PartialEq, Hash, Clone, Debug)] pub struct BloomIndex { - /// TODO [debris] Please document me + /// Bloom level pub level: u8, - /// TODO [debris] Please document me + /// Filter Index pub index: usize, } diff --git a/util/src/common.rs b/util/src/common.rs index 9cf7a3765..bfc883a6b 100644 --- a/util/src/common.rs +++ b/util/src/common.rs @@ -48,7 +48,7 @@ macro_rules! flushln { ($fmt:expr, $($arg:tt)*) => (flush!(concat!($fmt, "\n"), $($arg)*)); } -/// TODO [Gav Wood] Please document me +#[doc(hidden)] pub fn flush(s: String) { ::std::io::stdout().write(s.as_bytes()).unwrap(); ::std::io::stdout().flush().unwrap(); diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 8a56c8827..0f147da1f 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -6,11 +6,12 @@ use uint::*; use secp256k1::{key, Secp256k1}; use rand::os::OsRng; -/// TODO [Gav Wood] Please document me +/// Secret key for secp256k1 EC operations. 256 bit generic "hash" data. pub type Secret = H256; -/// TODO [Gav Wood] Please document me +/// Public key for secp256k1 EC operations. 512 bit generic "hash" data. pub type Public = H512; -/// TODO [Gav Wood] Please document me +/// Signature for secp256k1 EC operations; encodes two 256-bit curve points +/// and a third sign bit. 520 bit generic "hash" data. pub type Signature = H520; lazy_static! { @@ -38,17 +39,17 @@ impl Signature { } #[derive(Debug)] -/// TODO [arkpar] Please document me +/// Crypto error pub enum CryptoError { - /// TODO [arkpar] Please document me + /// Invalid secret key InvalidSecret, - /// TODO [arkpar] Please document me + /// Invalid public key InvalidPublic, - /// TODO [arkpar] Please document me + /// Invalid EC signature InvalidSignature, - /// TODO [arkpar] Please document me + /// Invalid AES message InvalidMessage, - /// TODO [arkpar] Please document me + /// IO Error Io(::std::io::Error), } @@ -133,7 +134,7 @@ impl KeyPair { pub fn sign(&self, message: &H256) -> Result { ec::sign(&self.secret, message) } } -/// TODO [arkpar] Please document me +/// EC functions pub mod ec { use hash::*; use uint::*; @@ -210,12 +211,12 @@ pub mod ec { } } -/// TODO [arkpar] Please document me +/// ECDH functions pub mod ecdh { use crypto::*; use crypto::{self}; - /// TODO [arkpar] Please document me + /// Agree on a shared secret pub fn agree(secret: &Secret, public: &Public, ) -> Result { use secp256k1::*; let context = &crypto::SECP256K1; @@ -231,13 +232,13 @@ pub mod ecdh { } } -/// TODO [arkpar] Please document me +/// ECIES function pub mod ecies { use hash::*; use bytes::*; use crypto::*; - /// TODO [arkpar] Please document me + /// Encrypt a message with a public key pub fn encrypt(public: &Public, plain: &[u8]) -> Result { use ::rcrypto::digest::Digest; use ::rcrypto::sha2::Sha256; @@ -273,7 +274,7 @@ pub mod ecies { Ok(msg) } - /// TODO [arkpar] Please document me + /// Decrypt a message with a secret key pub fn decrypt(secret: &Secret, encrypted: &[u8]) -> Result { use ::rcrypto::digest::Digest; use ::rcrypto::sha2::Sha256; @@ -339,20 +340,20 @@ pub mod ecies { } } -/// TODO [arkpar] Please document me +/// AES encryption pub mod aes { use ::rcrypto::blockmodes::*; use ::rcrypto::aessafe::*; use ::rcrypto::symmetriccipher::*; use ::rcrypto::buffer::*; - /// TODO [arkpar] Please document me + /// Encrypt a message pub fn encrypt(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) { let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); } - /// TODO [arkpar] Please document me + /// Decrypt a message pub fn decrypt(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) { let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); diff --git a/util/src/error.rs b/util/src/error.rs index 0d13d329c..4d2e0943b 100644 --- a/util/src/error.rs +++ b/util/src/error.rs @@ -6,36 +6,36 @@ use rlp::DecoderError; use io; #[derive(Debug)] -/// TODO [Gav Wood] Please document me +/// Error in database subsystem. pub enum BaseDataError { - /// TODO [Gav Wood] Please document me + /// An entry was removed more times than inserted. NegativelyReferencedHash, } #[derive(Debug)] /// General error type which should be capable of representing all errors in ethcore. pub enum UtilError { - /// TODO [Gav Wood] Please document me + /// Error concerning the crypto utility subsystem. Crypto(::crypto::CryptoError), - /// TODO [Gav Wood] Please document me + /// Error concerning the Rust standard library's IO subsystem. StdIo(::std::io::Error), - /// TODO [Gav Wood] Please document me + /// Error concerning our IO utility subsystem. Io(io::IoError), - /// TODO [Gav Wood] Please document me + /// Error concerning the network address parsing subsystem. AddressParse(::std::net::AddrParseError), - /// TODO [Gav Wood] Please document me + /// Error concerning the network address resolution subsystem. AddressResolve(Option<::std::io::Error>), - /// TODO [Gav Wood] Please document me + /// Error concerning the hex conversion logic. FromHex(FromHexError), - /// TODO [Gav Wood] Please document me + /// Error concerning the database abstraction logic. BaseData(BaseDataError), - /// TODO [Gav Wood] Please document me + /// Error concerning the network subsystem. Network(NetworkError), - /// TODO [Gav Wood] Please document me + /// Error concerning the RLP decoder. Decoder(DecoderError), - /// TODO [Gav Wood] Please document me + /// Miscellaneous error described by a string. SimpleString(String), - /// TODO [Gav Wood] Please document me + /// Error from a bad input size being given for the needed output. BadSize, } diff --git a/util/src/from_json.rs b/util/src/from_json.rs index 7319ec8aa..63469ea61 100644 --- a/util/src/from_json.rs +++ b/util/src/from_json.rs @@ -9,8 +9,8 @@ macro_rules! xjson { } } -/// TODO [Gav Wood] Please document me +/// Trait allowing conversion from a JSON value. pub trait FromJson { - /// TODO [Gav Wood] Please document me + /// Convert a JSON value to an instance of this type. fn from_json(json: &Json) -> Self; } diff --git a/util/src/hash.rs b/util/src/hash.rs index b3154b57a..68611f7b4 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -15,35 +15,35 @@ use serde; /// /// Note: types implementing `FixedHash` must be also `BytesConvertable`. pub trait FixedHash: Sized + BytesConvertable + Populatable + FromStr + Default { - /// TODO [Gav Wood] Please document me + /// Create a new, zero-initialised, instance. fn new() -> Self; /// Synonym for `new()`. Prefer to new as it's more readable. fn zero() -> Self; - /// TODO [debris] Please document me + /// Create a new, cryptographically random, instance. fn random() -> Self; - /// TODO [debris] Please document me + /// Assign self have a cryptographically random value. fn randomize(&mut self); - /// TODO [arkpar] Please document me - fn size() -> usize; - /// TODO [arkpar] Please document me + /// Get the size of this object in bytes. + fn len() -> usize; + /// Convert a slice of bytes of length `len()` to an instance of this type. fn from_slice(src: &[u8]) -> Self; - /// TODO [arkpar] Please document me + /// Assign self to be of the same value as a slice of bytes of length `len()`. fn clone_from_slice(&mut self, src: &[u8]) -> usize; - /// TODO [Gav Wood] Please document me + /// Copy the data of this object into some mutable slice of length `len()`. fn copy_to(&self, dest: &mut [u8]); - /// TODO [Gav Wood] Please document me + /// When interpreting self as a bloom output, augment (bit-wise OR) with the a bloomed version of `b`. fn shift_bloomed<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash; - /// TODO [debris] Please document me + /// Same as `shift_bloomed` except that `self` is consumed and a new value returned. fn with_bloomed(mut self, b: &T) -> Self where T: FixedHash { self.shift_bloomed(b); self } - /// TODO [Gav Wood] Please document me + /// Bloom the current value using the bloom parameter `m`. fn bloom_part(&self, m: usize) -> T where T: FixedHash; - /// TODO [debris] Please document me + /// Check to see whether this hash, interpreted as a bloom, contains the value `b` when bloomed. fn contains_bloomed(&self, b: &T) -> bool where T: FixedHash; - /// TODO [arkpar] Please document me + /// Returns `true` if all bits set in `b` are also set in `self`. fn contains<'a>(&'a self, b: &'a Self) -> bool; - /// TODO [debris] Please document me + /// Returns `true` if no bits are set. fn is_zero(&self) -> bool; - /// Return the lowest 8 bytes interpreted as a BigEndian integer. + /// Returns the lowest 8 bytes interpreted as a BigEndian integer. fn low_u64(&self) -> u64; } @@ -58,7 +58,7 @@ fn clean_0x(s: &str) -> &str { macro_rules! impl_hash { ($from: ident, $size: expr) => { #[derive(Eq)] - /// TODO [Gav Wood] Please document me + /// Unformatted binary data of fixed length. pub struct $from (pub [u8; $size]); impl BytesConvertable for $from { @@ -103,7 +103,7 @@ macro_rules! impl_hash { rng.fill_bytes(&mut self.0); } - fn size() -> usize { + fn len() -> usize { $size } @@ -457,12 +457,12 @@ macro_rules! impl_hash { } impl $from { - /// TODO [Gav Wood] Please document me + /// Get a hex representation. pub fn hex(&self) -> String { format!("{:?}", self) } - /// TODO [Gav Wood] Please document me + /// Construct new instance equal to the bloomed value of `b`. pub fn from_bloomed(b: &T) -> Self where T: FixedHash { b.bloom_part($size) } } @@ -578,25 +578,27 @@ impl<'_> From<&'_ Address> for H256 { } } -/// TODO [Gav Wood] Please document me +/// Convert string `s` to an `H256`. Will panic if `s` is not 64 characters long or if any of +/// those characters are not 0-9, a-z or A-Z. pub fn h256_from_hex(s: &str) -> H256 { use std::str::FromStr; H256::from_str(s).unwrap() } -/// TODO [Gav Wood] Please document me +/// Convert `n` to an `H256`, setting the rightmost 8 bytes. pub fn h256_from_u64(n: u64) -> H256 { use uint::U256; H256::from(&U256::from(n)) } -/// TODO [Gav Wood] Please document me +/// Convert string `s` to an `Address`. Will panic if `s` is not 40 characters long or if any of +/// those characters are not 0-9, a-z or A-Z. pub fn address_from_hex(s: &str) -> Address { use std::str::FromStr; Address::from_str(s).unwrap() } -/// TODO [Gav Wood] Please document me +/// Convert `n` to an `Address`, setting the rightmost 8 bytes. pub fn address_from_u64(n: u64) -> Address { let h256 = h256_from_u64(n); From::from(h256) diff --git a/util/src/io/mod.rs b/util/src/io/mod.rs index f81732ce1..e421416ee 100644 --- a/util/src/io/mod.rs +++ b/util/src/io/mod.rs @@ -42,9 +42,9 @@ mod worker; use mio::{EventLoop, Token}; #[derive(Debug)] -/// TODO [arkpar] Please document me +/// IO Error pub enum IoError { - /// TODO [arkpar] Please document me + /// Low level error from mio crate Mio(::std::io::Error), } @@ -78,19 +78,12 @@ pub trait IoHandler: Send + Sync where Message: Send + Sync + Clone + ' fn deregister_stream(&self, _stream: StreamToken, _event_loop: &mut EventLoop>) {} } -/// TODO [arkpar] Please document me pub use io::service::TimerToken; -/// TODO [arkpar] Please document me pub use io::service::StreamToken; -/// TODO [arkpar] Please document me pub use io::service::IoContext; -/// TODO [arkpar] Please document me pub use io::service::IoService; -/// TODO [arkpar] Please document me pub use io::service::IoChannel; -/// TODO [arkpar] Please document me pub use io::service::IoManager; -/// TODO [arkpar] Please document me pub use io::service::TOKENS_PER_HANDLER; #[cfg(test)] diff --git a/util/src/json_aid.rs b/util/src/json_aid.rs index 5974c5989..7ca75a34f 100644 --- a/util/src/json_aid.rs +++ b/util/src/json_aid.rs @@ -1,6 +1,6 @@ use common::*; -/// TODO [Gav Wood] Please document me +/// Remove the `"0x"`, if present, from the left of `s`, returning the remaining slice. pub fn clean(s: &str) -> &str { if s.len() >= 2 && &s[0..2] == "0x" { &s[2..] diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index f2935cceb..71addda3c 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -107,14 +107,17 @@ impl MemoryDB { self.data.get(key) } - /// TODO [Gav Wood] Please document me + /// Return the internal map of hashes to data, clearing the current state. pub fn drain(&mut self) -> HashMap { let mut data = HashMap::new(); mem::swap(&mut self.data, &mut data); data } - /// TODO [Gav Wood] Please document me + /// Denote than an existing value has the given key. Used when a key gets removed without + /// a prior insert and thus has a negative reference with no value. + /// + /// May safely be called even if the key's value is known, in which case it will be a no-op. pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) { if self.raw(key) == None { unsafe { diff --git a/util/src/misc.rs b/util/src/misc.rs index f0e34d4c9..2c98179f3 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -5,13 +5,13 @@ use common::*; #[derive(Debug,Clone,PartialEq,Eq)] /// Diff type for specifying a change (or not). pub enum Diff where T: Eq { - /// TODO [Gav Wood] Please document me + /// Both sides are the same. Same, - /// TODO [Gav Wood] Please document me + /// Left (pre, source) side doesn't include value, right side (post, destination) does. Born(T), - /// TODO [Gav Wood] Please document me + /// Both sides include data; it chaged value between them. Changed(T, T), - /// TODO [Gav Wood] Please document me + /// Left (pre, source) side does include value, right side (post, destination) does not. Died(T), } @@ -32,8 +32,8 @@ impl Diff where T: Eq { #[derive(PartialEq,Eq,Clone,Copy)] /// Boolean type for clean/dirty status. pub enum Filth { - /// TODO [Gav Wood] Please document me + /// Data has not been changed. Clean, - /// TODO [Gav Wood] Please document me + /// Data has been changed. Dirty, } diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 0ca127ecc..f91c38b04 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -216,6 +216,12 @@ pub struct EncryptedConnection { } impl EncryptedConnection { + + /// Get socket token + pub fn token(&self) -> StreamToken { + self.connection.token + } + /// Create an encrypted connection out of the handshake. Consumes a handshake object. pub fn new(mut handshake: Handshake) -> Result { let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public)); @@ -607,4 +613,4 @@ mod tests { assert!(!status.is_ok()); assert_eq!(1, connection.send_queue.len()); } -} \ No newline at end of file +} diff --git a/util/src/network/error.rs b/util/src/network/error.rs index b9dfdc892..78f015c37 100644 --- a/util/src/network/error.rs +++ b/util/src/network/error.rs @@ -5,17 +5,17 @@ use rlp::*; pub enum DisconnectReason { DisconnectRequested, - //TCPError, - //BadProtocol, + _TCPError, + _BadProtocol, UselessPeer, - //TooManyPeers, - //DuplicatePeer, - //IncompatibleProtocol, - //NullIdentity, - //ClientQuit, - //UnexpectedIdentity, - //LocalIdentity, - //PingTimeout, + _TooManyPeers, + _DuplicatePeer, + _IncompatibleProtocol, + _NullIdentity, + _ClientQuit, + _UnexpectedIdentity, + _LocalIdentity, + PingTimeout, } #[derive(Debug)] diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 4e0ae6092..5a572dcae 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -19,6 +19,7 @@ use io::*; use network::NetworkProtocolHandler; use network::node::*; use network::stats::NetworkStats; +use network::error::DisconnectReason; type Slab = ::slab::Slab; @@ -108,6 +109,8 @@ pub enum NetworkIoMessage where Message: Send + Sync + Clone { /// Timer delay in milliseconds. delay: u64, }, + /// Disconnect a peer + Disconnect(PeerId), /// User message User(Message), } @@ -181,8 +184,14 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone } /// Disable current protocol capability for given peer. If no capabilities left peer gets disconnected. - pub fn disable_peer(&self, _peer: PeerId) { + pub fn disable_peer(&self, peer: PeerId) { //TODO: remove capability, disconnect if no capabilities left + self.disconnect_peer(peer); + } + + /// Disconnect peer. Reconnect can be attempted later. + pub fn disconnect_peer(&self, peer: PeerId) { + self.io.message(NetworkIoMessage::Disconnect(peer)); } /// Register a new IO timer. 'IoHandler::timeout' will be called with the token. @@ -332,6 +341,7 @@ impl Host where Message: Send + Sync + Clone { } fn maintain_network(&self, io: &IoContext>) { + self.keep_alive(io); self.connect_peers(io); } @@ -343,6 +353,21 @@ impl Host where Message: Send + Sync + Clone { self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false }) } + fn keep_alive(&self, io: &IoContext>) { + 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() { + s.disconnect(DisconnectReason::PingTimeout); + to_kill.push(s.token()); + } + } + } + for p in to_kill { + self.kill_connection(p, io); + } + } + fn connect_peers(&self, io: &IoContext>) { struct NodeInfo { id: NodeId, @@ -684,6 +709,15 @@ impl IoHandler> for Host where Messa self.timers.write().unwrap().insert(handler_token, ProtocolTimer { protocol: protocol, token: *token }); io.register_timer(handler_token, *delay).expect("Error registering timer"); }, + NetworkIoMessage::Disconnect(ref peer) => { + if let Some(connection) = self.connections.read().unwrap().get(*peer).cloned() { + match *connection.lock().unwrap().deref_mut() { + ConnectionEntry::Handshake(_) => {}, + ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); } + } + } + self.kill_connection(*peer, io); + }, NetworkIoMessage::User(ref message) => { for (p, h) in self.handlers.read().unwrap().iter() { h.message(&NetworkContext::new(io, p, None, self.connections.clone()), &message); diff --git a/util/src/network/service.rs b/util/src/network/service.rs index cbf400872..41a23cda6 100644 --- a/util/src/network/service.rs +++ b/util/src/network/service.rs @@ -21,7 +21,7 @@ impl NetworkService where Message: Send + Sync + Clone + 'stat let host = Arc::new(Host::new(config)); let stats = host.stats().clone(); let host_info = host.client_version(); - info!("NetworkService::start(): id={:?}", host.client_id()); + info!("Host ID={:?}", host.client_id()); try!(io_service.register_handler(host)); Ok(NetworkService { io_service: io_service, diff --git a/util/src/network/session.rs b/util/src/network/session.rs index fb385b487..41e8e9c5d 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -4,10 +4,14 @@ use rlp::*; use network::connection::{EncryptedConnection, Packet}; use network::handshake::Handshake; use error::*; -use io::{IoContext}; +use io::{IoContext, StreamToken}; use network::error::{NetworkError, DisconnectReason}; use network::host::*; use network::node::NodeId; +use time; + +const PING_TIMEOUT_SEC: u64 = 30; +const PING_INTERVAL_SEC: u64 = 30; /// Peer session over encrypted connection. /// When created waits for Hello packet exchange and signals ready state. @@ -19,6 +23,8 @@ pub struct Session { connection: EncryptedConnection, /// Session ready flag. Set after successfull Hello packet exchange had_hello: bool, + ping_time_ns: u64, + pong_time_ns: Option, } /// Structure used to report various session events. @@ -47,6 +53,8 @@ pub struct SessionInfo { pub protocol_version: u32, /// Peer protocol capabilities capabilities: Vec, + /// Peer ping delay in milliseconds + pub ping_ms: Option, } #[derive(Debug, PartialEq, Eq)] @@ -95,10 +103,13 @@ impl Session { client_version: String::new(), protocol_version: 0, capabilities: Vec::new(), + ping_ms: None, }, + ping_time_ns: 0, + pong_time_ns: None, }; try!(session.write_hello(host)); - try!(session.write_ping()); + try!(session.send_ping()); Ok(session) } @@ -141,7 +152,7 @@ impl Session { while protocol != self.info.capabilities[i].protocol { i += 1; if i == self.info.capabilities.len() { - debug!(target: "net", "Unkown protocol: {:?}", protocol); + debug!(target: "net", "Unknown protocol: {:?}", protocol); return Ok(()) } } @@ -152,6 +163,26 @@ impl Session { self.connection.send_packet(&rlp.out()) } + /// Keep this session alive. Returns false if ping timeout happened + pub fn keep_alive(&mut self) -> bool { + let timed_out = if let Some(pong) = self.pong_time_ns { + pong - self.ping_time_ns > PING_TIMEOUT_SEC * 1000_000_000 + } else { + time::precise_time_ns() - self.ping_time_ns > PING_TIMEOUT_SEC * 1000_000_000 + }; + + if !timed_out && time::precise_time_ns() - self.ping_time_ns > PING_INTERVAL_SEC * 1000_000_000 { + if let Err(e) = self.send_ping() { + debug!("Error sending ping message: {:?}", e); + } + } + !timed_out + } + + pub fn token(&self) -> StreamToken { + self.connection.token() + } + fn read_packet(&mut self, packet: Packet, host: &HostInfo) -> Result { if packet.data.len() < 2 { return Err(From::from(NetworkError::BadProtocol)); @@ -168,7 +199,12 @@ impl Session { }, PACKET_DISCONNECT => Err(From::from(NetworkError::Disconnect(DisconnectReason::DisconnectRequested))), PACKET_PING => { - try!(self.write_pong()); + try!(self.send_pong()); + Ok(SessionData::None) + }, + PACKET_PONG => { + self.pong_time_ns = Some(time::precise_time_ns()); + self.info.ping_ms = Some((self.pong_time_ns.unwrap() - self.ping_time_ns) / 1000_000); Ok(SessionData::None) }, PACKET_GET_PEERS => Ok(SessionData::None), //TODO; @@ -178,7 +214,7 @@ impl Session { while packet_id < self.info.capabilities[i].id_offset { i += 1; if i == self.info.capabilities.len() { - debug!(target: "net", "Unkown packet: {:?}", packet_id); + debug!(target: "net", "Unknown packet: {:?}", packet_id); return Ok(SessionData::None) } } @@ -189,7 +225,7 @@ impl Session { Ok(SessionData::Packet { data: packet.data, protocol: protocol, packet_id: pid } ) }, _ => { - debug!(target: "net", "Unkown packet: {:?}", packet_id); + debug!(target: "net", "Unknown packet: {:?}", packet_id); Ok(SessionData::None) } } @@ -255,15 +291,20 @@ impl Session { Ok(()) } - fn write_ping(&mut self) -> Result<(), UtilError> { - self.send(try!(Session::prepare(PACKET_PING))) + /// Senf ping packet + pub fn send_ping(&mut self) -> Result<(), UtilError> { + try!(self.send(try!(Session::prepare(PACKET_PING)))); + self.ping_time_ns = time::precise_time_ns(); + self.pong_time_ns = None; + Ok(()) } - fn write_pong(&mut self) -> Result<(), UtilError> { + fn send_pong(&mut self) -> Result<(), UtilError> { self.send(try!(Session::prepare(PACKET_PONG))) } - fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError { + /// Disconnect this session + pub fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError { let mut rlp = RlpStream::new(); rlp.append(&(PACKET_DISCONNECT as u32)); rlp.begin_list(1); diff --git a/util/src/nibbleslice.rs b/util/src/nibbleslice.rs index c0d076440..ac87b808f 100644 --- a/util/src/nibbleslice.rs +++ b/util/src/nibbleslice.rs @@ -34,7 +34,7 @@ pub struct NibbleSlice<'a> { offset_encode_suffix: usize, } -/// TODO [Gav Wood] Please document me +/// Iterator type for a nibble slice. pub struct NibbleSliceIterator<'a> { p: &'a NibbleSlice<'a>, i: usize, @@ -77,7 +77,7 @@ impl<'a, 'view> NibbleSlice<'a> where 'a: 'view { (r, a.len() + b.len()) }*/ - /// TODO [Gav Wood] Please document me + /// Get an iterator for the series of nibbles. pub fn iter(&'a self) -> NibbleSliceIterator<'a> { NibbleSliceIterator { p: self, i: 0 } } @@ -132,7 +132,7 @@ impl<'a, 'view> NibbleSlice<'a> where 'a: 'view { i } - /// TODO [Gav Wood] Please document me + /// Encode while nibble slice in prefixed hex notation, noting whether it `is_leaf`. pub fn encoded(&self, is_leaf: bool) -> Bytes { let l = self.len(); let mut r = Bytes::with_capacity(l / 2 + 1); @@ -145,7 +145,8 @@ impl<'a, 'view> NibbleSlice<'a> where 'a: 'view { r } - /// TODO [Gav Wood] Please document me + /// Encode only the leftmost `n` bytes of the nibble slice in prefixed hex notation, + /// noting whether it `is_leaf`. pub fn encoded_leftmost(&self, n: usize, is_leaf: bool) -> Bytes { let l = min(self.len(), n); let mut r = Bytes::with_capacity(l / 2 + 1); diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs index 69562764c..aa7287462 100644 --- a/util/src/rlp/bytes.rs +++ b/util/src/rlp/bytes.rs @@ -140,9 +140,9 @@ impl ToBytes for T where T: FixedHash { /// Error returned when FromBytes conversation goes wrong #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { - /// TODO [debris] Please document me + /// Expected more RLP data DataIsTooShort, - /// TODO [debris] Please document me + /// Extra bytes after the end of the last item DataIsTooLong, /// Integer-representation is non-canonically prefixed with zero byte(s). ZeroPrefixedInt, @@ -165,7 +165,7 @@ pub type FromBytesResult = Result; /// /// TODO: check size of bytes before conversation and return appropriate error pub trait FromBytes: Sized { - /// TODO [debris] Please document me + /// Create a value from bytes fn from_bytes(bytes: &[u8]) -> FromBytesResult; } @@ -236,7 +236,7 @@ impl_uint_from_bytes!(U128); impl FromBytes for T where T: FixedHash { fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len().cmp(&T::size()) { + match bytes.len().cmp(&T::len()) { Ordering::Less => return Err(FromBytesError::DataIsTooShort), Ordering::Greater => return Err(FromBytesError::DataIsTooLong), Ordering::Equal => () @@ -246,7 +246,7 @@ impl FromBytes for T where T: FixedHash { use std::{mem, ptr}; let mut res: T = mem::uninitialized(); - ptr::copy(bytes.as_ptr(), res.as_slice_mut().as_mut_ptr(), T::size()); + ptr::copy(bytes.as_ptr(), res.as_slice_mut().as_mut_ptr(), T::len()); Ok(res) } diff --git a/util/src/rlp/mod.rs b/util/src/rlp/mod.rs index f6101abc6..fb2ee3d5a 100644 --- a/util/src/rlp/mod.rs +++ b/util/src/rlp/mod.rs @@ -48,13 +48,13 @@ pub use self::rlpstream::{RlpStream}; pub use elastic_array::ElasticArray1024; use super::hash::H256; -/// TODO [arkpar] Please document me +/// The RLP encoded empty data (used to mean "null value"). pub const NULL_RLP: [u8; 1] = [0x80; 1]; -/// TODO [Gav Wood] Please document me +/// The RLP encoded empty list. pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; -/// TODO [arkpar] Please document me +/// The SHA3 of the RLP encoding of empty data. pub const SHA3_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21] ); -/// TODO [debris] Please document me +/// The SHA3 of the RLP encoding of empty list. pub const SHA3_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47] ); /// Shortcut function to decode trusted rlp diff --git a/util/src/rlp/rlperrors.rs b/util/src/rlp/rlperrors.rs index f5d4629ad..d032ab36a 100644 --- a/util/src/rlp/rlperrors.rs +++ b/util/src/rlp/rlperrors.rs @@ -3,27 +3,27 @@ use std::error::Error as StdError; use rlp::bytes::FromBytesError; #[derive(Debug, PartialEq, Eq)] -/// TODO [debris] Please document me +/// Error concerning the RLP decoder. pub enum DecoderError { - /// TODO [debris] Please document me + /// Couldn't convert given bytes to an instance of required type. FromBytesError(FromBytesError), - /// Given data has additional bytes at the end of the valid RLP fragment. + /// Data has additional bytes at the end of the valid RLP fragment. RlpIsTooBig, - /// TODO [debris] Please document me + /// Data has too few bytes for valid RLP. RlpIsTooShort, - /// TODO [debris] Please document me + /// Expect an encoded list, RLP was something else. RlpExpectedToBeList, - /// TODO [Gav Wood] Please document me + /// Expect encoded data, RLP was something else. RlpExpectedToBeData, - /// TODO [Gav Wood] Please document me + /// Expected a different size list. RlpIncorrectListLen, - /// TODO [Gav Wood] Please document me + /// Data length number has a prefixed zero byte, invalid for numbers. RlpDataLenWithZeroPrefix, - /// TODO [Gav Wood] Please document me + /// List length number has a prefixed zero byte, invalid for numbers. RlpListLenWithZeroPrefix, - /// TODO [debris] Please document me + /// Non-canonical (longer than necessary) representation used for data or list. RlpInvalidIndirection, - /// Returned when declared length is inconsistent with data specified after + /// Declared length is inconsistent with data specified after. RlpInconsistentLengthAndData } diff --git a/util/src/rlp/rlpin.rs b/util/src/rlp/rlpin.rs index cfcaee014..9b922ed43 100644 --- a/util/src/rlp/rlpin.rs +++ b/util/src/rlp/rlpin.rs @@ -103,12 +103,12 @@ impl <'a, 'view> Rlp<'a> where 'a: 'view { res.unwrap_or_else(|_| panic!()) } - /// TODO [debris] Please document me + /// Decode into an object pub fn as_val(&self) -> T where T: RlpDecodable { Self::view_as_val(self) } - /// TODO [debris] Please document me + /// Decode list item at given index into an object pub fn val_at(&self, index: usize) -> T where T: RlpDecodable { Self::view_as_val(&self.at(index)) } diff --git a/util/src/rlp/rlptraits.rs b/util/src/rlp/rlptraits.rs index 17acbb40b..f6b39729a 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -7,15 +7,15 @@ use elastic_array::ElasticArray1024; use hash::H256; use sha3::*; -/// TODO [debris] Please document me +/// Type is able to decode RLP. pub trait Decoder: Sized { - /// TODO [debris] Please document me + /// Read a value from the RLP into a given type. fn read_value(&self, f: F) -> Result where F: FnOnce(&[u8]) -> Result; - /// TODO [Gav Wood] Please document me + /// Get underlying `UntrustedRLP` object. fn as_rlp(&self) -> &UntrustedRlp; - /// TODO [debris] Please document me + /// Get underlying raw bytes slice. fn as_raw(&self) -> &[u8]; } @@ -31,17 +31,17 @@ pub trait RlpDecodable: Sized { fn decode(decoder: &D) -> Result where D: Decoder; } -/// TODO [debris] Please document me +/// A view into RLP encoded data pub trait View<'a, 'view>: Sized { - /// TODO [debris] Please document me + /// RLP prototype type type Prototype; - /// TODO [debris] Please document me + /// Payload info type type PayloadInfo; - /// TODO [debris] Please document me + /// Data type type Data; - /// TODO [debris] Please document me + /// Item type type Item; - /// TODO [debris] Please document me + /// Iterator type type Iter; /// Creates a new instance of `Rlp` reader @@ -65,10 +65,10 @@ pub trait View<'a, 'view>: Sized { /// Get the prototype of the RLP. fn prototype(&self) -> Self::Prototype; - /// TODO [debris] Please document me + /// Get payload info. fn payload_info(&self) -> Self::PayloadInfo; - /// TODO [debris] Please document me + /// Get underlieing data. fn data(&'view self) -> Self::Data; /// Returns number of RLP items. @@ -205,18 +205,18 @@ pub trait View<'a, 'view>: Sized { /// ``` fn iter(&'view self) -> Self::Iter; - /// TODO [debris] Please document me + /// Decode data into an object fn as_val(&self) -> Result where T: RlpDecodable; - /// TODO [debris] Please document me + /// Decode data at given list index into an object fn val_at(&self, index: usize) -> Result where T: RlpDecodable; } -/// TODO [debris] Please document me +/// Raw RLP encoder pub trait Encoder { - /// TODO [debris] Please document me + /// Write a value represented as bytes fn emit_value(&mut self, value: &E); - /// TODO [debris] Please document me + /// Write raw preencoded data to the output fn emit_raw(&mut self, bytes: &[u8]) -> (); } @@ -250,7 +250,7 @@ pub trait RlpEncodable { fn rlp_append(&self, s: &mut RlpStream); } -/// TODO [debris] Please document me +/// RLP encoding stream pub trait Stream: Sized { /// Initializes instance of empty `Stream`. @@ -341,7 +341,7 @@ pub trait Stream: Sized { /// } fn is_finished(&self) -> bool; - /// TODO [debris] Please document me + /// Get raw encoded bytes fn as_raw(&self) -> &[u8]; /// Streams out encoded bytes. diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 604273b20..ed288bbdd 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -21,21 +21,21 @@ impl OffsetCache { } #[derive(Debug)] -/// TODO [debris] Please document me +/// RLP prototype pub enum Prototype { - /// TODO [debris] Please document me + /// Empty Null, - /// TODO [debris] Please document me + /// Value Data(usize), - /// TODO [debris] Please document me + /// List List(usize), } /// Stores basic information about item pub struct PayloadInfo { - /// TODO [debris] Please document me + /// Header length in bytes pub header_len: usize, - /// TODO [debris] Please document me + /// Value length in bytes pub value_len: usize, } diff --git a/util/src/sha3.rs b/util/src/sha3.rs index 115a408de..d00516000 100644 --- a/util/src/sha3.rs +++ b/util/src/sha3.rs @@ -6,7 +6,7 @@ use bytes::{BytesConvertable, Populatable}; use hash::{H256, FixedHash}; use self::sha3_ext::*; -/// TODO [Gav Wood] Please document me +/// Get the SHA3 (i.e. Keccak) hash of the empty bytes string. pub const SHA3_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] ); diff --git a/util/src/squeeze.rs b/util/src/squeeze.rs index 3fb4a81f9..5cda39249 100644 --- a/util/src/squeeze.rs +++ b/util/src/squeeze.rs @@ -36,7 +36,7 @@ use heapsize::HeapSizeOf; /// Should be used to squeeze collections to certain size in bytes pub trait Squeeze { - /// TODO [debris] Please document me + /// Try to reduce collection size to `size` bytes fn squeeze(&mut self, size: usize); } diff --git a/util/src/trie/mod.rs b/util/src/trie/mod.rs index 502a7688d..74a525bb6 100644 --- a/util/src/trie/mod.rs +++ b/util/src/trie/mod.rs @@ -1,19 +1,20 @@ //! Trie interface and implementation. -/// TODO [Gav Wood] Please document me +/// Export the trietraits module. pub mod trietraits; +/// Export the standardmap module. pub mod standardmap; -/// TODO [Gav Wood] Please document me +/// Export the journal module. pub mod journal; -/// TODO [Gav Wood] Please document me +/// Export the node module. pub mod node; -/// TODO [Gav Wood] Please document me +/// Export the triedb module. pub mod triedb; -/// TODO [Gav Wood] Please document me +/// Export the triedbmut module. pub mod triedbmut; -/// TODO [Gav Wood] Please document me +/// Export the sectriedb module. pub mod sectriedb; -/// TODO [Gav Wood] Please document me +/// Export the sectriedbmut module. pub mod sectriedbmut; pub use self::trietraits::*; diff --git a/util/src/trie/node.rs b/util/src/trie/node.rs index c47a0d25f..626c4dd00 100644 --- a/util/src/trie/node.rs +++ b/util/src/trie/node.rs @@ -7,13 +7,13 @@ use super::journal::*; /// Type of node in the trie and essential information thereof. #[derive(Clone, Eq, PartialEq, Debug)] pub enum Node<'a> { - /// TODO [Gav Wood] Please document me + /// Null trie node; could be an empty root or an empty branch entry. Empty, - /// TODO [Gav Wood] Please document me + /// Leaf node; has key slice and value. Value may not be empty. Leaf(NibbleSlice<'a>, &'a[u8]), - /// TODO [Gav Wood] Please document me + /// Extension node; has key slice and node data. Data may not be null. Extension(NibbleSlice<'a>, &'a[u8]), - /// TODO [Gav Wood] Please document me + /// Branch node; has array of 16 child nodes (each possibly null) and an optional immediate node data. Branch([&'a[u8]; 16], Option<&'a [u8]>) } diff --git a/util/src/trie/standardmap.rs b/util/src/trie/standardmap.rs index 4573efd66..ce2062566 100644 --- a/util/src/trie/standardmap.rs +++ b/util/src/trie/standardmap.rs @@ -7,13 +7,13 @@ use hash::*; /// Alphabet to use when creating words for insertion into tries. pub enum Alphabet { - /// TODO [Gav Wood] Please document me + /// All values are allowed in each bytes of the key. All, - /// TODO [Gav Wood] Please document me + /// Only a 6 values ('a' - 'f') are chosen to compose the key. Low, - /// TODO [Gav Wood] Please document me + /// Quite a few values (around 32) are chosen to compose the key. Mid, - /// TODO [Gav Wood] Please document me + /// A set of bytes given is used to compose the key. Custom(Bytes), } diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index 7179c395e..9909c05a4 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -34,7 +34,7 @@ use super::node::*; pub struct TrieDB<'db> { db: &'db HashDB, root: &'db H256, - /// TODO [Gav Wood] Please document me + /// The number of hashes performed so far in operations on this trie. pub hash_count: usize, } diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 4c3d36646..f65d196e4 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -40,7 +40,7 @@ use super::trietraits::*; pub struct TrieDBMut<'db> { db: &'db mut HashDB, root: &'db mut H256, - /// TODO [Gav Wood] Please document me + /// The number of hashes performed so far in operations on this trie. pub hash_count: usize, } @@ -72,7 +72,7 @@ impl<'db> TrieDBMut<'db> { // TODO: return Result pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self { if !db.exists(root) { - flush(format!("Trie root not found {}", root)); + flushln!("Trie root not found {}", root); panic!("Trie root not found!"); } TrieDBMut { diff --git a/util/src/uint.rs b/util/src/uint.rs index 7eee6029e..568885c82 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -60,20 +60,20 @@ macro_rules! panic_on_overflow { } } -/// TODO [Gav Wood] Please document me +/// Large, fixed-length unsigned integer type. pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { /// Size of this type. const SIZE: usize; - /// TODO [Gav Wood] Please document me + /// Returns new instance equalling zero. fn zero() -> Self; - /// TODO [Gav Wood] Please document me + /// Returns new instance equalling one. fn one() -> Self; - /// TODO [Gav Wood] Please document me + /// Error type for converting from a decimal string. type FromDecStrErr; - /// TODO [Gav Wood] Please document me + /// Convert from a decimal string. fn from_dec_str(value: &str) -> Result; /// Conversion to u32 @@ -104,26 +104,25 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + /// Return wrapped eponentation `self**other` and flag if there was an overflow fn overflowing_pow(self, other: Self) -> (Self, bool); - - /// TODO [debris] Please document me + /// Add this `Uint` to other returning result and possible overflow fn overflowing_add(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Subtract another `Uint` from this returning result and possible overflow fn overflowing_sub(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Multiple this `Uint` with other returning result and possible overflow fn overflowing_mul(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Divide this `Uint` by other returning result and possible overflow fn overflowing_div(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Returns reminder of division of this `Uint` by other and possible overflow fn overflowing_rem(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Returns negation of this `Uint` and overflow (always true) fn overflowing_neg(self) -> (Self, bool); - /// TODO [Gav Wood] Please document me + /// Shifts this `Uint` and returns overflow fn overflowing_shl(self, shift: u32) -> (Self, bool); } @@ -939,12 +938,10 @@ impl From for u32 { } } -/// TODO [Gav Wood] Please document me +/// Constant value of `U256::zero()` that can be used for a reference saving an additional instance creation. pub const ZERO_U256: U256 = U256([0x00u64; 4]); -/// TODO [Gav Wood] Please document me +/// Constant value of `U256::one()` that can be used for a reference saving an additional instance creation. pub const ONE_U256: U256 = U256([0x01u64, 0x00u64, 0x00u64, 0x00u64]); -/// TODO [Gav Wood] Please document me -pub const BAD_U256: U256 = U256([0xffffffffffffffffu64; 4]); #[cfg(test)] mod tests { diff --git a/util/src/vector.rs b/util/src/vector.rs index b9770e30b..ed844a5a4 100644 --- a/util/src/vector.rs +++ b/util/src/vector.rs @@ -13,7 +13,7 @@ /// } /// ``` pub trait SharedPrefix { - /// TODO [debris] Please document me + /// Get common prefix length fn shared_prefix_len(&self, elem: &[T]) -> usize; }