diff --git a/.travis.yml b/.travis.yml index b7124b2df..d051971bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ env: global: # GH_TOKEN - secure: bumJASbZSU8bxJ0EyPUJmu16AiV9EXOpyOj86Jlq/Ty9CfwGqsSXt96uDyE+OUJf34RUFQMsw0nk37/zC4lcn6kqk2wpuH3N/o85Zo/cVZY/NusBWLQqtT5VbYWsV+u2Ua4Tmmsw8yVYQhYwU2ZOejNpflL+Cs9XGgORp1L+/gMRMC2y5Se6ZhwnKPQlRJ8LGsG1dzjQULxzADIt3/zuspNBS8a2urJwlHfGMkvHDoUWCviP/GXoSqw3TZR7FmKyxE19I8n9+iSvm9+oZZquvcgfUxMHn8Gq/b44UbPvjtFOg2yam4xdWXF/RyWCHdc/R9EHorSABeCbefIsm+zcUF3/YQxwpSxM4IZEeH2rTiC7dcrsKw3XsO16xFQz5YI5Bay+CT/wTdMmJd7DdYz7Dyf+pOvcM9WOf/zorxYWSBOMYy0uzbusU2iyIghQ82s7E/Ahg+WARtPgkuTLSB5aL1oCTBKHqQscMr7lo5Ti6RpWLxEdTQMBznc+bMr+6dEtkEcG9zqc6cE9XX+ox3wTU6+HVMfQ1ltCntJ4UKcw3A6INEbw9wgocQa812CIASQ2fE+SCAbz6JxBjIAlFUnD1lUB7S8PdMPwn9plfQgKQ2A5YZqg6FnBdf0rQXIJYxQWKHXj/rBHSUCT0tHACDlzTA+EwWggvkP5AGIxRxm8jhw= - - TARGETS="-p ethkey -p ethstore -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethjson -p ethcore-dapps -p ethcore-signer" + - TARGETS="-p ethkey -p ethstore -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethjson -p ethcore-dapps -p ethcore-signer -p bigint" - ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}" - KCOV_FEATURES="" - KCOV_CMD="./kcov-master/tmp/usr/local/bin/kcov --exclude-pattern /usr/,/.cargo,/root/.multirust,src/tests,util/json-tests,util/src/network/tests,sync/src/tests,ethcore/src/tests,ethcore/src/evm/tests,ethstore/tests target/kcov" diff --git a/Cargo.lock b/Cargo.lock index 645e859db..10a52aabb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "parity" version = "1.3.0" dependencies = [ "ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)", "daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)", @@ -129,15 +129,15 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.77" +version = "0.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clippy_lints 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy_lints" -version = "0.0.77" +version = "0.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -250,7 +250,7 @@ name = "ethcore" version = "1.3.0" dependencies = [ "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.3.0", @@ -277,7 +277,7 @@ dependencies = [ name = "ethcore-dapps" version = "1.3.0" dependencies = [ - "clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-rpc 1.3.0", "ethcore-util 1.3.0", "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", @@ -287,7 +287,7 @@ dependencies = [ "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)", "parity-dapps-builtins 0.5.2 (git+https://github.com/ethcore/parity-dapps-builtins-rs.git)", - "parity-dapps-status 0.5.0 (git+https://github.com/ethcore/parity-dapps-status-rs.git)", + "parity-dapps-status 0.5.1 (git+https://github.com/ethcore/parity-dapps-status-rs.git)", "parity-dapps-wallet 0.6.1 (git+https://github.com/ethcore/parity-dapps-wallet-rs.git)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -339,7 +339,7 @@ dependencies = [ name = "ethcore-rpc" version = "1.3.0" dependencies = [ - "clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.3.0", "ethcore 1.3.0", "ethcore-devtools 1.3.0", @@ -363,7 +363,7 @@ dependencies = [ name = "ethcore-signer" version = "1.3.0" dependencies = [ - "clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-rpc 1.3.0", "ethcore-util 1.3.0", @@ -383,7 +383,7 @@ dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", "chrono 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -455,7 +455,7 @@ dependencies = [ name = "ethsync" version = "1.3.0" dependencies = [ - "clippy 0.0.77 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.78 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.3.0", "ethcore-util 1.3.0", @@ -900,7 +900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-dapps" version = "0.3.0" -source = "git+https://github.com/ethcore/parity-dapps-rs.git#8cc812c26c903cf5764ce0f4cc3f2a7c3ddb0dc2" +source = "git+https://github.com/ethcore/parity-dapps-rs.git#8ce18c014d8b69fa31fb203b68ff240091d77a23" dependencies = [ "aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -921,8 +921,8 @@ dependencies = [ [[package]] name = "parity-dapps-status" -version = "0.5.0" -source = "git+https://github.com/ethcore/parity-dapps-status-rs.git#0cdd3512004e403aff7da3b8c16ba0bf5d6c911c" +version = "0.5.1" +source = "git+https://github.com/ethcore/parity-dapps-status-rs.git#110ef2e66142ec8dc15fc40b8ddda5ed3bcfc1fb" dependencies = [ "parity-dapps 0.3.0 (git+https://github.com/ethcore/parity-dapps-rs.git)", ] diff --git a/Cargo.toml b/Cargo.toml index 9493af006..e49c3efc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ fdlimit = { path = "util/fdlimit" } num_cpus = "0.2" number_prefix = "0.2" rpassword = "0.2.1" -clippy = { version = "0.0.77", optional = true} +clippy = { version = "0.0.78", optional = true} ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/README.md b/README.md index 53212b229..d605fa87c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ This includes a few useful Dapps, including Ethereum Wallet, Maker OTC, and a no In a near-future release, it will be easy to install Dapps and use them through this web interface. If you run into an issue while using parity, feel free to file one in this repository -or hop on our [gitter chat room]([gitter-url]) to ask a question. We are glad to help! +or hop on our [gitter chat room][gitter-url] to ask a question. We are glad to help! Parity's current release is 1.2. You can download it at https://ethcore.io/parity.html or follow the instructions below to build from source. diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 6aaceb50a..94af56ca3 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -22,13 +22,13 @@ ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-dapps = { git = "https://github.com/ethcore/parity-dapps-rs.git", version = "0.3" } # List of apps -parity-dapps-status = { git = "https://github.com/ethcore/parity-dapps-status-rs.git", version = "0.5.0" } +parity-dapps-status = { git = "https://github.com/ethcore/parity-dapps-status-rs.git", version = "0.5.1" } parity-dapps-builtins = { git = "https://github.com/ethcore/parity-dapps-builtins-rs.git", version = "0.5.2" } parity-dapps-wallet = { git = "https://github.com/ethcore/parity-dapps-wallet-rs.git", version = "0.6.0", optional = true } parity-dapps-dao = { git = "https://github.com/ethcore/parity-dapps-dao-rs.git", version = "0.4.0", optional = true } parity-dapps-makerotc = { git = "https://github.com/ethcore/parity-dapps-makerotc-rs.git", version = "0.3.0", optional = true } mime_guess = { version = "1.6.1" } -clippy = { version = "0.0.77", optional = true} +clippy = { version = "0.0.78", optional = true} [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/db/Cargo.toml b/db/Cargo.toml index 2f5f0254e..92bc8282c 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -12,7 +12,7 @@ syntex = "*" ethcore-ipc-codegen = { path = "../ipc/codegen" } [dependencies] -clippy = { version = "0.0.77", optional = true} +clippy = { version = "0.0.78", optional = true} ethcore-devtools = { path = "../devtools" } ethcore-ipc = { path = "../ipc/rpc" } rocksdb = { git = "https://github.com/ethcore/rust-rocksdb" } diff --git a/docker/centos/Dockerfile b/docker/centos/Dockerfile index 56015422c..9fd33f4ff 100644 --- a/docker/centos/Dockerfile +++ b/docker/centos/Dockerfile @@ -20,6 +20,8 @@ g++ -v # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity&&\ + git checkout beta && \ + git pull && \ ls -a&&\ cargo build --release --verbose && \ ls /build/parity/target/release/parity && \ diff --git a/docker/ubuntu-aarch64/Dockerfile b/docker/ubuntu-aarch64/Dockerfile index 3212f84d0..38ed4c9b1 100644 --- a/docker/ubuntu-aarch64/Dockerfile +++ b/docker/ubuntu-aarch64/Dockerfile @@ -36,6 +36,8 @@ ENV CC aarch64-linux-gnu-gcc # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ + git checkout beta && \ + git pull && \ mkdir -p .cargo && \ echo '[target.aarch64-unknown-linux-gnu]\n\ linker = "aarch64-linux-gnu-gcc"\n'\ diff --git a/docker/ubuntu-arm/Dockerfile b/docker/ubuntu-arm/Dockerfile index fab325e5e..b59573a0f 100644 --- a/docker/ubuntu-arm/Dockerfile +++ b/docker/ubuntu-arm/Dockerfile @@ -36,6 +36,8 @@ ENV CC arm-linux-gnueabihf-gcc # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ + git checkout beta && \ + git pull && \ mkdir -p .cargo && \ echo '[target.armv7-unknown-linux-gnueabihf]\n\ linker = "arm-linux-gnueabihf-gcc"\n'\ diff --git a/docker/ubuntu-jit/Dockerfile b/docker/ubuntu-jit/Dockerfile index 89c38cee7..666b16904 100644 --- a/docker/ubuntu-jit/Dockerfile +++ b/docker/ubuntu-jit/Dockerfile @@ -47,6 +47,8 @@ g++ -v # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ + git checkout beta && \ + git pull && \ cargo build --release --features ethcore/jit --verbose && \ ls /build/parity/target/release/parity && \ strip /build/parity/target/release/parity diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index 9999909c3..4c82e1ecc 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -27,7 +27,9 @@ g++ -v # build parity RUN git clone https://github.com/ethcore/parity && \ cd parity && \ + git checkout beta && \ + git pull && \ cargo build --release --verbose && \ - ls /build/parity/target/release/parity && \ + ls /build/parity/target/release/parity && \ strip /build/parity/target/release/parity RUN file /build/parity/target/release/parity diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index e8fb94e97..6979043e3 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -22,7 +22,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.77", optional = true} +clippy = { version = "0.0.78", optional = true} crossbeam = "0.2.9" lazy_static = "0.2" ethcore-devtools = { path = "../devtools" } diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index 2edbf87ae..2db4ffcc0 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -214,8 +214,8 @@ impl Account { } /// Commit the `storage_overlay` to the backing DB and update `storage_root`. - pub fn commit_storage(&mut self, db: &mut AccountDBMut) { - let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root) + pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) { + let mut t = trie_factory.from_existing(db, &mut self.storage_root) .expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \ SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \ using it will not fail."); @@ -275,7 +275,7 @@ mod tests { let rlp = { let mut a = Account::new_contract(69.into(), 0.into()); a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64))); - a.commit_storage(&mut db); + a.commit_storage(&Default::default(), &mut db); a.init_code(vec![]); a.commit_code(&mut db); a.rlp() @@ -313,7 +313,7 @@ mod tests { let mut db = AccountDBMut::new(&mut db, &Address::new()); a.set_storage(0.into(), 0x1234.into()); assert_eq!(a.storage_root(), None); - a.commit_storage(&mut db); + a.commit_storage(&Default::default(), &mut db); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); } @@ -323,11 +323,11 @@ mod tests { let mut db = MemoryDB::new(); let mut db = AccountDBMut::new(&mut db, &Address::new()); a.set_storage(0.into(), 0x1234.into()); - a.commit_storage(&mut db); + a.commit_storage(&Default::default(), &mut db); a.set_storage(1.into(), 0x1234.into()); - a.commit_storage(&mut db); + a.commit_storage(&Default::default(), &mut db); a.set_storage(1.into(), 0.into()); - a.commit_storage(&mut db); + a.commit_storage(&Default::default(), &mut db); assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2"); } diff --git a/ethcore/src/basic_authority.rs b/ethcore/src/basic_authority.rs index 4426d3059..e487548a3 100644 --- a/ethcore/src/basic_authority.rs +++ b/ethcore/src/basic_authority.rs @@ -254,7 +254,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); assert!(b.try_seal(engine.deref(), seal).is_ok()); diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 13a2024d9..9453e1350 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -222,6 +222,7 @@ impl<'x> OpenBlock<'x> { pub fn new( engine: &'x Engine, vm_factory: &'x EvmFactory, + trie_factory: TrieFactory, tracing: bool, db: Box, parent: &Header, @@ -231,7 +232,7 @@ impl<'x> OpenBlock<'x> { gas_range_target: (U256, U256), extra_data: Bytes, ) -> Result { - let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce())); + let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(), trie_factory)); let mut r = OpenBlock { block: ExecutedBlock::new(state, tracing), engine: engine, @@ -481,16 +482,17 @@ pub fn enact( parent: &Header, last_hashes: LastHashes, dao_rescue_block_gas_limit: Option, - vm_factory: &EvmFactory + vm_factory: &EvmFactory, + trie_factory: TrieFactory, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { - let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce())); + let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), trie_factory.clone())); trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author())); } } - let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone())); + let mut b = try!(OpenBlock::new(engine, vm_factory, trie_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone())); b.set_difficulty(*header.difficulty()); b.set_gas_limit(*header.gas_limit()); b.set_timestamp(header.timestamp()); @@ -509,11 +511,12 @@ pub fn enact_bytes( parent: &Header, last_hashes: LastHashes, dao_rescue_block_gas_limit: Option, - vm_factory: &EvmFactory + vm_factory: &EvmFactory, + trie_factory: TrieFactory, ) -> Result { let block = BlockView::new(block_bytes); let header = block.header(); - enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory) + enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header @@ -526,10 +529,11 @@ pub fn enact_verified( parent: &Header, last_hashes: LastHashes, dao_rescue_block_gas_limit: Option, - vm_factory: &EvmFactory + vm_factory: &EvmFactory, + trie_factory: TrieFactory, ) -> Result { let view = BlockView::new(&block.bytes); - enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory) + enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory) } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards @@ -542,10 +546,11 @@ pub fn enact_and_seal( parent: &Header, last_hashes: LastHashes, dao_rescue_block_gas_limit: Option, - vm_factory: &EvmFactory + vm_factory: &EvmFactory, + trie_factory: TrieFactory, ) -> Result { let header = BlockView::new(block_bytes).header_view(); - Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)).seal(engine, header.seal()))) + Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)).seal(engine, header.seal()))) } #[cfg(test)] @@ -565,7 +570,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); let _ = b.seal(engine.deref(), vec![]); } @@ -581,7 +586,7 @@ mod tests { let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() + let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() .close_and_lock().seal(engine.deref(), vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -589,7 +594,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); - let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap(); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -609,7 +614,7 @@ mod tests { let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); let vm_factory = Default::default(); - let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle1_header = Header::new(); uncle1_header.extra_data = b"uncle1".to_vec(); let mut uncle2_header = Header::new(); @@ -624,7 +629,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); - let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap(); + let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap(); let bytes = e.rlp_bytes(); assert_eq!(bytes, orig_bytes); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 4b2246b21..252c17b34 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -30,7 +30,7 @@ use blockchain::best_block::BestBlock; use types::tree_route::TreeRoute; use blockchain::update::ExtrasUpdate; use blockchain::{CacheSize, ImportRoute, Config}; -use db::{Writable, Readable, CacheUpdatePolicy}; +use db::{Writable, Readable, CacheUpdatePolicy, Key}; const LOG_BLOOMS_LEVELS: usize = 3; const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16; @@ -295,7 +295,22 @@ impl BlockChain { // load best block let best_block_hash = match bc.extras_db.get(b"best").unwrap() { - Some(best) => H256::from_slice(&best), + Some(best) => { + let best = H256::from_slice(&best); + let mut b = best.clone(); + while !bc.blocks_db.get(&b).unwrap().is_some() { + // track back to the best block we have in the blocks database + let extras: BlockDetails = bc.extras_db.read(&b).unwrap(); + type DetailsKey = Key; + bc.extras_db.delete(&(DetailsKey::key(&b))).unwrap(); + b = extras.parent; + } + if b != best { + info!("Restored mismatched best block. Was: {}, new: {}", best.hex(), b.hex()); + bc.extras_db.put(b"best", &b).unwrap(); + } + b + } None => { // best block does not exist // we need to insert genesis into the cache diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 3c0733ec5..d50eb8c54 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -18,3 +18,4 @@ #![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues include!(concat!(env!("OUT_DIR"), "/client.ipc.rs")); + diff --git a/ethcore/src/client/client.rs.in b/ethcore/src/client/client.rs.in index deebaa857..bb6421520 100644 --- a/ethcore/src/client/client.rs.in +++ b/ethcore/src/client/client.rs.in @@ -122,6 +122,7 @@ pub struct Client { panic_handler: Arc, verifier: Box, vm_factory: Arc, + trie_factory: TrieFactory, miner: Arc, io_channel: IoChannel, queue_transactions: AtomicUsize, @@ -203,6 +204,7 @@ impl Client { panic_handler: panic_handler, verifier: verification::new(config.verifier_type), vm_factory: Arc::new(EvmFactory::new(config.vm_type)), + trie_factory: TrieFactory::new(config.trie_spec), miner: miner, io_channel: message_channel, queue_transactions: AtomicUsize::new(0), @@ -261,7 +263,7 @@ impl Client { let last_hashes = self.build_last_hashes(header.parent_hash.clone()); let db = self.state_db.lock().unwrap().boxed_clone(); - let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory); + let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory, self.trie_factory.clone()); if let Err(e) = enact_result { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); return Err(()); @@ -376,7 +378,7 @@ impl Client { imported } - fn commit_block(&self, block: B, hash: &H256, block_data: &Bytes) -> ImportRoute where B: IsBlock + Drain { + fn commit_block(&self, block: B, hash: &H256, block_data: &[u8]) -> ImportRoute where B: IsBlock + Drain { let number = block.header().number(); // Are we committing an era? let ancient = if number >= HISTORY { @@ -446,13 +448,17 @@ impl Client { let root = HeaderView::new(&header).state_root(); - State::from_existing(db, root, self.engine.account_start_nonce()).ok() + State::from_existing(db, root, self.engine.account_start_nonce(), self.trie_factory.clone()).ok() }) } /// Get a copy of the best block's state. pub fn state(&self) -> State { - State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce()) + State::from_existing( + self.state_db.lock().unwrap().boxed_clone(), + HeaderView::new(&self.best_block_header()).state_root(), + self.engine.account_start_nonce(), + self.trie_factory.clone()) .expect("State root of best block header always valid.") } @@ -509,7 +515,6 @@ impl Client { } } -#[derive(Ipc)] impl BlockChainClient for Client { fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result { let header = self.block_header(BlockID::Latest).unwrap(); @@ -610,7 +615,7 @@ impl BlockChainClient for Client { fn uncle(&self, id: UncleID) -> Option { let index = id.position; - self.block(id.block).and_then(|block| BlockView::new(&block).uncle_at(index).and_then(|u| Some(u.rlp(Seal::With)))) + self.block(id.block).and_then(|block| BlockView::new(&block).uncle_rlp_at(index)) } fn transaction_receipt(&self, id: TransactionID) -> Option { @@ -684,7 +689,7 @@ impl BlockChainClient for Client { return Err(BlockImportError::Import(ImportError::AlreadyInChain)); } if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown { - return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash())); + return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash()))); } } Ok(try!(self.block_queue.import_block(bytes))) @@ -694,9 +699,8 @@ impl BlockChainClient for Client { self.block_queue.queue_info() } - fn clear_queue(&self) -> bool { + fn clear_queue(&self) { self.block_queue.clear(); - true } fn chain_info(&self) -> BlockChainInfo { @@ -742,8 +746,8 @@ impl BlockChainClient for Client { receipt.logs.into_iter() .enumerate() .filter(|tuple| filter.matches(&tuple.1)) - .map(|(i, log)| LocalizedLogEntry { - entry: log, + .map(|(i, log)| LocalizedLogEntry { + entry: log, block_hash: hash.clone(), block_number: number, transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new), @@ -802,31 +806,29 @@ impl BlockChainClient for Client { self.build_last_hashes(self.chain.best_block_hash()) } - fn import_transactions(&self, transactions: Vec) -> Vec> { + fn import_transactions(&self, transactions: Vec) -> Vec> { let fetch_account = |a: &Address| AccountDetails { nonce: self.latest_nonce(a), balance: self.latest_balance(a), }; - self.miner.import_transactions(self, transactions, fetch_account) - .iter() - .map(|res| match res { &Ok(ref t) => Ok(t.clone()), &Err(ref e) => Err(format!("{:?}", e)) }) - .collect::>>() + + self.miner.import_transactions(self, transactions, &fetch_account) + .into_iter() + .map(|res| res.map_err(|e| e.into())) + .collect() } - fn queue_transactions(&self, transactions: Vec) -> bool { + fn queue_transactions(&self, transactions: Vec) { if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE { debug!("Ignoring {} transactions: queue is full", transactions.len()); - false } else { let len = transactions.len(); match self.io_channel.send(NetworkIoMessage::User(SyncMessage::NewTransactions(transactions))) { Ok(_) => { self.queue_transactions.fetch_add(len, AtomicOrdering::SeqCst); - true } Err(e) => { debug!("Ignoring {} transactions: error queueing: {}", len, e); - false } } } @@ -845,6 +847,7 @@ impl MiningBlockChainClient for Client { let mut open_block = OpenBlock::new( engine, &self.vm_factory, + self.trie_factory.clone(), false, // TODO: this will need to be parameterised once we want to do immediate mining insertion. self.state_db.lock().unwrap().boxed_clone(), &self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"), diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 52a875a2f..6cb34c151 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -20,6 +20,7 @@ pub use trace::{Config as TraceConfig, Switch}; pub use evm::VMType; pub use verification::VerifierType; use util::journaldb; +use util::trie::TrieSpec; /// Client state db compaction profile #[derive(Debug, PartialEq)] @@ -45,6 +46,8 @@ pub struct ClientConfig { pub tracing: TraceConfig, /// VM type. pub vm_type: VMType, + /// Trie type. + pub trie_spec: TrieSpec, /// The JournalDB ("pruning") algorithm to use. pub pruning: journaldb::Algorithm, /// The name of the client instance. diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 7a2562f4b..d6f9f584a 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -47,9 +47,25 @@ use error::{ImportResult, ExecutionError}; use receipt::LocalizedReceipt; use trace::LocalizedTrace; use evm::Factory as EvmFactory; +<<<<<<< HEAD use miner::{TransactionImportResult}; pub use types::call_analytics::CallAnalytics; pub use types::block_import_error::BlockImportError; +======= +pub use block_import_error::BlockImportError; +pub use transaction_import::{TransactionImportResult, TransactionImportError}; + +/// Options concerning what analytics we run on the call. +#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)] +pub struct CallAnalytics { + /// Make a transaction trace. + pub transaction_tracing: bool, + /// Make a VM trace. + pub vm_tracing: bool, + /// Make a diff. + pub state_diffing: bool, +} +>>>>>>> master /// Blockchain database client. Owns and manages a blockchain and a block queue. pub trait BlockChainClient : Sync + Send { @@ -178,7 +194,11 @@ pub trait BlockChainClient : Sync + Send { fn last_hashes(&self) -> LastHashes; /// import transactions from network/other 3rd party +<<<<<<< HEAD fn import_transactions(&self, transactions: Vec) -> Vec>; +======= + fn import_transactions(&self, transactions: Vec) -> Vec>; +>>>>>>> master /// Queue transactions for importing. fn queue_transactions(&self, transactions: Vec) -> bool; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index eacf323b5..1ac47bbec 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -21,7 +21,8 @@ use util::*; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID, - TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError}; + TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics, + TransactionImportError, BlockImportError}; use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; @@ -488,7 +489,7 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn import_transactions(&self, transactions: Vec) -> Vec> { + fn import_transactions(&self, transactions: Vec) -> Vec> { let nonces = self.nonces.read().unwrap(); let balances = self.balances.read().unwrap(); let fetch_account = |a: &Address| AccountDetails { @@ -496,10 +497,10 @@ impl BlockChainClient for TestBlockChainClient { balance: balances[a], }; - self.miner.import_transactions(self, transactions, fetch_account) - .iter() - .map(|res| match res { &Ok(ref t) => Ok(t.clone()), &Err(ref e) => Err(format!("{:?}", e)) }) - .collect::>>() + self.miner.import_transactions(self, transactions, &fetch_account) + .into_iter() + .map(|res| res.map_err(|e| e.into())) + .collect() } fn queue_transactions(&self, transactions: Vec) -> bool { diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 0ee09c354..10786cf91 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -20,12 +20,11 @@ use util::*; use header::BlockNumber; use basic_types::LogBloom; use client::Error as ClientError; -use client::BlockImportError; -use ipc::binary::{BinaryConvertable, BinaryConvertError}; - +use ipc::binary::{BinaryConvertError, BinaryConvertable}; +use types::block_import_error::BlockImportError; pub use types::executed::ExecutionError; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] /// Errors concerning transaction processing. pub enum TransactionError { /// Transaction is already imported to the queue @@ -196,9 +195,6 @@ pub enum ImportError { KnownBad, } -binary_fixed_size!(BlockError); -binary_fixed_size!(ImportError); - impl fmt::Display for ImportError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let msg = match *self { @@ -327,6 +323,10 @@ impl From for Error { } } +binary_fixed_size!(BlockError); +binary_fixed_size!(ImportError); +binary_fixed_size!(TransactionError); + // TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted. /*#![feature(concat_idents)] macro_rules! assimilate { diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 84c2a9608..c438c33ca 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -325,7 +325,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -340,7 +340,7 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()); let last_hashes = vec![genesis_header.hash()]; let vm_factory = Default::default(); - let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut uncle = Header::new(); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); uncle.author = uncle_author.clone(); diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index ed75576c6..d40ee8983 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -67,7 +67,7 @@ mod tests { let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()); - let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()).unwrap(); + let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce(), Default::default()).unwrap(); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64)); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64)); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64)); diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 7b101afc7..215506607 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -29,8 +29,10 @@ use transaction::SignedTransaction; use receipt::{Receipt}; use spec::Spec; use engine::Engine; -use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; +use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionOrigin}; use miner::work_notify::WorkPoster; +use client::TransactionImportResult; + /// Different possible definitions for pending transaction set. #[derive(Debug)] @@ -158,7 +160,7 @@ impl Miner { fn prepare_sealing(&self, chain: &MiningBlockChainClient) { trace!(target: "miner", "prepare_sealing: entering"); - let (transactions, mut open_block, last_work_hash) = { + let (transactions, mut open_block, original_work_hash) = { let transactions = {self.transaction_queue.lock().unwrap().top_transactions()}; let mut sealing_work = self.sealing_work.lock().unwrap(); let last_work_hash = sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash()); @@ -254,23 +256,31 @@ impl Miner { } } - let work = { + let (work, is_new) = { let mut sealing_work = self.sealing_work.lock().unwrap(); - trace!(target: "miner", "Checking whether we need to reseal: last={:?}, this={:?}", last_work_hash, block.block().fields().header.hash()); - let work = if last_work_hash.map_or(true, |h| h != block.block().fields().header.hash()) { + let last_work_hash = sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash()); + trace!(target: "miner", "Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", original_work_hash, last_work_hash, block.block().fields().header.hash()); + let (work, is_new) = if last_work_hash.map_or(true, |h| h != block.block().fields().header.hash()) { trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash()); let pow_hash = block.block().fields().header.hash(); let number = block.block().fields().header.number(); let difficulty = *block.block().fields().header.difficulty(); + let is_new = original_work_hash.map_or(true, |h| block.block().fields().header.hash() != h); sealing_work.push(block); - Some((pow_hash, difficulty, number)) + // If push notifications are enabled we assume all work items are used. + if self.work_poster.is_some() && is_new { + sealing_work.use_last_ref(); + } + (Some((pow_hash, difficulty, number)), is_new) } else { - None + (None, false) }; trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash())); - work + (work, is_new) }; - work.map(|(pow_hash, difficulty, number)| self.work_poster.as_ref().map(|ref p| p.notify(pow_hash, difficulty, number))); + if is_new { + work.map(|(pow_hash, difficulty, number)| self.work_poster.as_ref().map(|ref p| p.notify(pow_hash, difficulty, number))); + } } fn update_gas_limit(&self, chain: &MiningBlockChainClient) { diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 152bd1a61..3d0185753 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -47,9 +47,10 @@ mod external; mod transaction_queue; mod work_notify; -pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; +pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionOrigin}; pub use self::miner::{Miner, MinerOptions, PendingSet}; pub use self::external::{ExternalMiner, ExternalMinerService}; +pub use client::TransactionImportResult; use std::collections::BTreeMap; use util::{H256, U256, Address, Bytes}; diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index 130d46875..3c2ad10d3 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -90,7 +90,11 @@ use util::hash::{Address, H256}; use util::table::*; use transaction::*; use error::{Error, TransactionError}; +<<<<<<< HEAD pub use types::transaction_import_result::TransactionImportResult; +======= +use client::TransactionImportResult; +>>>>>>> master /// Transaction origin #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -805,6 +809,7 @@ mod test { use error::{Error, TransactionError}; use super::*; use super::{TransactionSet, TransactionOrder, VerifiedTransaction}; + use client::TransactionImportResult; fn unwrap_tx_err(err: Result) -> TransactionError { match err.unwrap_err() { diff --git a/ethcore/src/miner/work_notify.rs b/ethcore/src/miner/work_notify.rs index a153be79f..ea2f6140e 100644 --- a/ethcore/src/miner/work_notify.rs +++ b/ethcore/src/miner/work_notify.rs @@ -52,10 +52,10 @@ impl WorkPoster { } fn create_client() -> Client { - let client = Client::::configure() + Client::::configure() .keep_alive(true) - .build().expect("Error creating HTTP client") as Client; - client + .build() + .expect("Error creating HTTP client") } pub fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) { @@ -63,8 +63,10 @@ impl WorkPoster { let target = Ethash::difficulty_to_boundary(&difficulty); let seed_hash = &self.seed_compute.lock().unwrap().get_seedhash(number); let seed_hash = H256::from_slice(&seed_hash[..]); - let body = format!(r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#, - pow_hash.hex(), seed_hash.hex(), target.hex(), number); + let body = format!( + r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#, + pow_hash.hex(), seed_hash.hex(), target.hex(), number + ); let mut client = self.client.lock().unwrap(); for u in &self.urls { if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) { @@ -104,12 +106,12 @@ impl hyper::client::Handler for PostHandler { } fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder) -> Next { - Next::end() + Next::end() } - fn on_error(&mut self, err: hyper::Error) -> Next { + fn on_error(&mut self, err: hyper::Error) -> Next { trace!("Error posting work data: {}", err); Next::end() - } + } } diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 0c086ffc3..92a501e80 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -42,6 +42,7 @@ pub struct State { cache: RefCell>>, snapshots: RefCell>>>>, account_start_nonce: U256, + trie_factory: TrieFactory, } const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \ @@ -50,11 +51,11 @@ const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with v impl State { /// Creates new state with empty state root #[cfg(test)] - pub fn new(mut db: Box, account_start_nonce: U256) -> State { + pub fn new(mut db: Box, account_start_nonce: U256, trie_factory: TrieFactory) -> State { let mut root = H256::new(); { // init trie and reset root too null - let _ = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root); + let _ = trie_factory.create(db.as_hashdb_mut(), &mut root); } State { @@ -63,22 +64,26 @@ impl State { cache: RefCell::new(HashMap::new()), snapshots: RefCell::new(Vec::new()), account_start_nonce: account_start_nonce, + trie_factory: trie_factory, } } /// Creates new state with existing state root - pub fn from_existing(db: Box, root: H256, account_start_nonce: U256) -> Result { + pub fn from_existing(db: Box, root: H256, account_start_nonce: U256, trie_factory: TrieFactory) -> Result { if !db.as_hashdb().contains(&root) { - Err(TrieError::InvalidStateRoot) - } else { - Ok(State { - db: db, - root: root, - cache: RefCell::new(HashMap::new()), - snapshots: RefCell::new(Vec::new()), - account_start_nonce: account_start_nonce, - }) + return Err(TrieError::InvalidStateRoot); } + + let state = State { + db: db, + root: root, + cache: RefCell::new(HashMap::new()), + snapshots: RefCell::new(Vec::new()), + account_start_nonce: account_start_nonce, + trie_factory: trie_factory, + }; + + Ok(state) } /// Create a recoverable snaphot of this state @@ -156,7 +161,7 @@ impl State { /// Determine whether an account exists. pub fn exists(&self, a: &Address) -> bool { - let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); + let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); self.cache.borrow().get(&a).unwrap_or(&None).is_some() || db.contains(&a) } @@ -242,7 +247,10 @@ impl State { for a in &addresses { if self.code(a).map_or(false, |c| c.sha3() == broken_dao) { // Figure out if the balance has been reduced. - let maybe_original = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR).get(&a).map(Account::from_rlp); + let maybe_original = self.trie_factory + .readonly(self.db.as_hashdb(), &self.root) + .expect(SEC_TRIE_DB_UNWRAP_STR) + .get(&a).map(Account::from_rlp); if maybe_original.map_or(false, |original| *original.balance() > self.balance(a)) { return Err(Error::Transaction(TransactionError::DAORescue)); } @@ -262,14 +270,14 @@ impl State { /// 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. #[cfg_attr(feature="dev", allow(match_ref_pats))] - pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { + pub fn commit_into(trie_factory: &TrieFactory, db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { // first, commit the sub trees. // TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? for (address, ref mut a) in accounts.iter_mut() { match a { &mut&mut Some(ref mut account) => { let mut account_db = AccountDBMut::new(db, address); - account.commit_storage(&mut account_db); + account.commit_storage(trie_factory, &mut account_db); account.commit_code(&mut account_db); } &mut&mut None => {} @@ -277,7 +285,7 @@ impl State { } { - let mut trie = SecTrieDBMut::from_existing(db, root).unwrap(); + let mut trie = trie_factory.from_existing(db, root).unwrap(); for (address, ref a) in accounts.iter() { match **a { Some(ref account) => trie.insert(address, &account.rlp()), @@ -290,7 +298,7 @@ impl State { /// Commits our cached account changes into the trie. pub fn commit(&mut self) { assert!(self.snapshots.borrow().is_empty()); - Self::commit_into(self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut()); + Self::commit_into(&self.trie_factory, self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut()); } #[cfg(test)] @@ -340,7 +348,7 @@ impl State { fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option { let have_key = self.cache.borrow().contains_key(a); if !have_key { - let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); + let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); self.insert_cache(a, db.get(&a).map(Account::from_rlp)) } if require_code { @@ -361,7 +369,7 @@ impl State { fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account { let have_key = self.cache.borrow().contains_key(a); if !have_key { - let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); + let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); self.insert_cache(a, db.get(&a).map(Account::from_rlp)) } else { self.note_cache(a); @@ -396,6 +404,7 @@ impl Clone for State { cache: RefCell::new(self.cache.borrow().clone()), snapshots: RefCell::new(self.snapshots.borrow().clone()), account_start_nonce: self.account_start_nonce.clone(), + trie_factory: self.trie_factory.clone(), } } } @@ -1179,7 +1188,7 @@ fn code_from_database() { state.drop() }; - let state = State::from_existing(db, root, U256::from(0u8)).unwrap(); + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); } @@ -1194,7 +1203,7 @@ fn storage_at_from_database() { state.drop() }; - let s = State::from_existing(db, root, U256::from(0u8)).unwrap(); + let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64))); } @@ -1211,7 +1220,7 @@ fn get_from_database() { state.drop() }; - let state = State::from_existing(db, root, U256::from(0u8)).unwrap(); + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.nonce(&a), U256::from(1u64)); } @@ -1244,7 +1253,7 @@ fn remove_from_database() { }; let (root, db) = { - let mut state = State::from_existing(db, root, U256::from(0u8)).unwrap(); + let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.exists(&a), true); assert_eq!(state.nonce(&a), U256::from(1u64)); state.kill_account(&a); @@ -1254,7 +1263,7 @@ fn remove_from_database() { state.drop() }; - let state = State::from_existing(db, root, U256::from(0u8)).unwrap(); + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.exists(&a), false); assert_eq!(state.nonce(&a), U256::from(0u64)); } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 70a644896..ad8058ac6 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -175,6 +175,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe let mut b = OpenBlock::new( test_engine.deref(), &vm_factory, + Default::default(), false, db, &last_header, @@ -315,7 +316,7 @@ pub fn get_temp_state() -> GuardedTempResult { let journal_db = get_temp_journal_db_in(temp.as_path()); GuardedTempResult { _temp: temp, - result: Some(State::new(journal_db, U256::from(0u8))) + result: Some(State::new(journal_db, U256::from(0), Default::default())), } } @@ -325,7 +326,7 @@ pub fn get_temp_journal_db_in(path: &Path) -> Box { pub fn get_temp_state_in(path: &Path) -> State { let journal_db = get_temp_journal_db_in(path); - State::new(journal_db, U256::from(0u8)) + State::new(journal_db, U256::from(0), Default::default()) } pub fn get_good_dummy_block_seq(count: usize) -> Vec { diff --git a/ethcore/src/types/mod.rs.in b/ethcore/src/types/mod.rs.in index 6330ed29b..e7731d1cc 100644 --- a/ethcore/src/types/mod.rs.in +++ b/ethcore/src/types/mod.rs.in @@ -26,8 +26,8 @@ pub mod block_status; pub mod account_diff; pub mod state_diff; pub mod block_queue_info; -pub mod transaction_import_result; pub mod filter; pub mod trace_filter; pub mod call_analytics; +pub mod transaction_import; pub mod block_import_error; diff --git a/ethcore/src/types/transaction_import.rs b/ethcore/src/types/transaction_import.rs new file mode 100644 index 000000000..c52a9fb80 --- /dev/null +++ b/ethcore/src/types/transaction_import.rs @@ -0,0 +1,52 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Transaction import result related types + +use ipc::binary::{BinaryConvertError, BinaryConvertable}; +use std::collections::VecDeque; +use error::{TransactionError, Error}; +use std::mem; +use util::Populatable; + +#[derive(Debug, Clone, PartialEq)] +/// Represents the result of importing transaction. +pub enum TransactionImportResult { + /// Transaction was imported to current queue. + Current, + /// Transaction was imported to future queue. + Future +} + +binary_fixed_size!(TransactionImportResult); + +/// Api-level error for transaction import +#[derive(Debug, Clone, Binary)] +pub enum TransactionImportError { + /// Transaction error + Transaction(TransactionError), + /// Other error + Other(String), +} + +impl From for TransactionImportError { + fn from(e: Error) -> Self { + match e { + Error::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error), + _ => TransactionImportError::Other(format!("other block import error: {:?}", e)), + } + } +} diff --git a/ethcore/src/views/block.rs b/ethcore/src/views/block.rs index 82b8fb805..42fd52a20 100644 --- a/ethcore/src/views/block.rs +++ b/ethcore/src/views/block.rs @@ -139,6 +139,11 @@ impl<'a> BlockView<'a> { pub fn uncle_at(&self, index: usize) -> Option
{ self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val()) } + + /// Return nth uncle rlp. + pub fn uncle_rlp_at(&self, index: usize) -> Option { + self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_raw().to_vec()) + } } impl<'a> Hashable for BlockView<'a> { diff --git a/ipc/codegen/Cargo.toml b/ipc/codegen/Cargo.toml index 4d83b65e1..649882c51 100644 --- a/ipc/codegen/Cargo.toml +++ b/ipc/codegen/Cargo.toml @@ -22,5 +22,5 @@ aster = { version = "0.17", default-features = false } clippy = { version = "^0.*", optional = true } quasi = { version = "0.11", default-features = false } quasi_macros = { version = "0.11", optional = true } -syntex = { version = "*", optional = true } -syntex_syntax = { version = "*", optional = true } +syntex = { version = "0.33", optional = true } +syntex_syntax = { version = "0.33", optional = true } diff --git a/ipc/codegen/src/codegen.rs b/ipc/codegen/src/codegen.rs index 9dd6a7b32..c07f0b37a 100644 --- a/ipc/codegen/src/codegen.rs +++ b/ipc/codegen/src/codegen.rs @@ -201,15 +201,20 @@ fn implement_dispatch_arm_invoke_stmt( { let _sp = ext_cx.call_site(); let mut tt = ::std::vec::Vec::new(); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc")))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary")))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize")))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And))); + + if dispatch.return_type_ty.is_some() { + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc")))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary")))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize")))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And))); + } + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self")))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter()); @@ -221,12 +226,25 @@ fn implement_dispatch_arm_invoke_stmt( } tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap")))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); + + if dispatch.return_type_ty.is_some() { + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap")))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); + } + else { + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Semi)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Vec")))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("new")))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); + + } tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace))); + tt })).unwrap() } @@ -497,9 +515,9 @@ fn client_generics(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> .build() } -fn client_qualified_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P { +fn client_qualified_ident(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P { let generics = client_generics(builder, interface_map); - aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(builder)) + aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item)) .with_generics(generics).build() .build() } @@ -515,7 +533,7 @@ fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMa /// for say `Service` it generates `ServiceClient` fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap, push: &mut FnMut(Annotatable)) { let generics = client_generics(builder, interface_map); - let client_short_ident = interface_map.ident_map.client_ident(builder); + let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item); let phantom = client_phantom_ident(builder, interface_map); let client_struct_item = quote_item!(cx, @@ -547,9 +565,9 @@ fn push_with_socket_client_implementation( push: &mut FnMut(Annotatable)) { let generics = client_generics(builder, interface_map); - let client_ident = client_qualified_ident(builder, interface_map); + let client_ident = client_qualified_ident(cx, builder, interface_map); let where_clause = &generics.where_clause; - let client_short_ident = interface_map.ident_map.client_ident(builder); + let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item); let implement = quote_item!(cx, impl $generics ::ipc::WithSocket for $client_ident $where_clause { @@ -578,7 +596,7 @@ fn push_client_implementation( .collect::>>(); let generics = client_generics(builder, interface_map); - let client_ident = client_qualified_ident(builder, interface_map); + let client_ident = client_qualified_ident(cx, builder, interface_map); let where_clause = &generics.where_clause; let handshake_item = quote_impl_item!(cx, @@ -682,6 +700,52 @@ fn implement_handshake_arm( } +fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result { + match lit.node { + ast::LitKind::Str(ref s, _) => Ok(format!("{}", s)), + _ => { + cx.span_err( + lit.span, + &format!("ipc client_ident annotation `{}` must be a string, not `{}`", + name, + ::syntax::print::pprust::lit_to_string(lit))); + + return Err(()); + } + } +} + +pub fn get_ipc_meta_items(attr: &ast::Attribute) -> Option<&[P]> { + match attr.node.value.node { + ast::MetaItemKind::List(ref name, ref items) if name == &"ipc" => { + Some(items) + } + _ => None + } +} + +fn client_ident_renamed(cx: &ExtCtxt, item: &ast::Item) -> Option { + for meta_items in item.attrs().iter().filter_map(get_ipc_meta_items) { + for meta_item in meta_items { + let span = meta_item.span; + match meta_item.node { + ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"client_ident" => { + if let Ok(s) = get_str_from_lit(cx, name, lit) { + return Some(s); + } + } + _ => { + cx.span_err( + meta_item.span, + &format!("unknown client_ident container attribute `{}`", + ::syntax::print::pprust::meta_item_to_string(meta_item))); + } + } + } + } + None +} + struct InterfaceMap { pub original_item: Item, pub item: P, @@ -700,8 +764,13 @@ impl IdentMap { builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path))) } - fn client_ident(&self, builder: &aster::AstBuilder) -> Ident { - builder.id(format!("{}Client", self.original_path.segments[0].identifier)) + fn client_ident(&self, cx: &ExtCtxt, builder: &aster::AstBuilder, item: &ast::Item) -> Ident { + if let Some(new_name) = client_ident_renamed(cx, item) { + builder.id(new_name) + } + else { + builder.id(format!("{}Client", self.original_path.segments[0].identifier)) + } } fn qualified_ident(&self, builder: &aster::AstBuilder) -> Ident { diff --git a/ipc/codegen/src/lib.rs b/ipc/codegen/src/lib.rs index 126aa3a85..afa7979d0 100644 --- a/ipc/codegen/src/lib.rs +++ b/ipc/codegen/src/lib.rs @@ -50,11 +50,36 @@ include!("lib.rs.in"); #[cfg(feature = "with-syntex")] pub fn register(reg: &mut syntex::Registry) { + use syntax::{ast, fold}; + + #[cfg(feature = "with-syntex")] + fn strip_attributes(krate: ast::Crate) -> ast::Crate { + struct StripAttributeFolder; + impl fold::Folder for StripAttributeFolder { + fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { + match attr.node.value.node { + ast::MetaItemKind::List(ref n, _) if n == &"ipc" => { return None; } + _ => {} + } + + Some(attr) + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } + } + + fold::Folder::fold_crate(&mut StripAttributeFolder, krate) + } + reg.add_attr("feature(custom_derive)"); reg.add_attr("feature(custom_attribute)"); reg.add_decorator("derive_Ipc", codegen::expand_ipc_implementation); reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation); + + reg.add_post_expansion_pass(strip_attributes); } #[cfg(not(feature = "with-syntex"))] @@ -67,4 +92,6 @@ pub fn register(reg: &mut rustc_plugin::Registry) { syntax::parse::token::intern("derive_Binary"), syntax::ext::base::MultiDecorator( Box::new(serialization::expand_serialization_implementation))); + + reg.register_attribute("ipc".to_owned(), AttributeType::Normal); } diff --git a/ipc/rpc/src/binary.rs b/ipc/rpc/src/binary.rs index aabe19ed1..77de07be3 100644 --- a/ipc/rpc/src/binary.rs +++ b/ipc/rpc/src/binary.rs @@ -144,10 +144,8 @@ impl BinaryConvertable for BTreeMap where K : BinaryConvertable + Or 0usize + match K::len_params() { 0 => mem::size_of::() * self.len(), _ => self.iter().fold(0usize, |acc, (k, _)| acc + k.size()) - } - + - match V::len_params() { - 0 => mem::size_of::() * self.len(), + } + match V::len_params() { + 0 => mem::size_of::() * self.len(), 0 => mem::size_of::() * self.len(), _ => self.iter().fold(0usize, |acc, (_, v)| acc + v.size()) } } @@ -179,7 +177,7 @@ impl BinaryConvertable for BTreeMap where K : BinaryConvertable + Or Ok(()) } - fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque ) -> Result { + fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result { let mut index = 0; let mut result = Self::new(); @@ -192,8 +190,7 @@ impl BinaryConvertable for BTreeMap where K : BinaryConvertable + Or }; let key = if key_size == 0 { try!(K::from_empty_bytes()) - } - else { + } else { try!(K::from_bytes(&buffer[index..index+key_size], length_stack)) }; index = index + key_size; @@ -204,8 +201,7 @@ impl BinaryConvertable for BTreeMap where K : BinaryConvertable + Or }; let val = if val_size == 0 { try!(V::from_empty_bytes()) - } - else { + } else { try!(V::from_bytes(&buffer[index..index+val_size], length_stack)) }; result.insert(key, val); diff --git a/ipc/tests/Cargo.toml b/ipc/tests/Cargo.toml index f7a5ee9bd..d9c80145d 100644 --- a/ipc/tests/Cargo.toml +++ b/ipc/tests/Cargo.toml @@ -16,5 +16,5 @@ ethcore-ipc-nano = { path = "../nano" } ethcore-util = { path = "../../util" } [build-dependencies] -syntex = "*" +syntex = "0.33" ethcore-ipc-codegen = { path = "../codegen" } diff --git a/ipc/tests/build.rs b/ipc/tests/build.rs index e498e3405..6538f56e1 100644 --- a/ipc/tests/build.rs +++ b/ipc/tests/build.rs @@ -58,6 +58,23 @@ pub fn main() { registry.expand("", &src, &dst).unwrap(); } + // rpc pass + if { + let src = Path::new("with_attrs.rs.in"); + let dst = Path::new(&out_dir).join("with_attrs_ipc.rs"); + let mut registry = syntex::Registry::new(); + codegen::register(&mut registry); + registry.expand("", &src, &dst).is_ok() + } + // serialization pass + { + let src = Path::new(&out_dir).join("with_attrs_ipc.rs"); + let dst = Path::new(&out_dir).join("with_attrs_cg.rs"); + let mut registry = syntex::Registry::new(); + codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } + // rpc pass { let src = Path::new("binary.rs.in"); diff --git a/ipc/tests/examples.rs b/ipc/tests/examples.rs index 99cf385fa..8b52be11c 100644 --- a/ipc/tests/examples.rs +++ b/ipc/tests/examples.rs @@ -86,7 +86,7 @@ mod tests { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0], - service_client.socket().borrow().write_buffer.clone()); + service_client.socket().write().unwrap().write_buffer.clone()); assert_eq!(10, result); } @@ -103,7 +103,7 @@ mod tests { 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 10, 0, 0, 0], service_client.socket().borrow().write_buffer.clone()); + 5, 0, 0, 0, 10, 0, 0, 0], service_client.socket().write().unwrap().write_buffer.clone()); assert_eq!(10, result); } @@ -145,7 +145,7 @@ mod tests { // items 3, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0], - service_client.socket().borrow().write_buffer.clone()); + service_client.socket().write().unwrap().write_buffer.clone()); assert_eq!(true, result); } @@ -190,4 +190,20 @@ mod tests { assert_eq!(struct_, new_struct); } + + #[test] + fn can_call_void_method() { + let mut socket = TestSocket::new(); + socket.read_buffer = vec![1]; + let service_client = ServiceClient::init(socket); + + service_client.void(99); + + assert_eq!(vec![ + 0, 19, + 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 99, 0, 0, 0, 0, 0, 0, 0], + service_client.socket().write().unwrap().write_buffer.clone()); + } } diff --git a/ipc/tests/over_nano.rs b/ipc/tests/over_nano.rs index 36ad17f2a..bdeaec3d5 100644 --- a/ipc/tests/over_nano.rs +++ b/ipc/tests/over_nano.rs @@ -18,6 +18,7 @@ mod tests { use super::super::service::*; + use super::super::with_attrs::PrettyNamedClient; use nanoipc; use std::sync::Arc; use std::io::Write; @@ -43,6 +44,12 @@ mod tests { assert!(client.is_ok()); } + #[test] + fn can_create_renamed_client() { + let client = nanoipc::init_duplex_client::>("ipc:///tmp/parity-nano-test10.ipc"); + assert!(client.is_ok()); + } + #[test] fn can_call_handshake() { let url = "ipc:///tmp/parity-test-nano-20.ipc"; diff --git a/ipc/tests/run.rs b/ipc/tests/run.rs index cdda5275b..ab0041899 100644 --- a/ipc/tests/run.rs +++ b/ipc/tests/run.rs @@ -28,3 +28,4 @@ mod examples; mod over_nano; mod nested; mod binary; +mod with_attrs; diff --git a/ipc/tests/service.rs.in b/ipc/tests/service.rs.in index 2c58122bf..6bee63133 100644 --- a/ipc/tests/service.rs.in +++ b/ipc/tests/service.rs.in @@ -39,12 +39,14 @@ impl Service { *lock = *lock + f as usize; f } + pub fn rollback(&self, a: Option, b: u32) -> i32 { let a_0 = a.unwrap_or_else(|| 0); let mut lock = self.rollbacks.write().unwrap(); *lock = *lock + a_0 as usize - b as usize; (a_0 - b) as i32 } + pub fn push_custom(&self, data: CustomData) -> bool { let mut clock = self.commits.write().unwrap(); let mut rlock = self.commits.write().unwrap(); @@ -54,6 +56,9 @@ impl Service { true } + + pub fn void(&self, a: u64) { + } } impl Service { diff --git a/ipc/tests/with_attrs.rs b/ipc/tests/with_attrs.rs new file mode 100644 index 000000000..e9b3e0d76 --- /dev/null +++ b/ipc/tests/with_attrs.rs @@ -0,0 +1,18 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues +include!(concat!(env!("OUT_DIR"), "/with_attrs_cg.rs")); diff --git a/ethcore/src/types/transaction_import_result.rs b/ipc/tests/with_attrs.rs.in similarity index 72% rename from ethcore/src/types/transaction_import_result.rs rename to ipc/tests/with_attrs.rs.in index dc883c8c6..0168f3a72 100644 --- a/ethcore/src/types/transaction_import_result.rs +++ b/ipc/tests/with_attrs.rs.in @@ -14,16 +14,21 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Transaction import result related types - +use std::sync::RwLock; +use std::ops::*; +use ipc::IpcConfig; +use std::mem; use ipc::binary::BinaryConvertError; use std::collections::VecDeque; -#[derive(Debug, Clone, PartialEq, Binary)] -/// Represents the result of importing transaction. -pub enum TransactionImportResult { - /// Transaction was imported to current queue. - Current, - /// Transaction was imported to future queue. - Future +pub struct BadlyNamedService; + +#[derive(Ipc)] +#[ipc(client_ident="PrettyNamedClient")] +impl BadlyNamedService { + fn is_zero(&self, x: u64) -> bool { + x == 0 + } } + +impl ::ipc::IpcConfig for BadlyNamedService {} diff --git a/json/Cargo.toml b/json/Cargo.toml index e93f493e1..591d3969f 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -10,7 +10,7 @@ rustc-serialize = "0.3" serde = "0.7.0" serde_json = "0.7.0" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.77", optional = true} +clippy = { version = "0.0.78", optional = true} [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/parity/cli.rs b/parity/cli.rs index 7ebbcb0aa..17954eb2a 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -52,12 +52,21 @@ Protocol Options: Account Options: --unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution. ACCOUNTS is a comma-delimited list of addresses. + Implies --no-signer. --password FILE Provide a file containing a password for unlocking an account. --keys-iterations NUM Specify the number of iterations to use when deriving key from the password (bigger is more secure) [default: 10240]. --no-import-keys Do not import keys from legacy clients. + --force-signer Enable Trusted Signer WebSocket endpoint used by + Signer UIs, even when --unlock is in use. + --no-signer Disable Trusted Signer WebSocket endpoint used by + Signer UIs. + --signer-port PORT Specify the port of Trusted Signer server + [default: 8180]. + --signer-path PATH Specify directory where Signer UIs tokens should + be stored. [default: $HOME/.parity/signer] Networking Options: --no-network Disable p2p networking. @@ -114,17 +123,6 @@ API and Console Options: --dapps-path PATH Specify directory where dapps should be installed. [default: $HOME/.parity/dapps] - --signer Enable Trusted Signer WebSocket endpoint used by - Signer UIs. Default if run with ui command. - --no-signer Disable Trusted Signer WebSocket endpoint used by - Signer UIs. Default if no command is specified. - --signer-port PORT Specify the port of Trusted Signer server - [default: 8180]. - --signer-path PATH Specify directory where Signer UIs tokens should - be stored. [default: $HOME/.parity/signer] - --no-token By default a new system UI security token will be - output on start up. This will prevent it. - Sealing/Mining Options: --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks. @@ -203,6 +201,7 @@ Database Options: --db-compaction TYPE Database compaction type. TYPE may be one of: ssd - suitable for SSDs and fast HDDs; hdd - suitable for slow HDDs [default: ssd]. + --fat-db Fat database. Import/Export Options: --from BLOCK Export from block BLOCK, which may be an index or @@ -308,11 +307,10 @@ pub struct Args { pub flag_dapps_user: Option, pub flag_dapps_pass: Option, pub flag_dapps_path: String, - pub flag_signer: bool, + pub flag_force_signer: bool, pub flag_no_signer: bool, pub flag_signer_port: u16, pub flag_signer_path: String, - pub flag_no_token: bool, pub flag_force_sealing: bool, pub flag_reseal_on_txs: String, pub flag_reseal_min_period: u64, @@ -362,6 +360,7 @@ pub struct Args { pub flag_ipcapi: Option, pub flag_db_cache_size: Option, pub flag_db_compaction: String, + pub flag_fat_db: bool, } pub fn print_version() { diff --git a/parity/configuration.rs b/parity/configuration.rs index fb31bf7ad..14932423c 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -254,7 +254,7 @@ impl Configuration { let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host)); Some(SocketAddr::new(host, port)) } else { - listen_address + None }; (listen_address, public_address) } @@ -333,6 +333,14 @@ impl Configuration { _ => { die!("Invalid pruning method given."); } }; + if self.args.flag_fat_db { + if let journaldb::Algorithm::Archive = client_config.pruning { + client_config.trie_spec = TrieSpec::Fat; + } else { + die!("Fatdb is not supported. Please rerun with --pruning=archive") + } + } + // forced state db cache size if provided client_config.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 4)); @@ -340,7 +348,7 @@ impl Configuration { client_config.db_compaction = match self.args.flag_db_compaction.as_str() { "ssd" => DatabaseCompactionProfile::Default, "hdd" => DatabaseCompactionProfile::HDD, - _ => { die!("Invalid compaction profile given (--db-compaction argument), expected hdd/default."); } + _ => { die!("Invalid compaction profile given (--db-compaction argument), expected hdd/ssd (default)."); } }; if self.args.flag_jitvm { @@ -467,6 +475,11 @@ impl Configuration { let signer_path = Configuration::replace_home(&self.args.flag_signer_path); ::std::fs::create_dir_all(&signer_path).unwrap_or_else(|e| die_with_io_error("main", e)); + if self.args.flag_geth { + let geth_path = path::ethereum::default(); + ::std::fs::create_dir_all(geth_path.as_path()).unwrap_or_else( + |e| die!("Error while attempting to create '{}' for geth mode: {}", &geth_path.to_str().unwrap(), e)); + } Directories { keys: keys_path, @@ -531,8 +544,8 @@ impl Configuration { } pub fn signer_enabled(&self) -> bool { - (self.args.cmd_ui && !self.args.flag_no_signer) || - (!self.args.cmd_ui && self.args.flag_signer) + (self.args.flag_unlock.is_none() && !self.args.flag_no_signer) || + self.args.flag_force_signer } } diff --git a/parity/main.rs b/parity/main.rs index 8d46d28e5..b7a106181 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -193,13 +193,6 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig) let net_settings = conf.net_settings(&spec); let sync_config = conf.sync_config(&spec); - // Create and display a new token for UIs. - if conf.signer_enabled() && !conf.args.flag_no_token { - new_token(conf.directories().signer).unwrap_or_else(|e| { - die!("Error generating token: {:?}", e) - }); - } - // Display warning about using unlock with signer if conf.signer_enabled() && conf.args.flag_unlock.is_some() { warn!("Using Trusted Signer and --unlock is not recommended!"); diff --git a/parity/price_info.rs b/parity/price_info.rs index ad25f31da..0c04b3a77 100644 --- a/parity/price_info.rs +++ b/parity/price_info.rs @@ -28,10 +28,12 @@ impl PriceInfo { pub fn get() -> Option { let mut body = String::new(); // TODO: Handle each error type properly - Client::new() - .get("http://api.etherscan.io/api?module=stats&action=ethprice") + let mut client = Client::new(); + client.set_read_timeout(Some(::std::time::Duration::from_secs(3))); + client.get("http://api.etherscan.io/api?module=stats&action=ethprice") .header(Connection::close()) - .send().ok() + .send() + .ok() .and_then(|mut s| s.read_to_string(&mut body).ok()) .and_then(|_| Json::from_str(&body).ok()) .and_then(|json| json.find_path(&["result", "ethusd"]) diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index f5563b50b..ed9bfd347 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -23,7 +23,7 @@ ethcore-devtools = { path = "../devtools" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.77", optional = true} +clippy = { version = "0.0.78", optional = true} json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" } ethcore-ipc = { path = "../ipc/rpc" } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 9e1713eb1..7f9d5c1ed 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -42,6 +42,7 @@ use v1::traits::Eth; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::impls::{default_gas_price, dispatch_transaction, error_codes}; use serde; +use ethcore::header::Header as BlockHeader; /// Eth rpc implementation. pub struct EthClient where diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 4ef8bb03e..5e59d04a7 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -20,7 +20,7 @@ ethcore-util = { path = "../util" } ethcore-rpc = { path = "../rpc" } parity-minimal-sysui = { git = "https://github.com/ethcore/parity-dapps-minimal-sysui-rs.git", version = "0.2.0" } -clippy = { version = "0.0.77", optional = true} +clippy = { version = "0.0.78", optional = true} [features] dev = ["clippy"] diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 10edcd0ed..1cf9d21a4 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore 0 { @@ -1052,14 +1052,18 @@ macro_rules! construct_uint { let word_shift = shift / 64; let bit_shift = shift % 64; + // shift for i in word_shift..$n_words { - // Shift - ret[i - word_shift] += original[i] >> bit_shift; - // Carry - if bit_shift > 0 && i < $n_words - 1 { - ret[i - word_shift] += original[i + 1] << (64 - bit_shift); + ret[i - word_shift] = original[i] >> bit_shift; + } + + // Carry + if bit_shift > 0 { + for i in word_shift+1..$n_words { + ret[i - word_shift - 1] += original[i] << (64 - bit_shift); } } + $name(ret) } } diff --git a/util/src/error.rs b/util/src/error.rs index 5e9f8e7a8..c5f40d717 100644 --- a/util/src/error.rs +++ b/util/src/error.rs @@ -101,7 +101,7 @@ impl fmt::Display for Mismatch { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone)] /// Error indicating value found is outside of a valid range. pub struct OutOfBounds { /// Minimum allowed value. diff --git a/util/src/hashdb.rs b/util/src/hashdb.rs index 1ec3069d8..51b9d445e 100644 --- a/util/src/hashdb.rs +++ b/util/src/hashdb.rs @@ -104,6 +104,21 @@ pub trait HashDB: AsHashDB { /// } /// ``` fn remove(&mut self, key: &H256); + + /// Insert auxiliary data into hashdb. + fn insert_aux(&mut self, _hash: Vec, _value: Vec) { + unimplemented!(); + } + + /// Get auxiliary data from hashdb. + fn get_aux(&self, _hash: &[u8]) -> Option> { + unimplemented!(); + } + + /// Removes auxiliary data from hashdb. + fn remove_aux(&mut self, _hash: &[u8]) { + unimplemented!(); + } } /// Upcast trait. diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index a01ed807f..40172cccd 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -26,6 +26,13 @@ use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; +/// Suffix appended to auxiliary keys to distinguish them from normal keys. +/// Would be nich to use rocksdb columns for this eventually. +const AUX_FLAG: u8 = 255; + +/// Database version. +const DB_VERSION : u32 = 0x103; + /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// @@ -39,8 +46,6 @@ pub struct ArchiveDB { latest_era: Option, } -const DB_VERSION : u32 = 0x103; - impl ArchiveDB { /// Create a new instance from file pub fn new(path: &str, config: DatabaseConfig) -> ArchiveDB { @@ -115,12 +120,35 @@ impl HashDB for ArchiveDB { fn insert(&mut self, value: &[u8]) -> H256 { self.overlay.insert(value) } + fn emplace(&mut self, key: H256, value: Bytes) { self.overlay.emplace(key, value); } + fn remove(&mut self, key: &H256) { self.overlay.remove(key); } + + fn insert_aux(&mut self, hash: Vec, value: Vec) { + self.overlay.insert_aux(hash, value); + } + + fn get_aux(&self, hash: &[u8]) -> Option> { + if let Some(res) = self.overlay.get_aux(hash) { + return Some(res) + } + + let mut db_hash = hash.to_vec(); + db_hash.push(AUX_FLAG); + + self.backing.get(&db_hash) + .expect("Low-level database error. Some issue with your hard disk?") + .map(|v| v.to_vec()) + } + + fn remove_aux(&mut self, hash: &[u8]) { + self.overlay.remove_aux(hash); + } } impl JournalDB for ArchiveDB { @@ -144,6 +172,7 @@ impl JournalDB for ArchiveDB { let batch = DBTransaction::new(); let mut inserts = 0usize; let mut deletes = 0usize; + for i in self.overlay.drain().into_iter() { let (key, (value, rc)) = i; if rc > 0 { @@ -156,6 +185,12 @@ impl JournalDB for ArchiveDB { deletes += 1; } } + + for (mut key, value) in self.overlay.drain_aux().into_iter() { + key.push(AUX_FLAG); + batch.put(&key, &value).expect("Low-level database error. Some issue with your hard disk?"); + } + if self.latest_era.map_or(true, |e| now > e) { try!(batch.put(&LATEST_ERA_KEY, &encode(&now))); self.latest_era = Some(now); diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index ea77f4aa2..f63dfd992 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -74,6 +74,7 @@ use std::default::Default; pub struct MemoryDB { data: HashMap, static_null_rlp: (Bytes, i32), + aux: HashMap, } impl Default for MemoryDB { @@ -88,6 +89,7 @@ impl MemoryDB { MemoryDB { data: HashMap::new(), static_null_rlp: (vec![0x80u8; 1], 1), + aux: HashMap::new(), } } @@ -134,9 +136,12 @@ impl MemoryDB { /// 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 + mem::replace(&mut self.data, HashMap::new()) + } + + /// Return the internal map of auxiliary data, clearing the current state. + pub fn drain_aux(&mut self) -> HashMap { + mem::replace(&mut self.aux, HashMap::new()) } /// Denote than an existing value has the given key. Used when a key gets removed without @@ -233,6 +238,18 @@ impl HashDB for MemoryDB { self.data.insert(key.clone(), (Bytes::new(), -1)); } } + + fn insert_aux(&mut self, hash: Vec, value: Vec) { + self.aux.insert(hash, value); + } + + fn get_aux(&self, hash: &[u8]) -> Option> { + self.aux.get(hash).cloned() + } + + fn remove_aux(&mut self, hash: &[u8]) { + self.aux.remove(hash); + } } #[test] diff --git a/util/src/network/host.rs b/util/src/network/host.rs index a48d1544c..a8bbc17e5 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -539,7 +539,7 @@ impl Host where Message: Send + Sync + Clone { self.info.write().unwrap().public_endpoint = Some(public_endpoint.clone()); if self.first_time.load(AtomicOrdering::Relaxed) { - info!("Public node URL: {}", paint(White.bold(), format!("{}", self.external_url().unwrap()))); + info!("Public node URL: {}", paint(White.bold(), self.external_url().unwrap())); self.first_time.store(false, AtomicOrdering::Relaxed); } diff --git a/util/src/trie/fatdb.rs b/util/src/trie/fatdb.rs new file mode 100644 index 000000000..cc5786f43 --- /dev/null +++ b/util/src/trie/fatdb.rs @@ -0,0 +1,113 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use hash::H256; +use sha3::Hashable; +use hashdb::HashDB; +use super::{TrieDB, Trie, TrieDBIterator, TrieError}; +use trie::trietraits::TrieItem; + +/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. +/// Additionaly it stores inserted hash-key mappings for later retrieval. +/// +/// Use it as a `Trie` or `TrieMut` trait object. +pub struct FatDB<'db> { + raw: TrieDB<'db>, +} + +impl<'db> FatDB<'db> { + /// Create a new trie with the backing database `db` and empty `root` + /// Initialise to the state entailed by the genesis block. + /// This guarantees the trie is built correctly. + pub fn new(db: &'db HashDB, root: &'db H256) -> Result { + let fatdb = FatDB { + raw: try!(TrieDB::new(db, root)) + }; + + Ok(fatdb) + } + + /// Get the backing database. + pub fn db(&self) -> &HashDB { + self.raw.db() + } + + /// Iterator over all key / vlaues in the trie. + pub fn iter(&self) -> FatDBIterator { + FatDBIterator::new(&self.raw) + } +} + +impl<'db> Trie for FatDB<'db> { + fn iter<'a>(&'a self) -> Box + 'a> { + Box::new(FatDB::iter(self)) + } + + fn root(&self) -> &H256 { + self.raw.root() + } + + fn contains(&self, key: &[u8]) -> bool { + self.raw.contains(&key.sha3()) + } + + fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { + self.raw.get(&key.sha3()) + } +} + +/// Itarator over inserted pairs of key values. +pub struct FatDBIterator<'db> { + trie_iterator: TrieDBIterator<'db>, + trie: &'db TrieDB<'db>, +} + +impl<'db> FatDBIterator<'db> { + /// Creates new iterator. + pub fn new(trie: &'db TrieDB) -> Self { + FatDBIterator { + trie_iterator: TrieDBIterator::new(trie), + trie: trie, + } + } +} + +impl<'db> Iterator for FatDBIterator<'db> { + type Item = (Vec, &'db [u8]); + + fn next(&mut self) -> Option { + self.trie_iterator.next() + .map(|(hash, value)| { + (self.trie.db().get_aux(&hash).expect("Missing fatdb hash"), value) + }) + } +} + +#[test] +fn fatdb_to_trie() { + use memorydb::MemoryDB; + use trie::{FatDBMut, TrieMut}; + + let mut memdb = MemoryDB::new(); + let mut root = H256::default(); + { + let mut t = FatDBMut::new(&mut memdb, &mut root); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); + } + let t = FatDB::new(&memdb, &root).unwrap(); + assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]); + assert_eq!(t.iter().collect::>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]); +} diff --git a/util/src/trie/fatdbmut.rs b/util/src/trie/fatdbmut.rs new file mode 100644 index 000000000..e07ee0ed1 --- /dev/null +++ b/util/src/trie/fatdbmut.rs @@ -0,0 +1,95 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use hash::H256; +use sha3::Hashable; +use hashdb::HashDB; +use super::{TrieDBMut, TrieMut, TrieError}; + +/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. +/// Additionaly it stores inserted hash-key mappings for later retrieval. +/// +/// Use it as a `Trie` or `TrieMut` trait object. +pub struct FatDBMut<'db> { + raw: TrieDBMut<'db>, +} + +impl<'db> FatDBMut<'db> { + /// Create a new trie with the backing database `db` and empty `root` + /// Initialise to the state entailed by the genesis block. + /// This guarantees the trie is built correctly. + pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { + FatDBMut { raw: TrieDBMut::new(db, root) } + } + + /// Create a new trie with the backing database `db` and `root`. + /// + /// Returns an error if root does not exist. + pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Result { + Ok(FatDBMut { raw: try!(TrieDBMut::from_existing(db, root)) }) + } + + /// Get the backing database. + pub fn db(&self) -> &HashDB { + self.raw.db() + } + + /// Get the backing database. + pub fn db_mut(&mut self) -> &mut HashDB { + self.raw.db_mut() + } +} + +impl<'db> TrieMut for FatDBMut<'db> { + fn root(&self) -> &H256 { + self.raw.root() + } + + fn contains(&self, key: &[u8]) -> bool { + self.raw.contains(&key.sha3()) + } + + fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { + self.raw.get(&key.sha3()) + } + + fn insert(&mut self, key: &[u8], value: &[u8]) { + let hash = key.sha3(); + self.raw.insert(&hash, value); + let db = self.raw.db_mut(); + db.insert_aux(hash.to_vec(), key.to_vec()); + } + + fn remove(&mut self, key: &[u8]) { + self.raw.remove(&key.sha3()); + } +} + +#[test] +fn fatdb_to_trie() { + use memorydb::MemoryDB; + use super::TrieDB; + use super::Trie; + + let mut memdb = MemoryDB::new(); + let mut root = H256::default(); + { + let mut t = FatDBMut::new(&mut memdb, &mut root); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); + } + let t = TrieDB::new(&memdb, &root).unwrap(); + assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap(), &[0x01u8, 0x23]); +} diff --git a/util/src/trie/mod.rs b/util/src/trie/mod.rs index 79135162c..2843932a7 100644 --- a/util/src/trie/mod.rs +++ b/util/src/trie/mod.rs @@ -17,6 +17,8 @@ //! Trie interface and implementation. use std::fmt; +use hash::H256; +use hashdb::HashDB; /// Export the trietraits module. pub mod trietraits; @@ -35,12 +37,18 @@ pub mod sectriedb; /// Export the sectriedbmut module. pub mod sectriedbmut; +mod fatdb; + +mod fatdbmut; + pub use self::trietraits::{Trie, TrieMut}; pub use self::standardmap::{Alphabet, StandardMap, ValueMode}; pub use self::triedbmut::TrieDBMut; -pub use self::triedb::TrieDB; +pub use self::triedb::{TrieDB, TrieDBIterator}; pub use self::sectriedbmut::SecTrieDBMut; pub use self::sectriedb::SecTrieDB; +pub use self::fatdb::{FatDB, FatDBIterator}; +pub use self::fatdbmut::FatDBMut; /// Trie Errors #[derive(Debug)] @@ -53,4 +61,64 @@ impl fmt::Display for TrieError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Trie Error: Invalid state root.") } -} \ No newline at end of file +} + +/// Trie types +#[derive(Debug, Clone)] +pub enum TrieSpec { + /// Generic trie. + Generic, + /// Secure trie. + Secure, + /// Secure trie with fat database. + Fat, +} + +impl Default for TrieSpec { + fn default() -> TrieSpec { + TrieSpec::Secure + } +} + +/// Trie factory. +#[derive(Default, Clone)] +pub struct TrieFactory { + spec: TrieSpec, +} + +#[cfg_attr(feature="dev", allow(wrong_self_convention))] +impl TrieFactory { + /// Creates new factory. + pub fn new(spec: TrieSpec) -> Self { + TrieFactory { + spec: spec, + } + } + + /// Create new immutable instance of Trie. + pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result, TrieError> { + match self.spec { + TrieSpec::Generic => Ok(Box::new(try!(TrieDB::new(db, root)))), + TrieSpec::Secure => Ok(Box::new(try!(SecTrieDB::new(db, root)))), + TrieSpec::Fat => Ok(Box::new(try!(FatDB::new(db, root)))), + } + } + + /// Create new mutable instance of Trie. + pub fn create<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Box { + match self.spec { + TrieSpec::Generic => Box::new(TrieDBMut::new(db, root)), + TrieSpec::Secure => Box::new(SecTrieDBMut::new(db, root)), + TrieSpec::Fat => Box::new(FatDBMut::new(db, root)), + } + } + + /// Create new mutable instance of trie and check for errors. + pub fn from_existing<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Result, TrieError> { + match self.spec { + TrieSpec::Generic => Ok(Box::new(try!(TrieDBMut::from_existing(db, root)))), + TrieSpec::Secure => Ok(Box::new(try!(SecTrieDBMut::from_existing(db, root)))), + TrieSpec::Fat => Ok(Box::new(try!(FatDBMut::from_existing(db, root)))), + } + } +} diff --git a/util/src/trie/sectriedb.rs b/util/src/trie/sectriedb.rs index eda4ac58b..9217fb4fc 100644 --- a/util/src/trie/sectriedb.rs +++ b/util/src/trie/sectriedb.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use hash::*; -use sha3::*; +use hash::H256; +use sha3::Hashable; use hashdb::HashDB; use super::triedb::TrieDB; -use super::trietraits::Trie; +use super::trietraits::{Trie, TrieItem}; use super::TrieError; /// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. @@ -50,6 +50,10 @@ impl<'db> SecTrieDB<'db> { } impl<'db> Trie for SecTrieDB<'db> { + fn iter<'a>(&'a self) -> Box + 'a> { + Box::new(TrieDB::iter(&self.raw)) + } + fn root(&self) -> &H256 { self.raw.root() } fn contains(&self, key: &[u8]) -> bool { @@ -68,7 +72,7 @@ fn trie_to_sectrie() { use super::trietraits::TrieMut; let mut memdb = MemoryDB::new(); - let mut root = H256::new(); + let mut root = H256::default(); { let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&(&[0x01u8, 0x23]).sha3(), &[0x01u8, 0x23]); diff --git a/util/src/trie/sectriedbmut.rs b/util/src/trie/sectriedbmut.rs index 9c8231af4..243e5dec8 100644 --- a/util/src/trie/sectriedbmut.rs +++ b/util/src/trie/sectriedbmut.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use hash::*; -use sha3::*; +use hash::H256; +use sha3::Hashable; use hashdb::HashDB; use super::triedbmut::TrieDBMut; -use super::trietraits::{Trie, TrieMut}; +use super::trietraits::TrieMut; use super::TrieError; /// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. @@ -44,13 +44,13 @@ impl<'db> SecTrieDBMut<'db> { } /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { self.raw.db() } + pub fn db(&self) -> &HashDB { self.raw.db() } /// Get the backing database. - pub fn db_mut(&'db mut self) -> &'db mut HashDB { self.raw.db_mut() } + pub fn db_mut(&mut self) -> &mut HashDB { self.raw.db_mut() } } -impl<'db> Trie for SecTrieDBMut<'db> { +impl<'db> TrieMut for SecTrieDBMut<'db> { fn root(&self) -> &H256 { self.raw.root() } fn contains(&self, key: &[u8]) -> bool { @@ -60,9 +60,7 @@ impl<'db> Trie for SecTrieDBMut<'db> { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { self.raw.get(&key.sha3()) } -} -impl<'db> TrieMut for SecTrieDBMut<'db> { fn insert(&mut self, key: &[u8], value: &[u8]) { self.raw.insert(&key.sha3(), value); } @@ -76,9 +74,10 @@ impl<'db> TrieMut for SecTrieDBMut<'db> { fn sectrie_to_trie() { use memorydb::*; use super::triedb::*; + use super::Trie; let mut memdb = MemoryDB::new(); - let mut root = H256::new(); + let mut root = H256::default(); { let mut t = SecTrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index 9cd3a8c41..e938fcc64 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -18,7 +18,7 @@ use common::*; use hashdb::*; use nibbleslice::*; use rlp::*; -use super::trietraits::Trie; +use super::trietraits::{Trie, TrieItem}; use super::node::Node; use super::TrieError; @@ -257,7 +257,7 @@ pub struct TrieDBIterator<'a> { impl<'a> TrieDBIterator<'a> { /// Create a new iterator. - fn new(db: &'a TrieDB) -> TrieDBIterator<'a> { + pub fn new(db: &'a TrieDB) -> TrieDBIterator<'a> { let mut r = TrieDBIterator { db: db, trail: vec![], @@ -331,10 +331,16 @@ impl<'a> Iterator for TrieDBIterator<'a> { impl<'db> TrieDB<'db> { /// Get all keys/values stored in the trie. - pub fn iter(&self) -> TrieDBIterator { TrieDBIterator::new(self) } + pub fn iter(&self) -> TrieDBIterator { + TrieDBIterator::new(self) + } } impl<'db> Trie for TrieDB<'db> { + fn iter<'a>(&'a self) -> Box + 'a> { + Box::new(TrieDB::iter(self)) + } + fn root(&self) -> &H256 { &self.root } fn contains(&self, key: &[u8]) -> bool { diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 65d5bbd2b..4d46814c0 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -20,7 +20,7 @@ use nibbleslice::*; use rlp::*; use super::node::Node; use super::journal::Journal; -use super::trietraits::{Trie, TrieMut}; +use super::trietraits::TrieMut; use super::TrieError; /// A `Trie` implementation using a generic `HashDB` backing database. @@ -99,12 +99,12 @@ impl<'db> TrieDBMut<'db> { } /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { + pub fn db(&self) -> &HashDB { self.db } /// Get the backing database. - pub fn db_mut(&'db mut self) -> &'db mut HashDB { + pub fn db_mut(&mut self) -> &mut HashDB { self.db } @@ -642,7 +642,7 @@ impl<'db> TrieDBMut<'db> { } } -impl<'db> Trie for TrieDBMut<'db> { +impl<'db> TrieMut for TrieDBMut<'db> { fn root(&self) -> &H256 { &self.root } fn contains(&self, key: &[u8]) -> bool { @@ -652,9 +652,7 @@ impl<'db> Trie for TrieDBMut<'db> { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { self.do_lookup(&NibbleSlice::new(key)) } -} -impl<'db> TrieMut for TrieDBMut<'db> { fn insert(&mut self, key: &[u8], value: &[u8]) { match value.is_empty() { false => self.insert_ns(&NibbleSlice::new(key), value), diff --git a/util/src/trie/trietraits.rs b/util/src/trie/trietraits.rs index 160f9466f..f4d53d158 100644 --- a/util/src/trie/trietraits.rs +++ b/util/src/trie/trietraits.rs @@ -17,6 +17,9 @@ use hash::H256; use rlp::SHA3_NULL_RLP; +/// Trie-Item type. +pub type TrieItem<'a> = (Vec, &'a[u8]); + /// A key-value datastore implemented as a database-backed modified Merkle tree. pub trait Trie { /// Return the root of the trie. @@ -30,10 +33,25 @@ pub trait Trie { /// What is the value of the given key in this trie? fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key; + + /// Returns an iterator over elements of trie. + fn iter<'a>(&'a self) -> Box + 'a>; } /// A key-value datastore implemented as a database-backed modified Merkle tree. -pub trait TrieMut: Trie { +pub trait TrieMut { + /// Return the root of the trie. + fn root(&self) -> &H256; + + /// Is the trie empty? + fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP } + + /// Does the trie contain a given key? + fn contains(&self, key: &[u8]) -> bool; + + /// What is the value of the given key in this trie? + fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key; + /// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing /// `key` from the trie. fn insert(&mut self, key: &[u8], value: &[u8]); @@ -42,4 +60,3 @@ pub trait TrieMut: Trie { /// value. fn remove(&mut self, key: &[u8]); } -