From dfb2ddfdc2784b251ff3080c47c9dabde6068ba6 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Fri, 12 Aug 2016 12:16:20 +0200 Subject: [PATCH] Backports to beta (#1919) * RPC errors & logs (#1845) * Refactoring errors in RPC * Updating jsonrpc-core * Fixing code_at * Avoid mentioning obvious segments in proof [ci:skip] * fixed cache_manager lock order * Purging .derefs, fixing clippy warnings. (#1890) * Fixing clippy warnings * Purging derefs * Simplifying engine derefs * Simplifying more engine derefs * Adding more details to miner log * fixed #1889, .DS_Store is no longer treated as key file (#1892) * fixed #1889, .DS_Store is no longer treated as key file * ethstore filters directories, hidden files and common system files * fixed compiling * fix regression with geth dir * fix regression with geth dir * Fix ipc compilation and add ipc feature to test targets (#1902) * fix compilation and add it to the ci run * no separator? * use quotes and spaces * RocksDB version bump * Don't return deleted nodes that are not yet flushed (#1908) * polling & connection timeouts (#1910) * Peers RPC + UI displaying active/connected/max peers (#1915) * Peers API * Bumping Parity-UI * Fixing tests * Save nodes removed from backing_overlay until commit (#1917) --- Cargo.lock | 68 +++--- dapps/Cargo.toml | 10 +- ethcore/src/block.rs | 21 +- ethcore/src/blockchain/blockchain.rs | 94 +++++--- ethcore/src/cache_manager.rs | 11 +- ethcore/src/client/client.rs | 4 +- ethcore/src/client/test_client.rs | 15 +- ethcore/src/client/traits.rs | 10 +- ethcore/src/engines/basic_authority.rs | 6 +- ethcore/src/engines/instant_seal.rs | 6 +- ethcore/src/ethereum/ethash.rs | 8 +- ethcore/src/json_tests/state.rs | 2 +- ethcore/src/lib.rs | 2 + ethcore/src/miner/miner.rs | 10 +- ethcore/src/miner/transaction_queue.rs | 6 +- ethcore/src/snapshot/error.rs | 14 +- ethcore/src/snapshot/mod.rs | 16 +- ethcore/src/snapshot/service.rs | 22 +- ethcore/src/snapshot/tests/blocks.rs | 4 +- ethcore/src/snapshot/tests/helpers.rs | 4 +- ethcore/src/snapshot/tests/state.rs | 4 +- ethcore/src/state.rs | 22 +- ethcore/src/tests/helpers.rs | 6 +- ethcore/src/trace/db.rs | 39 ++-- ethcore/src/verification/verification.rs | 32 +-- ethkey/src/signature.rs | 2 +- ethstore/src/account/safe_account.rs | 5 +- ethstore/src/bin/ethstore.rs | 2 +- ethstore/src/dir/disk.rs | 11 +- ipc/nano/src/lib.rs | 6 +- parity/configuration.rs | 12 +- parity/informant.rs | 11 +- parity/rpc_apis.rs | 2 +- parity/run.rs | 8 +- parity/snapshot.rs | 8 +- rpc/Cargo.toml | 2 +- rpc/src/v1/helpers/dispatch.rs | 96 ++++++++ rpc/src/v1/helpers/errors.rs | 188 ++++++++++++++++ rpc/src/v1/helpers/mod.rs | 4 + rpc/src/v1/helpers/network_settings.rs | 6 - rpc/src/v1/helpers/params.rs | 53 +++++ rpc/src/v1/impls/eth.rs | 275 ++++++++++------------- rpc/src/v1/impls/eth_filter.rs | 34 ++- rpc/src/v1/impls/eth_signing.rs | 14 +- rpc/src/v1/impls/ethcore.rs | 113 ++++++---- rpc/src/v1/impls/ethcore_set.rs | 18 +- rpc/src/v1/impls/mod.rs | 211 +---------------- rpc/src/v1/impls/net.rs | 10 +- rpc/src/v1/impls/personal.rs | 34 +-- rpc/src/v1/impls/personal_signer.rs | 10 +- rpc/src/v1/impls/rpc.rs | 7 +- rpc/src/v1/impls/traces.rs | 6 +- rpc/src/v1/impls/web3.rs | 7 +- rpc/src/v1/mod.rs | 3 +- rpc/src/v1/tests/mocked/ethcore.rs | 96 +++++--- rpc/src/v1/traits/ethcore.rs | 6 +- rpc/src/v1/types/mod.rs.in | 2 +- rpc/src/v1/types/sync.rs | 20 +- signer/Cargo.toml | 4 +- sync/src/api.rs | 17 +- sync/src/chain.rs | 19 +- sync/src/tests/chain.rs | 15 +- test.sh | 6 +- util/io/src/panics.rs | 3 +- util/network/src/host.rs | 2 +- util/network/src/tests.rs | 2 +- util/src/hash.rs | 4 +- util/src/journaldb/archivedb.rs | 2 +- util/src/journaldb/earlymergedb.rs | 2 +- util/src/journaldb/overlayrecentdb.rs | 41 +++- util/src/journaldb/refcounteddb.rs | 2 +- util/src/journaldb/traits.rs | 8 +- util/src/kvdb.rs | 132 +++++------ util/src/overlaydb.rs | 7 +- util/src/rlp/rlpstream.rs | 6 +- util/src/rlp/rlptraits.rs | 5 +- util/src/trie/triedb.rs | 2 +- 77 files changed, 1139 insertions(+), 858 deletions(-) create mode 100644 rpc/src/v1/helpers/dispatch.rs create mode 100644 rpc/src/v1/helpers/errors.rs create mode 100644 rpc/src/v1/helpers/params.rs diff --git a/Cargo.lock b/Cargo.lock index 9a4eefa08..4e8ca1e11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,14 +277,14 @@ dependencies = [ "ethcore-rpc 1.3.0", "ethcore-util 1.3.0", "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", - "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", - "parity-dapps-home 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", - "parity-dapps-status 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", - "parity-dapps-wallet 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps-home 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps-status 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps-wallet 1.4.0 (git+https://github.com/ethcore/parity-ui.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)", "serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -417,7 +417,7 @@ dependencies = [ "ethjson 0.1.0", "ethsync 1.3.0", "json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)", - "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -437,9 +437,9 @@ dependencies = [ "ethcore-io 1.3.0", "ethcore-rpc 1.3.0", "ethcore-util 1.3.0", - "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-dapps-signer 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.5.2 (git+https://github.com/ethcore/ws-rs.git?branch=mio-upstream-stable)", @@ -685,7 +685,7 @@ source = "git+https://github.com/ethcore/json-ipc-server.git#56b6307130710ebc73c dependencies = [ "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -695,13 +695,13 @@ dependencies = [ [[package]] name = "jsonrpc-core" -version = "2.0.7" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -710,7 +710,7 @@ version = "6.1.0" source = "git+https://github.com/ethcore/jsonrpc-http-server.git#4e3f93eb79125e91a46e04d77c25ff8885498b86" dependencies = [ "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", - "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -987,8 +987,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-dapps" -version = "0.6.0" -source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a" +version = "1.4.0" +source = "git+https://github.com/ethcore/parity-ui.git#fa7c8b054507b0c85db22e555fe7cca838704661" 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)", @@ -1001,34 +1001,34 @@ dependencies = [ [[package]] name = "parity-dapps-home" -version = "0.6.0" -source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a" +version = "1.4.0" +source = "git+https://github.com/ethcore/parity-ui.git#fa7c8b054507b0c85db22e555fe7cca838704661" dependencies = [ - "parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] [[package]] name = "parity-dapps-signer" -version = "0.6.0" -source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a" +version = "1.4.0" +source = "git+https://github.com/ethcore/parity-ui.git#fa7c8b054507b0c85db22e555fe7cca838704661" dependencies = [ - "parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] [[package]] name = "parity-dapps-status" -version = "0.6.0" -source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a" +version = "1.4.0" +source = "git+https://github.com/ethcore/parity-ui.git#fa7c8b054507b0c85db22e555fe7cca838704661" dependencies = [ - "parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] [[package]] name = "parity-dapps-wallet" -version = "0.6.0" -source = "git+https://github.com/ethcore/parity-ui.git#697e860dedc45003909602a002e7743478ab173a" +version = "1.4.0" +source = "git+https://github.com/ethcore/parity-ui.git#fa7c8b054507b0c85db22e555fe7cca838704661" dependencies = [ - "parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", + "parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)", ] [[package]] @@ -1183,7 +1183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" version = "0.4.5" -source = "git+https://github.com/ethcore/rust-rocksdb#eadce7f74cfe92b99ce63a77af425b47857239b8" +source = "git+https://github.com/ethcore/rust-rocksdb#84c5ac0bbd6901b6279a5480708e93eb3da6caa4" dependencies = [ "libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)", @@ -1192,7 +1192,7 @@ dependencies = [ [[package]] name = "rocksdb-sys" version = "0.3.0" -source = "git+https://github.com/ethcore/rust-rocksdb#eadce7f74cfe92b99ce63a77af425b47857239b8" +source = "git+https://github.com/ethcore/rust-rocksdb#84c5ac0bbd6901b6279a5480708e93eb3da6caa4" dependencies = [ "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1621,7 +1621,7 @@ dependencies = [ "checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c" "checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76" "checksum json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)" = "" -"checksum jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "91755680900913f73576065c85359ee793ac3883bc461dbca90fc4a603be84cc" +"checksum jsonrpc-core 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec4477e4e8218da23caa5dd31f4eb39999aa0ea9035660617eccfb19a23bf5ad" "checksum jsonrpc-http-server 6.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" @@ -1653,11 +1653,11 @@ dependencies = [ "checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09" "checksum number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "084d05f4bf60621a9ac9bde941a410df548f4de9545f06e5ee9d3aef4b97cd77" "checksum odds 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "b28c06e81b0f789122d415d6394b5fe849bde8067469f4c2980d3cdc10c78ec1" -"checksum parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "" -"checksum parity-dapps-home 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "" -"checksum parity-dapps-signer 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "" -"checksum parity-dapps-status 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "" -"checksum parity-dapps-wallet 0.6.0 (git+https://github.com/ethcore/parity-ui.git)" = "" +"checksum parity-dapps 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "" +"checksum parity-dapps-home 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "" +"checksum parity-dapps-signer 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "" +"checksum parity-dapps-status 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "" +"checksum parity-dapps-wallet 1.4.0 (git+https://github.com/ethcore/parity-ui.git)" = "" "checksum parking_lot 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0fd1be2c3cf5fef20a6d18fec252c4f3c87c14fc3039002eb7d4ed91e436826" "checksum phf 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "447d9d45f2e0b4a9b532e808365abf18fc211be6ca217202fcd45236ef12f026" "checksum phf_codegen 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8af7ae7c3f75a502292b491e5cc0a1f69e3407744abe6e57e2a3b712bb82f01d" diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 1586677ac..be3b79202 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -10,7 +10,7 @@ build = "build.rs" [dependencies] log = "0.3" -jsonrpc-core = "2.0" +jsonrpc-core = "2.1" jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" } hyper = { default-features = false, git = "https://github.com/ethcore/hyper" } unicase = "1.3" @@ -21,11 +21,11 @@ serde_json = "0.7.0" serde_macros = { version = "0.7.0", optional = true } ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } -parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" } +parity-dapps = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" } # List of apps -parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" } -parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6" } -parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6", optional = true } +parity-dapps-status = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" } +parity-dapps-home = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4" } +parity-dapps-wallet = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true } mime_guess = { version = "1.6.1" } clippy = { version = "0.0.80", optional = true} diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d2477b489..e87e5e450 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -582,23 +582,22 @@ mod tests { fn open_block() { use spec::*; let spec = Spec::new_test(); - let engine = &spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(&*spec.engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); - let _ = b.seal(engine.deref(), vec![]); + let _ = b.seal(&*spec.engine, vec![]); } #[test] fn enact_block() { use spec::*; let spec = Spec::new_test(); - let engine = &spec.engine; + let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_journal_db(); @@ -606,15 +605,15 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); let vm_factory = Default::default(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() - .close_and_lock().seal(engine.deref(), vec![]).unwrap(); + let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() + .close_and_lock().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); - let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap(); + let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap(); assert_eq!(e.rlp_bytes(), orig_bytes); @@ -627,7 +626,7 @@ mod tests { fn enact_block_with_uncle() { use spec::*; let spec = Spec::new_test(); - let engine = &spec.engine; + let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_journal_db(); @@ -635,14 +634,14 @@ mod tests { spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); let vm_factory = Default::default(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let mut open_block = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), 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(); uncle2_header.extra_data = b"uncle2".to_vec(); open_block.push_uncle(uncle1_header).unwrap(); open_block.push_uncle(uncle2_header).unwrap(); - let b = open_block.close_and_lock().seal(engine.deref(), vec![]).unwrap(); + let b = open_block.close_and_lock().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -650,7 +649,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()).unwrap(); - let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap(); + let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &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 a374c0bf6..b5cd6076c 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -133,8 +133,9 @@ enum CacheID { impl bc::group::BloomGroupDatabase for BlockChain { fn blooms_at(&self, position: &bc::group::GroupPosition) -> Option { let position = LogGroupPosition::from(position.clone()); - self.note_used(CacheID::BlocksBlooms(position.clone())); - self.db.read_with_cache(DB_COL_EXTRA, &self.blocks_blooms, &position).map(Into::into) + let result = self.db.read_with_cache(DB_COL_EXTRA, &self.blocks_blooms, &position).map(Into::into); + self.note_used(CacheID::BlocksBlooms(position)); + result } } @@ -211,9 +212,7 @@ impl BlockProvider for BlockChain { let opt = self.db.get(DB_COL_HEADERS, hash) .expect("Low level database error. Some issue with disk?"); - self.note_used(CacheID::BlockHeader(hash.clone())); - - match opt { + let result = match opt { Some(b) => { let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec(); let mut write = self.block_headers.write(); @@ -221,7 +220,10 @@ impl BlockProvider for BlockChain { Some(bytes) }, None => None - } + }; + + self.note_used(CacheID::BlockHeader(hash.clone())); + result } /// Get block body data @@ -246,9 +248,7 @@ impl BlockProvider for BlockChain { let opt = self.db.get(DB_COL_BODIES, hash) .expect("Low level database error. Some issue with disk?"); - self.note_used(CacheID::BlockBody(hash.clone())); - - match opt { + let result = match opt { Some(b) => { let bytes: Bytes = UntrustedRlp::new(&b).decompress(RlpType::Blocks).to_vec(); let mut write = self.block_bodies.write(); @@ -256,31 +256,39 @@ impl BlockProvider for BlockChain { Some(bytes) }, None => None - } + }; + + self.note_used(CacheID::BlockBody(hash.clone())); + + result } /// Get the familial details concerning a block. fn block_details(&self, hash: &H256) -> Option { + let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_details, hash); self.note_used(CacheID::BlockDetails(hash.clone())); - self.db.read_with_cache(DB_COL_EXTRA, &self.block_details, hash) + result } /// Get the hash of given block's number. fn block_hash(&self, index: BlockNumber) -> Option { + let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_hashes, &index); self.note_used(CacheID::BlockHashes(index)); - self.db.read_with_cache(DB_COL_EXTRA, &self.block_hashes, &index) + result } /// Get the address of transaction with given hash. fn transaction_address(&self, hash: &H256) -> Option { + let result = self.db.read_with_cache(DB_COL_EXTRA, &self.transaction_addresses, hash); self.note_used(CacheID::TransactionAddresses(hash.clone())); - self.db.read_with_cache(DB_COL_EXTRA, &self.transaction_addresses, hash) + result } /// Get receipts of block with given hash. fn block_receipts(&self, hash: &H256) -> Option { + let result = self.db.read_with_cache(DB_COL_EXTRA, &self.block_receipts, hash); self.note_used(CacheID::BlockReceipts(hash.clone())); - self.db.read_with_cache(DB_COL_EXTRA, &self.block_receipts, hash) + result } /// Returns numbers of blocks containing given bloom. @@ -635,11 +643,12 @@ impl BlockChain { let mut update = HashMap::new(); update.insert(block_hash, parent_details); - self.note_used(CacheID::BlockDetails(block_hash)); let mut write_details = self.block_details.write(); batch.extend_with_cache(DB_COL_EXTRA, &mut *write_details, update, CacheUpdatePolicy::Overwrite); + self.note_used(CacheID::BlockDetails(block_hash)); + self.db.write(batch).unwrap(); } @@ -730,12 +739,14 @@ impl BlockChain { /// Prepares extras update. fn prepare_update(&self, batch: &DBTransaction, update: ExtrasUpdate, is_best: bool) { { - for hash in update.block_details.keys().cloned() { - self.note_used(CacheID::BlockDetails(hash)); - } + let block_hashes: Vec<_> = update.block_details.keys().cloned().collect(); let mut write_details = self.block_details.write(); batch.extend_with_cache(DB_COL_EXTRA, &mut *write_details, update.block_details, CacheUpdatePolicy::Overwrite); + + for hash in block_hashes.into_iter() { + self.note_used(CacheID::BlockDetails(hash)); + } } { @@ -779,13 +790,6 @@ impl BlockChain { let mut pending_write_hashes = self.pending_block_hashes.write(); let mut pending_write_txs = self.pending_transaction_addresses.write(); - for n in pending_write_hashes.keys() { - self.note_used(CacheID::BlockHashes(*n)); - } - for hash in pending_write_txs.keys() { - self.note_used(CacheID::TransactionAddresses(hash.clone())); - } - let mut best_block = self.best_block.write(); let mut write_hashes = self.block_hashes.write(); let mut write_txs = self.transaction_addresses.write(); @@ -794,8 +798,19 @@ impl BlockChain { *best_block = block; } + let pending_hashes_keys: Vec<_> = pending_write_hashes.keys().cloned().collect(); + let pending_txs_keys: Vec<_> = pending_write_txs.keys().cloned().collect(); + write_hashes.extend(mem::replace(&mut *pending_write_hashes, HashMap::new())); write_txs.extend(mem::replace(&mut *pending_write_txs, HashMap::new())); + + for n in pending_hashes_keys.into_iter() { + self.note_used(CacheID::BlockHashes(n)); + } + + for hash in pending_txs_keys.into_iter() { + self.note_used(CacheID::TransactionAddresses(hash)); + } } /// Iterator that lists `first` and then all of `first`'s ancestors, by hash. @@ -1000,16 +1015,18 @@ impl BlockChain { /// Ticks our cache system and throws out any old data. pub fn collect_garbage(&self) { - let mut cache_man = self.cache_man.write(); - cache_man.collect_garbage(|| self.cache_size().total(), | ids | { - let mut block_headers = self.block_headers.write(); - let mut block_bodies = self.block_bodies.write(); - let mut block_details = self.block_details.write(); - let mut block_hashes = self.block_hashes.write(); - let mut transaction_addresses = self.transaction_addresses.write(); - let mut blocks_blooms = self.blocks_blooms.write(); - let mut block_receipts = self.block_receipts.write(); + let current_size = self.cache_size().total(); + let mut block_headers = self.block_headers.write(); + let mut block_bodies = self.block_bodies.write(); + let mut block_details = self.block_details.write(); + let mut block_hashes = self.block_hashes.write(); + let mut transaction_addresses = self.transaction_addresses.write(); + let mut blocks_blooms = self.blocks_blooms.write(); + let mut block_receipts = self.block_receipts.write(); + + let mut cache_man = self.cache_man.write(); + cache_man.collect_garbage(current_size, | ids | { for id in &ids { match *id { CacheID::BlockHeader(ref h) => { block_headers.remove(h); }, @@ -1021,6 +1038,7 @@ impl BlockChain { CacheID::BlockReceipts(ref h) => { block_receipts.remove(h); } } } + block_headers.shrink_to_fit(); block_bodies.shrink_to_fit(); block_details.shrink_to_fit(); @@ -1028,6 +1046,14 @@ impl BlockChain { transaction_addresses.shrink_to_fit(); blocks_blooms.shrink_to_fit(); block_receipts.shrink_to_fit(); + + block_headers.heap_size_of_children() + + block_bodies.heap_size_of_children() + + block_details.heap_size_of_children() + + block_hashes.heap_size_of_children() + + transaction_addresses.heap_size_of_children() + + blocks_blooms.heap_size_of_children() + + block_receipts.heap_size_of_children() }); } diff --git a/ethcore/src/cache_manager.rs b/ethcore/src/cache_manager.rs index f68e3c616..715f68a57 100644 --- a/ethcore/src/cache_manager.rs +++ b/ethcore/src/cache_manager.rs @@ -45,16 +45,19 @@ impl CacheManager where T: Eq + Hash { } } - pub fn collect_garbage(&mut self, current_size: C, mut notify_unused: F) where C: Fn() -> usize, F: FnMut(HashSet) { - if current_size() < self.pref_cache_size { + /// Collects unused objects from cache. + /// First params is the current size of the cache. + /// Second one is an with objects to remove. It should also return new size of the cache. + pub fn collect_garbage(&mut self, current_size: usize, mut notify_unused: F) where F: FnMut(HashSet) -> usize { + if current_size < self.pref_cache_size { self.rotate_cache_if_needed(); return; } for _ in 0..COLLECTION_QUEUE_SIZE { - notify_unused(self.cache_usage.pop_back().unwrap()); + let current_size = notify_unused(self.cache_usage.pop_back().unwrap()); self.cache_usage.push_front(Default::default()); - if current_size() < self.max_cache_size { + if current_size < self.max_cache_size { break; } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 0b51dacd3..bf9c86633 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -800,8 +800,8 @@ impl BlockChainClient for Client { Self::block_hash(&self.chain, id) } - fn code(&self, address: &Address) -> Option { - self.state().code(address) + fn code(&self, address: &Address, id: BlockID) -> Option> { + self.state_at(id).map(|s| s.code(address)) } fn balance(&self, address: &Address, id: BlockID) -> Option { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 113974dee..b4e0d8a90 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -258,7 +258,7 @@ pub fn get_temp_journal_db() -> GuardedTempResult> { impl MiningBlockChainClient for TestBlockChainClient { fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { - let engine = &self.spec.engine; + let engine = &*self.spec.engine; let genesis_header = self.spec.genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); @@ -266,7 +266,7 @@ impl MiningBlockChainClient for TestBlockChainClient { let last_hashes = vec![genesis_header.hash()]; let mut open_block = OpenBlock::new( - engine.deref(), + engine, self.vm_factory(), Default::default(), false, @@ -319,8 +319,11 @@ impl BlockChainClient for TestBlockChainClient { self.nonce(address, BlockID::Latest).unwrap() } - fn code(&self, address: &Address) -> Option { - self.code.read().get(address).cloned() + fn code(&self, address: &Address, id: BlockID) -> Option> { + match id { + BlockID::Latest => Some(self.code.read().get(address).cloned()), + _ => None, + } } fn balance(&self, address: &Address, id: BlockID) -> Option { @@ -479,9 +482,9 @@ impl BlockChainClient for TestBlockChainClient { if number == len { { let mut difficulty = self.difficulty.write(); - *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; + *difficulty = *difficulty + header.difficulty; } - mem::replace(self.last_hash.write().deref_mut(), h.clone()); + mem::replace(&mut *self.last_hash.write(), h.clone()); self.blocks.write().insert(h.clone(), b); self.numbers.write().insert(number, h.clone()); let mut parent_hash = header.parent_hash; diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index ca4b8e6b1..f91747e7b 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -81,8 +81,14 @@ pub trait BlockChainClient : Sync + Send { /// Get block hash. fn block_hash(&self, id: BlockID) -> Option; - /// Get address code. - fn code(&self, address: &Address) -> Option; + /// Get address code at given block's state. + fn code(&self, address: &Address, id: BlockID) -> Option>; + + /// Get address code at the latest block's state. + fn latest_code(&self, address: &Address) -> Option { + self.code(address, BlockID::Latest) + .expect("code will return Some if given BlockID::Latest; qed") + } /// Get address balance at the given block's state. /// diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 2545340f1..6bdacd22d 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -246,16 +246,16 @@ mod tests { tap.unlock_account_permanently(addr, "".into()).unwrap(); let spec = new_test_authority(); - let engine = &spec.engine; + let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, 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()); + assert!(b.try_seal(engine, seal).is_ok()); } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 85d699241..c924257bb 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -80,18 +80,18 @@ mod tests { let addr = tap.insert_account("".sha3(), "").unwrap(); let spec = new_test_instant(); - let engine = &spec.engine; + let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); // Seal with empty AccountProvider. let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); - assert!(b.try_seal(engine.deref(), seal).is_ok()); + assert!(b.try_seal(engine, seal).is_ok()); } #[test] diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 477aa2129..8b137cf69 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -350,14 +350,14 @@ mod tests { #[test] fn on_close_block() { let spec = new_morden(); - let engine = &spec.engine; + let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let vm_factory = Default::default(); - let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); } @@ -365,14 +365,14 @@ mod tests { #[test] fn on_close_block_with_uncle() { let spec = new_morden(); - let engine = &spec.engine; + let engine = &*spec.engine; let genesis_header = spec.genesis_header(); let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); spec.ensure_db_good(db.as_hashdb_mut()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); let vm_factory = Default::default(); - let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); + let mut b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, 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/json_tests/state.rs b/ethcore/src/json_tests/state.rs index 4252c9f30..97f9f70f0 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -65,7 +65,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { state.commit() .expect(&format!("State test {} failed due to internal error.", name)); let vm_factory = Default::default(); - let res = state.apply(&env, engine.deref(), &vm_factory, &transaction, false); + let res = state.apply(&env, &*engine, &vm_factory, &transaction, false); if fail_unless(state.root() == &post_state_root) { println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 875abb804..6879ff551 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -26,6 +26,8 @@ #![cfg_attr(feature="dev", allow(match_bool))] // Keeps consistency (all lines with `.clone()`). #![cfg_attr(feature="dev", allow(clone_on_copy))] +// Complains on Box when implementing From> +#![cfg_attr(feature="dev", allow(boxed_local))] // TODO [todr] a lot of warnings to be fixed #![cfg_attr(feature="dev", allow(assign_op_pattern))] diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 51f424de8..f4bc39416 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -290,8 +290,8 @@ impl Miner { for tx in transactions { let hash = tx.hash(); match open_block.push_transaction(tx, None) { - Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, .. })) => { - debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?}", hash); + Err(Error::Execution(ExecutionError::BlockGasLimitReached { gas_limit, gas_used, gas })) => { + debug!(target: "miner", "Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?})", hash, gas_limit, gas_used, gas); // Exit early if gas left is smaller then min_tx_gas let min_tx_gas: U256 = 21000.into(); // TODO: figure this out properly. if gas_limit - gas_used < min_tx_gas { @@ -300,8 +300,8 @@ impl Miner { }, // Invalid nonce error can happen only if previous transaction is skipped because of gas limit. // If there is errornous state of transaction queue it will be fixed when next block is imported. - Err(Error::Execution(ExecutionError::InvalidNonce { .. })) => { - debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?}", hash); + Err(Error::Execution(ExecutionError::InvalidNonce { expected, got })) => { + debug!(target: "miner", "Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?})", hash, expected, got); }, // already have transaction - ignore Err(Error::Transaction(TransactionError::AlreadyImported)) => {}, @@ -527,7 +527,7 @@ impl MinerService for Miner { fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option { let sealing_work = self.sealing_work.lock(); - sealing_work.queue.peek_last_ref().map_or_else(|| chain.code(address), |b| b.block().fields().state.code(address)) + sealing_work.queue.peek_last_ref().map_or_else(|| chain.latest_code(address), |b| b.block().fields().state.code(address)) } fn set_author(&self, author: Address) { diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index a1b56aaca..1d688bafa 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -1467,7 +1467,7 @@ mod test { let keypair = KeyPair::create().unwrap(); let tx = new_unsigned_tx(U256::from(123)).sign(keypair.secret()); let tx2 = { - let mut tx2 = tx.deref().clone(); + let mut tx2 = (*tx).clone(); tx2.gas_price = U256::from(200); tx2.sign(keypair.secret()) }; @@ -1490,12 +1490,12 @@ mod test { let keypair = KeyPair::create().unwrap(); let tx0 = new_unsigned_tx(U256::from(123)).sign(keypair.secret()); let tx1 = { - let mut tx1 = tx0.deref().clone(); + let mut tx1 = (*tx0).clone(); tx1.nonce = U256::from(124); tx1.sign(keypair.secret()) }; let tx2 = { - let mut tx2 = tx1.deref().clone(); + let mut tx2 = (*tx1).clone(); tx2.gas_price = U256::from(200); tx2.sign(keypair.secret()) }; diff --git a/ethcore/src/snapshot/error.rs b/ethcore/src/snapshot/error.rs index be4ed39d2..d41d7cd2f 100644 --- a/ethcore/src/snapshot/error.rs +++ b/ethcore/src/snapshot/error.rs @@ -64,9 +64,9 @@ impl From<::std::io::Error> for Error { } } -impl From> for Error { - fn from(err: Box) -> Self { - Error::Trie(*err) +impl From for Error { + fn from(err: TrieError) -> Self { + Error::Trie(err) } } @@ -74,4 +74,10 @@ impl From for Error { fn from(err: DecoderError) -> Self { Error::Decoder(err) } -} \ No newline at end of file +} + +impl From> for Error where Error: From { + fn from(err: Box) -> Self { + Error::from(*err) + } +} diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 9dbbf1d9a..3be35d8d8 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -61,7 +61,7 @@ const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024; const SNAPSHOT_BLOCKS: u64 = 30000; /// A progress indicator for snapshots. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Progress { accounts: AtomicUsize, blocks: AtomicUsize, @@ -70,16 +70,6 @@ pub struct Progress { } impl Progress { - /// Create a new progress indicator. - pub fn new() -> Self { - Progress { - accounts: AtomicUsize::new(0), - blocks: AtomicUsize::new(0), - size: AtomicUsize::new(0), - done: AtomicBool::new(false), - } - } - /// Get the number of accounts snapshotted thus far. pub fn accounts(&self) -> usize { self.accounts.load(Ordering::Relaxed) } @@ -510,12 +500,12 @@ fn rebuild_account_trie(db: &mut HashDB, account_chunk: &[&[u8]], out_chunk: &mu Ok(()) } -/// Proportion of blocks which we will verify PoW for. +/// Proportion of blocks which we will verify `PoW` for. const POW_VERIFY_RATE: f32 = 0.02; /// Rebuilds the blockchain from chunks. /// -/// Does basic verification for all blocks, but PoW verification for some. +/// Does basic verification for all blocks, but `PoW` verification for some. /// Blocks must be fed in-order. /// /// The first block in every chunk is disconnected from the last block in the diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index dafce75cf..c3aa57faa 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -101,7 +101,7 @@ impl Restoration { fn new(manifest: &ManifestData, pruning: Algorithm, path: &Path, gb: &[u8]) -> Result { let cfg = DatabaseConfig::with_columns(::client::DB_NO_OF_COLUMNS); let raw_db = Arc::new(try!(Database::open(&cfg, &*path.to_string_lossy()) - .map_err(|s| UtilError::SimpleString(s)))); + .map_err(UtilError::SimpleString))); let chain = BlockChain::new(Default::default(), gb, raw_db.clone()); let blocks = try!(BlockRebuilder::new(chain, manifest.block_number)); @@ -207,23 +207,17 @@ impl Service { }; // create the snapshot dir if it doesn't exist. - match fs::create_dir_all(service.snapshot_dir()) { - Err(e) => { - if e.kind() != ErrorKind::AlreadyExists { - return Err(e.into()) - } + if let Err(e) = fs::create_dir_all(service.snapshot_dir()) { + if e.kind() != ErrorKind::AlreadyExists { + return Err(e.into()) } - _ => {} } // delete the temporary restoration dir if it does exist. - match fs::remove_dir_all(service.restoration_dir()) { - Err(e) => { - if e.kind() != ErrorKind::NotFound { - return Err(e.into()) - } + if let Err(e) = fs::remove_dir_all(service.restoration_dir()) { + if e.kind() != ErrorKind::NotFound { + return Err(e.into()) } - _ => {} } Ok(service) @@ -434,4 +428,4 @@ impl SnapshotService for Service { self.io_channel.send(ClientIoMessage::FeedBlockChunk(hash, chunk)) .expect("snapshot service and io service are kept alive by client service; qed"); } -} \ No newline at end of file +} diff --git a/ethcore/src/snapshot/tests/blocks.rs b/ethcore/src/snapshot/tests/blocks.rs index 97fa08e54..7c88d9e83 100644 --- a/ethcore/src/snapshot/tests/blocks.rs +++ b/ethcore/src/snapshot/tests/blocks.rs @@ -55,7 +55,7 @@ fn chunk_and_restore(amount: u64) { // snapshot it. let writer = Mutex::new(PackedWriter::new(&snapshot_path).unwrap()); - let block_hashes = chunk_blocks(&bc, (amount, best_hash), &writer, &Progress::new()).unwrap(); + let block_hashes = chunk_blocks(&bc, (amount, best_hash), &writer, &Progress::default()).unwrap(); writer.into_inner().finish(::snapshot::ManifestData { state_hashes: Vec::new(), block_hashes: block_hashes, @@ -88,4 +88,4 @@ fn chunk_and_restore(amount: u64) { fn chunk_and_restore_500() { chunk_and_restore(500) } #[test] -fn chunk_and_restore_40k() { chunk_and_restore(40000) } \ No newline at end of file +fn chunk_and_restore_40k() { chunk_and_restore(40000) } diff --git a/ethcore/src/snapshot/tests/helpers.rs b/ethcore/src/snapshot/tests/helpers.rs index 20fd4ae03..aa0fc3ae5 100644 --- a/ethcore/src/snapshot/tests/helpers.rs +++ b/ethcore/src/snapshot/tests/helpers.rs @@ -116,7 +116,7 @@ pub fn fill_storage(mut db: AccountDBMut, root: &mut H256, seed: &mut H256) { pub fn compare_dbs(one: &HashDB, two: &HashDB) { let keys = one.keys(); - for (key, _) in keys { + for key in keys.keys() { assert_eq!(one.get(&key).unwrap(), two.get(&key).unwrap()); } -} \ No newline at end of file +} diff --git a/ethcore/src/snapshot/tests/state.rs b/ethcore/src/snapshot/tests/state.rs index 9d87899db..c5d60cb03 100644 --- a/ethcore/src/snapshot/tests/state.rs +++ b/ethcore/src/snapshot/tests/state.rs @@ -48,7 +48,7 @@ fn snap_and_restore() { let state_root = producer.state_root(); let writer = Mutex::new(PackedWriter::new(&snap_file).unwrap()); - let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::new()).unwrap(); + let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default()).unwrap(); writer.into_inner().finish(::snapshot::ManifestData { state_hashes: state_hashes, @@ -79,4 +79,4 @@ fn snap_and_restore() { let new_db = journaldb::new(db, Algorithm::Archive, ::client::DB_COL_STATE); compare_dbs(&old_db, new_db.as_hashdb()); -} \ No newline at end of file +} diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 1dea50442..03dbcb596 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -347,7 +347,7 @@ impl State { let have_key = self.cache.borrow().contains_key(a); if !have_key { let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); - let maybe_acc = match db.get(&a) { + let maybe_acc = match db.get(a) { Ok(acc) => acc.map(Account::from_rlp), Err(e) => panic!("Potential DB corruption encountered: {}", e), }; @@ -375,7 +375,7 @@ impl State { let contains_key = self.cache.borrow().contains_key(a); if !contains_key { let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); - let maybe_acc = match db.get(&a) { + let maybe_acc = match db.get(a) { Ok(acc) => acc.map(Account::from_rlp), Err(e) => panic!("Potential DB corruption encountered: {}", e), }; @@ -630,7 +630,7 @@ fn should_trace_call_transaction_to_builtin() { let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); - let engine = Spec::new_test().engine; + let engine = &*Spec::new_test().engine; let t = Transaction { nonce: 0.into(), @@ -642,7 +642,7 @@ fn should_trace_call_transaction_to_builtin() { }.sign(&"".sha3()); let vm_factory = Default::default(); - let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); + let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { trace_address: Default::default(), @@ -673,7 +673,7 @@ fn should_not_trace_subcall_transaction_to_builtin() { let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); - let engine = Spec::new_test().engine; + let engine = &*Spec::new_test().engine; let t = Transaction { nonce: 0.into(), @@ -686,7 +686,7 @@ fn should_not_trace_subcall_transaction_to_builtin() { state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); let vm_factory = Default::default(); - let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); + let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { trace_address: Default::default(), @@ -717,7 +717,7 @@ fn should_not_trace_callcode() { let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); - let engine = Spec::new_test().engine; + let engine = &*Spec::new_test().engine; let t = Transaction { nonce: 0.into(), @@ -731,7 +731,7 @@ fn should_not_trace_callcode() { state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); let vm_factory = Default::default(); - let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); + let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { trace_address: Default::default(), @@ -778,7 +778,7 @@ fn should_not_trace_delegatecall() { let mut info = EnvInfo::default(); info.gas_limit = 1_000_000.into(); info.number = 0x789b0; - let engine = Spec::new_test().engine; + let engine = &*Spec::new_test().engine; println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); @@ -794,7 +794,7 @@ fn should_not_trace_delegatecall() { state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); let vm_factory = Default::default(); - let result = state.apply(&info, engine.deref(), &vm_factory, &t, true).unwrap(); + let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap(); let expected_trace = vec![FlatTrace { trace_address: Default::default(), @@ -1489,4 +1489,4 @@ fn create_empty() { assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); } -} \ No newline at end of file +} diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 4dc4f953d..87250d2af 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -134,7 +134,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe let test_spec = get_test_spec(); let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected()).unwrap(); - let test_engine = &test_spec.engine; + let test_engine = &*test_spec.engine; let mut db_result = get_temp_journal_db(); let mut db = db_result.take(); @@ -155,7 +155,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe // forge block. let mut b = OpenBlock::new( - test_engine.deref(), + test_engine, &vm_factory, Default::default(), false, @@ -183,7 +183,7 @@ pub fn generate_dummy_client_with_spec_and_data(get_test_spec: F, block_numbe n += 1; } - let b = b.close_and_lock().seal(test_engine.deref(), vec![]).unwrap(); + let b = b.close_and_lock().seal(test_engine, vec![]).unwrap(); if let Err(e) = client.import_block(b.rlp_bytes()) { panic!("error importing block which is valid by definition: {:?}", e); diff --git a/ethcore/src/trace/db.rs b/ethcore/src/trace/db.rs index b03380829..cd34e73c2 100644 --- a/ethcore/src/trace/db.rs +++ b/ethcore/src/trace/db.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Trace database. -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::collections::HashMap; use std::sync::Arc; use bloomchain::{Number, Config as BloomConfig}; @@ -119,8 +119,9 @@ pub struct TraceDB where T: DatabaseExtras { impl BloomGroupDatabase for TraceDB where T: DatabaseExtras { fn blooms_at(&self, position: &GroupPosition) -> Option { let position = TraceGroupPosition::from(position.clone()); - self.note_used(CacheID::Bloom(position.clone())); - self.tracesdb.read_with_cache(DB_COL_TRACE, &self.blooms, &position).map(Into::into) + let result = self.tracesdb.read_with_cache(DB_COL_TRACE, &self.blooms, &position).map(Into::into); + self.note_used(CacheID::Bloom(position)); + result } } @@ -174,11 +175,13 @@ impl TraceDB where T: DatabaseExtras { /// Ticks our cache system and throws out any old data. pub fn collect_garbage(&self) { - let mut cache_manager = self.cache_manager.write(); - cache_manager.collect_garbage(|| self.cache_size(), | ids | { - let mut traces = self.traces.write(); - let mut blooms = self.blooms.write(); + let current_size = self.cache_size(); + let mut traces = self.traces.write(); + let mut blooms = self.blooms.write(); + let mut cache_manager = self.cache_manager.write(); + + cache_manager.collect_garbage(current_size, | ids | { for id in &ids { match *id { CacheID::Trace(ref h) => { traces.remove(h); }, @@ -187,13 +190,16 @@ impl TraceDB where T: DatabaseExtras { } traces.shrink_to_fit(); blooms.shrink_to_fit(); + + traces.heap_size_of_children() + blooms.heap_size_of_children() }); } /// Returns traces for block with hash. fn traces(&self, block_hash: &H256) -> Option { + let result = self.tracesdb.read_with_cache(DB_COL_TRACE, &self.traces, block_hash); self.note_used(CacheID::Trace(block_hash.clone())); - self.tracesdb.read_with_cache(DB_COL_TRACE, &self.traces, block_hash) + result } /// Returns vector of transaction traces for given block. @@ -264,12 +270,12 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { // at first, let's insert new block traces { - // note_used must be called before locking traces to avoid cache/traces deadlock on garbage collection - self.note_used(CacheID::Trace(request.block_hash.clone())); let mut traces = self.traces.write(); // it's important to use overwrite here, // cause this value might be queried by hash later - batch.write_with_cache(DB_COL_TRACE, traces.deref_mut(), request.block_hash, request.traces, CacheUpdatePolicy::Overwrite); + batch.write_with_cache(DB_COL_TRACE, &mut *traces, request.block_hash, request.traces, CacheUpdatePolicy::Overwrite); + // note_used must be called after locking traces to avoid cache/traces deadlock on garbage collection + self.note_used(CacheID::Trace(request.block_hash.clone())); } // now let's rebuild the blooms @@ -294,12 +300,13 @@ impl TraceDatabase for TraceDB where T: DatabaseExtras { .map(|p| (From::from(p.0), From::from(p.1))) .collect::>(); - // note_used must be called before locking blooms to avoid cache/traces deadlock on garbage collection - for key in blooms_to_insert.keys() { - self.note_used(CacheID::Bloom(key.clone())); - } + let blooms_keys: Vec<_> = blooms_to_insert.keys().cloned().collect(); let mut blooms = self.blooms.write(); - batch.extend_with_cache(DB_COL_TRACE, blooms.deref_mut(), blooms_to_insert, CacheUpdatePolicy::Remove); + batch.extend_with_cache(DB_COL_TRACE, &mut *blooms, blooms_to_insert, CacheUpdatePolicy::Remove); + // note_used must be called after locking blooms to avoid cache/traces deadlock on garbage collection + for key in blooms_keys.into_iter() { + self.note_used(CacheID::Bloom(key)); + } } } diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 851a702a9..078bb72ae 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -344,7 +344,7 @@ mod tests { // Test against morden let mut good = Header::new(); let spec = Spec::new_test(); - let engine = &spec.engine; + let engine = &*spec.engine; let min_gas_limit = engine.params().min_gas_limit; good.gas_limit = min_gas_limit; @@ -425,69 +425,69 @@ mod tests { bc.insert(create_test_block(&parent7)); bc.insert(create_test_block(&parent8)); - check_ok(basic_test(&create_test_block(&good), engine.deref())); + check_ok(basic_test(&create_test_block(&good), engine)); let mut header = good.clone(); header.transactions_root = good_transactions_root.clone(); header.uncles_hash = good_uncles_hash.clone(); - check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref())); + check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine)); header.gas_limit = min_gas_limit - From::from(1); - check_fail(basic_test(&create_test_block(&header), engine.deref()), + check_fail(basic_test(&create_test_block(&header), engine), InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit })); header = good.clone(); header.number = BlockNumber::max_value(); - check_fail(basic_test(&create_test_block(&header), engine.deref()), + check_fail(basic_test(&create_test_block(&header), engine), RidiculousNumber(OutOfBounds { max: Some(BlockNumber::max_value()), min: None, found: header.number })); header = good.clone(); header.gas_used = header.gas_limit + From::from(1); - check_fail(basic_test(&create_test_block(&header), engine.deref()), + check_fail(basic_test(&create_test_block(&header), engine), TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit), min: None, found: header.gas_used })); header = good.clone(); header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8); - check_fail(basic_test(&create_test_block(&header), engine.deref()), + check_fail(basic_test(&create_test_block(&header), engine), ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() })); header = good.clone(); header.extra_data.resize(engine.maximum_extra_data_size() + 1, 0u8); - check_fail(basic_test(&create_test_block(&header), engine.deref()), + check_fail(basic_test(&create_test_block(&header), engine), ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data.len() })); header = good.clone(); header.uncles_hash = good_uncles_hash.clone(); - check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()), + check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine), InvalidTransactionsRoot(Mismatch { expected: good_transactions_root.clone(), found: header.transactions_root })); header = good.clone(); header.transactions_root = good_transactions_root.clone(); - check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref()), + check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine), InvalidUnclesHash(Mismatch { expected: good_uncles_hash.clone(), found: header.uncles_hash })); - check_ok(family_test(&create_test_block(&good), engine.deref(), &bc)); - check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine.deref(), &bc)); + check_ok(family_test(&create_test_block(&good), engine, &bc)); + check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine, &bc)); header = good.clone(); header.parent_hash = H256::random(); - check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc), + check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), UnknownParent(header.parent_hash)); header = good.clone(); header.timestamp = 10; - check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc), + check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp + 1), found: header.timestamp })); header = good.clone(); header.number = 9; - check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine.deref(), &bc), + check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), InvalidNumber(Mismatch { expected: parent.number + 1, found: header.number })); header = good.clone(); let mut bad_uncles = good_uncles.clone(); bad_uncles.push(good_uncle1.clone()); - check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine.deref(), &bc), + check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc), TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() })); // TODO: some additional uncle checks diff --git a/ethkey/src/signature.rs b/ethkey/src/signature.rs index 616db7bc9..407903a84 100644 --- a/ethkey/src/signature.rs +++ b/ethkey/src/signature.rs @@ -136,7 +136,7 @@ pub fn verify_public(public: &Public, signature: &Signature, message: &Message) let pdata: [u8; 65] = { let mut temp = [4u8; 65]; - temp[1..65].copy_from_slice(public.deref()); + temp[1..65].copy_from_slice(&**public); temp }; diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index ec80c9537..3b3dcf2ee 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::ops::{Deref, DerefMut}; use ethkey::{KeyPair, sign, Address, Secret, Signature, Message}; use {json, Error, crypto}; use crypto::Keccak256; @@ -87,7 +86,7 @@ impl Crypto { let mut ciphertext = [0u8; 32]; // aes-128-ctr with initial vector of iv - crypto::aes::encrypt(&derived_left_bits, &iv, secret.deref(), &mut ciphertext); + crypto::aes::encrypt(&derived_left_bits, &iv, &**secret, &mut ciphertext); // KECCAK(DK[16..31] ++ ), where DK[16..31] - derived_right_bits let mac = crypto::derive_mac(&derived_right_bits, &ciphertext).keccak256(); @@ -123,7 +122,7 @@ impl Crypto { match self.cipher { Cipher::Aes128Ctr(ref params) => { - crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, secret.deref_mut()) + crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut *secret) }, } diff --git a/ethstore/src/bin/ethstore.rs b/ethstore/src/bin/ethstore.rs index 748480069..d3e18c0e5 100644 --- a/ethstore/src/bin/ethstore.rs +++ b/ethstore/src/bin/ethstore.rs @@ -143,7 +143,7 @@ fn execute(command: I) -> Result where I: IntoIterator Result<(), i32> { use std::ffi; @@ -62,7 +64,14 @@ impl DiskDirectory { .flat_map(Result::ok) .filter(|entry| { let metadata = entry.metadata(); - metadata.is_ok() && !metadata.unwrap().is_dir() + let file_name = entry.file_name(); + let name = file_name.to_str().unwrap(); + // filter directories + metadata.is_ok() && !metadata.unwrap().is_dir() && + // hidden files + !name.starts_with(".") && + // other ignored files + !IGNORED_FILES.contains(&name) }) .map(|entry| entry.path()) .collect::>(); diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 4759217b0..58c2d22de 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -27,8 +27,8 @@ use std::sync::*; use nanomsg::{Socket, Protocol, Error, Endpoint, PollRequest, PollFd, PollInOut}; use std::ops::Deref; -const POLL_TIMEOUT: isize = 100; -const CLIENT_CONNECTION_TIMEOUT: isize = 2500; +const POLL_TIMEOUT: isize = 200; +const CLIENT_CONNECTION_TIMEOUT: isize = 15000; /// Generic worker to handle service (binded) sockets pub struct Worker where S: IpcInterface { @@ -68,7 +68,6 @@ pub fn init_duplex_client(socket_addr: &str) -> Result, Sock SocketError::DuplexLink })); - // 2500 ms default timeout socket.set_receive_timeout(CLIENT_CONNECTION_TIMEOUT).unwrap(); let endpoint = try!(socket.connect(socket_addr).map_err(|e| { @@ -91,7 +90,6 @@ pub fn init_client(socket_addr: &str) -> Result, SocketError SocketError::RequestLink })); - // 2500 ms default timeout socket.set_receive_timeout(CLIENT_CONNECTION_TIMEOUT).unwrap(); let endpoint = try!(socket.connect(socket_addr).map_err(|e| { diff --git a/parity/configuration.rs b/parity/configuration.rs index 17a0bef29..ef846ca80 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -501,8 +501,6 @@ impl Configuration { NetworkSettings { name: self.args.flag_identity.clone(), chain: self.chain(), - max_peers: self.max_peers(), - min_peers: self.min_peers(), network_port: self.args.flag_port, rpc_enabled: !self.args.flag_jsonrpc_off && !self.args.flag_no_jsonrpc, rpc_interface: self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()), @@ -511,6 +509,8 @@ impl Configuration { } fn directories(&self) -> Directories { + use util::path; + let db_path = replace_home(self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path)); let keys_path = replace_home( @@ -524,6 +524,12 @@ impl Configuration { let dapps_path = replace_home(&self.args.flag_dapps_path); let signer_path = replace_home(&self.args.flag_signer_path); + if self.args.flag_geth { + let geth_path = path::ethereum::default(); + ::std::fs::create_dir_all(geth_path.as_path()).unwrap_or_else( + |e| warn!("Failed to create '{}' for geth mode: {}", &geth_path.to_str().unwrap(), e)); + } + Directories { keys: keys_path, db: db_path, @@ -771,8 +777,6 @@ mod tests { assert_eq!(conf.network_settings(), NetworkSettings { name: "testname".to_owned(), chain: "morden".to_owned(), - max_peers: 50, - min_peers: 25, network_port: 30303, rpc_enabled: true, rpc_interface: "local".to_owned(), diff --git a/parity/informant.rs b/parity/informant.rs index fed1c46d1..b6e8b7a84 100644 --- a/parity/informant.rs +++ b/parity/informant.rs @@ -21,7 +21,6 @@ use self::ansi_term::Style; use std::sync::{Arc}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use std::time::{Instant, Duration}; -use std::ops::{Deref, DerefMut}; use isatty::{stdout_isatty}; use ethsync::{SyncProvider, ManageNetwork}; use util::{Uint, RwLock, Mutex, H256, Colour}; @@ -112,7 +111,7 @@ impl Informant { paint(White.bold(), format!("{:>8}", format!("#{}", chain_info.best_block_number))), paint(White.bold(), format!("{}", chain_info.best_block_hash)), { - let last_report = match write_report.deref() { &Some(ref last_report) => last_report.clone(), _ => ClientReport::default() }; + let last_report = match *write_report { Some(ref last_report) => last_report.clone(), _ => ClientReport::default() }; format!("{} blk/s {} tx/s {} Mgas/s", paint(Yellow.bold(), format!("{:4}", ((report.blocks_imported - last_report.blocks_imported) * 1000) as u64 / elapsed.as_milliseconds())), paint(Yellow.bold(), format!("{:4}", ((report.transactions_applied - last_report.transactions_applied) * 1000) as u64 / elapsed.as_milliseconds())), @@ -132,7 +131,7 @@ impl Informant { }, paint(Cyan.bold(), format!("{:2}", sync_info.num_active_peers)), paint(Cyan.bold(), format!("{:2}", sync_info.num_peers)), - paint(Cyan.bold(), format!("{:2}", if sync_info.num_peers as u32 > net_config.min_peers { net_config.max_peers} else { net_config.min_peers} )) + paint(Cyan.bold(), format!("{:2}", sync_info.current_max_peers(net_config.min_peers, net_config.max_peers))), ), _ => String::new(), }, @@ -147,9 +146,9 @@ impl Informant { ) ); - *self.chain_info.write().deref_mut() = Some(chain_info); - *self.cache_info.write().deref_mut() = Some(cache_info); - *write_report.deref_mut() = Some(report); + *self.chain_info.write() = Some(chain_info); + *self.cache_info.write() = Some(cache_info); + *write_report = Some(report); } } diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index a4b855e08..624c6b3f4 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -186,7 +186,7 @@ pub fn setup_rpc(server: T, deps: Arc, apis: ApiSet }, Api::Ethcore => { let queue = deps.signer_port.map(|_| deps.signer_queue.clone()); - server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone(), queue).to_delegate()) + server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, &deps.sync, &deps.net_service, deps.logger.clone(), deps.settings.clone(), queue).to_delegate()) }, Api::EthcoreSet => { server.add_delegate(EthcoreSetClient::new(&deps.client, &deps.miner, &deps.net_service).to_delegate()) diff --git a/parity/run.rs b/parity/run.rs index 7d8ef1ac7..c659d4d25 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -30,8 +30,6 @@ use ethcore::account_provider::AccountProvider; use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions}; use ethsync::SyncConfig; use informant::Informant; -#[cfg(feature="ipc")] -use ethcore::client::ChainNotify; use rpc::{HttpServer, IpcServer, HttpConfiguration, IpcConfiguration}; use signer::SignerServer; @@ -82,9 +80,6 @@ pub struct RunCmd { } pub fn execute(cmd: RunCmd) -> Result<(), String> { - // create supervisor - let mut hypervisor = modules::hypervisor(); - // increase max number of open files raise_fd_limit(); @@ -167,6 +162,9 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> { net_conf.boot_nodes = spec.nodes.clone(); } + // create supervisor + let mut hypervisor = modules::hypervisor(); + // create client service. let service = try!(ClientService::start( client_config, diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 70abf8fc1..2a3c12567 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -109,7 +109,7 @@ impl SnapshotCommand { warn!("Snapshot restoration is experimental and the format may be subject to change."); let snapshot = service.snapshot_service(); - let reader = PackedReader::new(&Path::new(&file)) + let reader = PackedReader::new(Path::new(&file)) .map_err(|e| format!("Couldn't open snapshot file: {}", e)) .and_then(|x| x.ok_or("Snapshot file has invalid format.".into())); @@ -172,7 +172,7 @@ impl SnapshotCommand { pub fn take_snapshot(self) -> Result<(), String> { let file_path = try!(self.file_path.clone().ok_or("No file path provided.".to_owned())); let file_path: PathBuf = file_path.into(); - let block_at = self.block_at.clone(); + let block_at = self.block_at; let (service, _panic_handler) = try!(self.start_service()); warn!("Snapshots are currently experimental. File formats may be subject to change."); @@ -180,7 +180,7 @@ impl SnapshotCommand { let writer = try!(PackedWriter::new(&file_path) .map_err(|e| format!("Failed to open snapshot writer: {}", e))); - let progress = Arc::new(Progress::new()); + let progress = Arc::new(Progress::default()); let p = progress.clone(); let informant_handle = ::std::thread::spawn(move || { ::std::thread::sleep(Duration::from_secs(5)); @@ -221,4 +221,4 @@ pub fn execute(cmd: SnapshotCommand) -> Result { } Ok(String::new()) -} \ No newline at end of file +} diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b02241046..441ea723c 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -12,7 +12,7 @@ build = "build.rs" log = "0.3" serde = "0.7.0" serde_json = "0.7.0" -jsonrpc-core = "2.0" +jsonrpc-core = "2.1" jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" } ethcore-io = { path = "../util/io" } ethcore-util = { path = "../util" } diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs new file mode 100644 index 000000000..f709e59ab --- /dev/null +++ b/rpc/src/v1/helpers/dispatch.rs @@ -0,0 +1,96 @@ +// 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 util::numbers::*; +use util::rlp::encode; +use util::bytes::ToPretty; +use ethcore::miner::MinerService; +use ethcore::client::MiningBlockChainClient; +use ethcore::transaction::{Action, SignedTransaction, Transaction}; +use ethcore::account_provider::AccountProvider; +use jsonrpc_core::{Error, Value, to_value}; +use v1::helpers::TransactionRequest; +use v1::types::{H256 as RpcH256, H520 as RpcH520}; +use v1::helpers::errors; + +fn prepare_transaction(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService { + Transaction { + nonce: request.nonce + .or_else(|| miner + .last_nonce(&request.from) + .map(|nonce| nonce + U256::one())) + .unwrap_or_else(|| client.latest_nonce(&request.from)), + + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()), + gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |b| b.to_vec()), + } +} + +pub fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result + where C: MiningBlockChainClient, M: MinerService { + let hash = RpcH256::from(signed_transaction.hash()); + + let import = miner.import_own_transaction(client, signed_transaction); + + import + .map_err(errors::from_transaction_error) + .and_then(|_| to_value(&hash)) +} + +pub fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result { + accounts.sign_with_password(address, pass, hash) + .map_err(errors::from_password_error) + .and_then(|hash| to_value(&RpcH520::from(hash))) +} + +pub fn unlock_sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result + where C: MiningBlockChainClient, M: MinerService { + + let address = request.from; + let signed_transaction = { + let t = prepare_transaction(client, miner, request); + let hash = t.hash(); + let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(errors::from_password_error)); + t.with_signature(signature) + }; + + trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); + dispatch_transaction(&*client, &*miner, signed_transaction) +} + +pub fn sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result + where C: MiningBlockChainClient, M: MinerService { + + let signed_transaction = { + let t = prepare_transaction(client, miner, request); + let hash = t.hash(); + let signature = try!(account_provider.sign(address, hash).map_err(errors::from_signing_error)); + t.with_signature(signature) + }; + + trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); + dispatch_transaction(&*client, &*miner, signed_transaction) +} + +pub fn default_gas_price(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService { + client + .gas_price_statistics(100, 8) + .map(|x| x[4]) + .unwrap_or_else(|_| miner.sensible_gas_price()) +} diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs new file mode 100644 index 000000000..bb62a80e5 --- /dev/null +++ b/rpc/src/v1/helpers/errors.rs @@ -0,0 +1,188 @@ +// 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 . + +//! RPC Error codes and error objects + +macro_rules! rpc_unimplemented { + () => (Err(::v1::helpers::errors::unimplemented())) +} + +use std::fmt; +use ethcore::error::Error as EthcoreError; +use ethcore::account_provider::{Error as AccountError}; +use jsonrpc_core::{Error, ErrorCode, Value}; + +mod codes { + // NOTE [ToDr] Codes from [-32099, -32000] + pub const UNSUPPORTED_REQUEST: i64 = -32000; + pub const NO_WORK: i64 = -32001; + pub const NO_AUTHOR: i64 = -32002; + pub const UNKNOWN_ERROR: i64 = -32009; + pub const TRANSACTION_ERROR: i64 = -32010; + pub const ACCOUNT_LOCKED: i64 = -32020; + pub const PASSWORD_INVALID: i64 = -32021; + pub const ACCOUNT_ERROR: i64 = -32023; + pub const SIGNER_DISABLED: i64 = -32030; + pub const REQUEST_REJECTED: i64 = -32040; + pub const REQUEST_NOT_FOUND: i64 = -32041; + pub const COMPILATION_ERROR: i64 = -32050; +} + +pub fn unimplemented() -> Error { + Error { + code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), + message: "This request is not implemented yet. Please create an issue on Github repo.".into(), + data: None + } +} + +pub fn request_not_found() -> Error { + Error { + code: ErrorCode::ServerError(codes::REQUEST_NOT_FOUND), + message: "Request not found.".into(), + data: None, + } +} + +pub fn request_rejected() -> Error { + Error { + code: ErrorCode::ServerError(codes::REQUEST_REJECTED), + message: "Request has been rejected.".into(), + data: None, + } +} + + +pub fn account(error: &str, details: T) -> Error { + Error { + code: ErrorCode::ServerError(codes::ACCOUNT_ERROR), + message: error.into(), + data: Some(Value::String(format!("{:?}", details))), + } +} + +pub fn compilation(error: T) -> Error { + Error { + code: ErrorCode::ServerError(codes::COMPILATION_ERROR), + message: "Error while compiling code.".into(), + data: Some(Value::String(format!("{:?}", error))), + } +} + +pub fn internal(error: &str, data: T) -> Error { + Error { + code: ErrorCode::InternalError, + message: format!("Internal error occurred: {}", error), + data: Some(Value::String(format!("{:?}", data))), + } +} + +pub fn invalid_params(param: &str, details: T) -> Error { + Error { + code: ErrorCode::InvalidParams, + message: format!("Couldn't parse parameters: {}", param), + data: Some(Value::String(format!("{:?}", details))), + } +} + +pub fn state_pruned() -> Error { + Error { + code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), + message: "This request is not supported because your node is running with state pruning. Run with --pruning=archive.".into(), + data: None + } +} + +pub fn no_work() -> Error { + Error { + code: ErrorCode::ServerError(codes::NO_WORK), + message: "Still syncing.".into(), + data: None + } +} + +pub fn no_author() -> Error { + Error { + code: ErrorCode::ServerError(codes::NO_AUTHOR), + message: "Author not configured. Run Parity with --author to configure.".into(), + data: None + } +} + + +pub fn signer_disabled() -> Error { + Error { + code: ErrorCode::ServerError(codes::SIGNER_DISABLED), + message: "Trusted Signer is disabled. This API is not available.".into(), + data: None + } +} + +pub fn from_signing_error(error: AccountError) -> Error { + Error { + code: ErrorCode::ServerError(codes::ACCOUNT_LOCKED), + message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(), + data: Some(Value::String(format!("{:?}", error))), + } +} + +pub fn from_password_error(error: AccountError) -> Error { + Error { + code: ErrorCode::ServerError(codes::PASSWORD_INVALID), + message: "Account password is invalid or account does not exist.".into(), + data: Some(Value::String(format!("{:?}", error))), + } +} + +pub fn from_transaction_error(error: EthcoreError) -> Error { + use ethcore::error::TransactionError::*; + + if let EthcoreError::Transaction(e) = error { + let msg = match e { + AlreadyImported => "Transaction with the same hash was already imported.".into(), + Old => "Transaction nonce is too low. Try incrementing the nonce.".into(), + TooCheapToReplace => { + "Transaction fee is too low. There is another transaction with same nonce in the queue. Try increasing the fee or incrementing the nonce.".into() + }, + LimitReached => { + "There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into() + }, + InsufficientGasPrice { minimal, got } => { + format!("Transaction fee is too low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got) + }, + InsufficientBalance { balance, cost } => { + format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance) + }, + GasLimitExceeded { limit, got } => { + format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) + }, + InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), + }; + Error { + code: ErrorCode::ServerError(codes::TRANSACTION_ERROR), + message: msg, + data: None, + } + } else { + Error { + code: ErrorCode::ServerError(codes::UNKNOWN_ERROR), + message: "Unknown error when sending transaction.".into(), + data: Some(Value::String(format!("{:?}", error))), + } + } +} + + diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index 315bb7a08..d71eaac41 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -14,6 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +#[macro_use] +pub mod errors; +pub mod dispatch; +pub mod params; mod poll_manager; mod poll_filter; mod requests; diff --git a/rpc/src/v1/helpers/network_settings.rs b/rpc/src/v1/helpers/network_settings.rs index 9e590c5e7..9847e9757 100644 --- a/rpc/src/v1/helpers/network_settings.rs +++ b/rpc/src/v1/helpers/network_settings.rs @@ -22,10 +22,6 @@ pub struct NetworkSettings { pub name: String, /// Name of the chain we are connected to pub chain: String, - /// Min number of peers - pub min_peers: u32, - /// Max number of peers - pub max_peers: u32, /// Networking port pub network_port: u16, /// Is JSON-RPC server enabled? @@ -41,8 +37,6 @@ impl Default for NetworkSettings { NetworkSettings { name: "".into(), chain: "homestead".into(), - min_peers: 25, - max_peers: 50, network_port: 30303, rpc_enabled: true, rpc_interface: "local".into(), diff --git a/rpc/src/v1/helpers/params.rs b/rpc/src/v1/helpers/params.rs new file mode 100644 index 000000000..c38529e4e --- /dev/null +++ b/rpc/src/v1/helpers/params.rs @@ -0,0 +1,53 @@ +// 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 . + +//! Parameters parsing helpers + +use serde; +use jsonrpc_core::{Error, Params, from_params}; +use v1::types::BlockNumber; +use v1::helpers::errors; + +pub fn expect_no_params(params: Params) -> Result<(), Error> { + match params { + Params::None => Ok(()), + p => Err(errors::invalid_params("No parameters were expected", p)), + } +} + +fn params_len(params: &Params) -> usize { + match params { + &Params::Array(ref vec) => vec.len(), + _ => 0, + } +} + +/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`. +pub fn from_params_default_second(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize { + match params_len(¶ms) { + 1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)), + _ => from_params::<(F, BlockNumber)>(params), + } +} + +/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`. +pub fn from_params_default_third(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize { + match params_len(¶ms) { + 2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)), + _ => from_params::<(F1, F2, BlockNumber)>(params) + } +} + diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 0d2b6164a..2d682954c 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,7 +23,6 @@ use std::process::{Command, Stdio}; use std::thread; use std::time::{Instant, Duration}; use std::sync::{Arc, Weak}; -use std::ops::Deref; use ethsync::{SyncProvider, SyncState}; use ethcore::miner::{MinerService, ExternalMinerService}; use jsonrpc_core::*; @@ -43,8 +42,9 @@ use ethcore::filter::Filter as EthcoreFilter; use self::ethash::SeedHashCompute; use v1::traits::Eth; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256}; -use v1::helpers::CallRequest as CRequest; -use v1::impls::{default_gas_price, dispatch_transaction, error_codes, from_params_default_second, from_params_default_third}; +use v1::helpers::{CallRequest as CRequest, errors}; +use v1::helpers::dispatch::{default_gas_price, dispatch_transaction}; +use v1::helpers::params::{expect_no_params, from_params_default_second, from_params_default_third}; /// Eth RPC options pub struct EthClientOptions { @@ -214,30 +214,6 @@ pub fn pending_logs(miner: &M, filter: &EthcoreFilter) -> Vec where M: M const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6. -fn make_unsupported_err() -> Error { - Error { - code: ErrorCode::ServerError(error_codes::UNSUPPORTED_REQUEST_CODE), - message: "Unsupported request.".into(), - data: None - } -} - -fn no_work_err() -> Error { - Error { - code: ErrorCode::ServerError(error_codes::NO_WORK_CODE), - message: "Still syncing.".into(), - data: None - } -} - -fn no_author_err() -> Error { - Error { - code: ErrorCode::ServerError(error_codes::NO_AUTHOR_CODE), - message: "Author not configured. Run parity with --author to configure.".into(), - data: None - } -} - impl EthClient where C: MiningBlockChainClient + 'static, S: SyncProvider + 'static, @@ -265,94 +241,80 @@ impl Eth for EthClient where fn protocol_version(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())), - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())) } fn syncing(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let status = take_weak!(self.sync).status(); - let res = match status.state { - SyncState::Idle => SyncStatus::None, - SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => { - let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number); - let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number)); + try!(expect_no_params(params)); - if highest_block > current_block + U256::from(6) { - let info = SyncInfo { - starting_block: status.start_block_number.into(), - current_block: current_block.into(), - highest_block: highest_block.into(), - }; - SyncStatus::Info(info) - } else { - SyncStatus::None - } - } - }; - to_value(&res) + let status = take_weak!(self.sync).status(); + let res = match status.state { + SyncState::Idle => SyncStatus::None, + SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => { + let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number); + let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number)); + + if highest_block > current_block + U256::from(6) { + let info = SyncInfo { + starting_block: status.start_block_number.into(), + current_block: current_block.into(), + highest_block: highest_block.into(), + }; + SyncStatus::Info(info) + } else { + SyncStatus::None + } } - _ => Err(Error::invalid_params()), - } + }; + to_value(&res) } fn author(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => to_value(&RpcH160::from(take_weak!(self.miner).author())), - _ => Err(Error::invalid_params()), - } + try!(expect_no_params(params)); + + to_value(&RpcH160::from(take_weak!(self.miner).author())) } fn is_mining(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => to_value(&(take_weak!(self.miner).is_sealing())), - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + to_value(&(take_weak!(self.miner).is_sealing())) } fn hashrate(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => to_value(&RpcU256::from(self.external_miner.hashrate())), - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + to_value(&RpcU256::from(self.external_miner.hashrate())) } fn gas_price(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let (client, miner) = (take_weak!(self.client), take_weak!(self.miner)); - to_value(&RpcU256::from(default_gas_price(&*client, &*miner))) - } - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + let (client, miner) = (take_weak!(self.client), take_weak!(self.miner)); + to_value(&RpcU256::from(default_gas_price(&*client, &*miner))) } fn accounts(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let store = take_weak!(self.accounts); - let accounts = try!(store.accounts().map_err(|_| Error::internal_error())); - to_value(&accounts.into_iter().map(Into::into).collect::>()) - }, - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + let store = take_weak!(self.accounts); + let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e))); + to_value(&accounts.into_iter().map(Into::into).collect::>()) } fn block_number(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => to_value(&RpcU256::from(take_weak!(self.client).chain_info().best_block_number)), - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + to_value(&RpcU256::from(take_weak!(self.client).chain_info().best_block_number)) } fn balance(&self, params: Params) -> Result { @@ -361,8 +323,11 @@ impl Eth for EthClient where .and_then(|(address, block_number,)| { let address: Address = RpcH160::into(address); match block_number { - BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).balance(take_weak!(self.client).deref(), &address))), - id => to_value(&RpcU256::from(try!(take_weak!(self.client).balance(&address, id.into()).ok_or_else(make_unsupported_err)))), + BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).balance(&*take_weak!(self.client), &address))), + id => match take_weak!(self.client).balance(&address, id.into()) { + Some(balance) => to_value(&RpcU256::from(balance)), + None => Err(errors::state_pruned()), + } } }) } @@ -377,7 +342,7 @@ impl Eth for EthClient where BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position)))), id => match take_weak!(self.client).storage_at(&address, &H256::from(position), id.into()) { Some(s) => to_value(&RpcH256::from(s)), - None => Err(make_unsupported_err()), // None is only returned on unsupported requests. + None => Err(errors::state_pruned()), } } }) @@ -390,8 +355,11 @@ impl Eth for EthClient where .and_then(|(address, block_number,)| { let address: Address = RpcH160::into(address); match block_number { - BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).nonce(take_weak!(self.client).deref(), &address))), - id => to_value(&take_weak!(self.client).nonce(&address, id.into()).map(RpcU256::from)), + BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address))), + id => match take_weak!(self.client).nonce(&address, id.into()) { + Some(nonce) => to_value(&RpcU256::from(nonce)), + None => Err(errors::state_pruned()), + } } }) } @@ -440,9 +408,11 @@ impl Eth for EthClient where .and_then(|(address, block_number,)| { let address: Address = RpcH160::into(address); match block_number { - BlockNumber::Pending => to_value(&take_weak!(self.miner).code(take_weak!(self.client).deref(), &address).map_or_else(Bytes::default, Bytes::new)), - BlockNumber::Latest => to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new)), - _ => Err(Error::invalid_params()), + BlockNumber::Pending => to_value(&take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)), + _ => match take_weak!(self.client).code(&address, block_number.into()) { + Some(code) => to_value(&code.map_or_else(Bytes::default, Bytes::new)), + None => Err(errors::state_pruned()), + }, } }) } @@ -515,16 +485,13 @@ impl Eth for EthClient where fn compilers(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let mut compilers = vec![]; - if Command::new(SOLC).output().is_ok() { - compilers.push("solidity".to_owned()) - } - to_value(&compilers) - } - _ => Err(Error::invalid_params()) + try!(expect_no_params(params)); + + let mut compilers = vec![]; + if Command::new(SOLC).output().is_ok() { + compilers.push("solidity".to_owned()) } + to_value(&compilers) } fn logs(&self, params: Params) -> Result { @@ -539,7 +506,7 @@ impl Eth for EthClient where .collect::>(); if include_pending { - let pending = pending_logs(take_weak!(self.miner).deref(), &filter); + let pending = pending_logs(&*take_weak!(self.miner), &filter); logs.extend(pending); } @@ -549,45 +516,42 @@ impl Eth for EthClient where fn work(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let client = take_weak!(self.client); - // check if we're still syncing and return empty strings in that case - { - //TODO: check if initial sync is complete here - //let sync = take_weak!(self.sync); - if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON { - trace!(target: "miner", "Syncing. Cannot give any work."); - return Err(no_work_err()); - } + try!(expect_no_params(params)); - // Otherwise spin until our submitted block has been included. - let timeout = Instant::now() + Duration::from_millis(1000); - while Instant::now() < timeout && client.queue_info().total_queue_size() > 0 { - thread::sleep(Duration::from_millis(1)); - } - } + let client = take_weak!(self.client); + // check if we're still syncing and return empty strings in that case + { + //TODO: check if initial sync is complete here + //let sync = take_weak!(self.sync); + if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON { + trace!(target: "miner", "Syncing. Cannot give any work."); + return Err(errors::no_work()); + } - let miner = take_weak!(self.miner); - if miner.author().is_zero() { - warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!"); - return Err(no_author_err()) - } - miner.map_sealing_work(client.deref(), |b| { - let pow_hash = b.hash(); - let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); - let seed_hash = self.seed_compute.lock().get_seedhash(b.block().header().number()); - - if self.options.send_block_number_in_get_work { - let block_number = RpcU256::from(b.block().header().number()); - to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target), block_number)) - } else { - to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target))) - } - }).unwrap_or(Err(Error::internal_error())) // no work found. - }, - _ => Err(Error::invalid_params()) + // Otherwise spin until our submitted block has been included. + let timeout = Instant::now() + Duration::from_millis(1000); + while Instant::now() < timeout && client.queue_info().total_queue_size() > 0 { + thread::sleep(Duration::from_millis(1)); + } } + + let miner = take_weak!(self.miner); + if miner.author().is_zero() { + warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!"); + return Err(errors::no_author()) + } + miner.map_sealing_work(&*client, |b| { + let pow_hash = b.hash(); + let target = Ethash::difficulty_to_boundary(b.block().header().difficulty()); + let seed_hash = self.seed_compute.lock().get_seedhash(b.block().header().number()); + + if self.options.send_block_number_in_get_work { + let block_number = RpcU256::from(b.block().header().number()); + to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target), block_number)) + } else { + to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target))) + } + }).unwrap_or(Err(Error::internal_error())) // no work found. } fn submit_work(&self, params: Params) -> Result { @@ -600,7 +564,7 @@ impl Eth for EthClient where let miner = take_weak!(self.miner); let client = take_weak!(self.client); let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()]; - let r = miner.submit_seal(client.deref(), pow_hash, seal); + let r = miner.submit_seal(&*client, pow_hash, seal); to_value(&r.is_ok()) }) } @@ -627,13 +591,12 @@ impl Eth for EthClient where fn call(&self, params: Params) -> Result { try!(self.active()); - trace!(target: "jsonrpc", "call: {:?}", params); from_params_default_second(params) .and_then(|(request, block_number,)| { let request = CallRequest::into(request); let signed = try!(self.sign_call(request)); let r = match block_number { - BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()), + BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()), block_number => take_weak!(self.client).call(&signed, block_number.into(), Default::default()), }; to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![]))) @@ -647,7 +610,7 @@ impl Eth for EthClient where let request = CallRequest::into(request); let signed = try!(self.sign_call(request)); let r = match block_number { - BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()), + BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()), block => take_weak!(self.client).call(&signed, block.into(), Default::default()), }; to_value(&RpcU256::from(r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0)))) @@ -675,17 +638,23 @@ impl Eth for EthClient where .stdout(Stdio::piped()) .stderr(Stdio::null()) .spawn(); - if let Ok(mut child) = maybe_child { - if let Ok(_) = child.stdin.as_mut().expect("we called child.stdin(Stdio::piped()) before spawn; qed").write_all(code.as_bytes()) { - if let Ok(output) = child.wait_with_output() { - let s = String::from_utf8_lossy(&output.stdout); - if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() { - return to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![]))); - } + + maybe_child + .map_err(errors::compilation) + .and_then(|mut child| { + try!(child.stdin.as_mut() + .expect("we called child.stdin(Stdio::piped()) before spawn; qed") + .write_all(code.as_bytes()) + .map_err(errors::compilation)); + let output = try!(child.wait_with_output().map_err(errors::compilation)); + + let s = String::from_utf8_lossy(&output.stdout); + if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() { + to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![]))) + } else { + Err(errors::compilation("Unexpected output.")) } - } - } - Err(Error::invalid_params()) + }) }) } } diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index 6eb0c60bb..973e23e0b 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -16,7 +16,6 @@ //! Eth Filter RPC implementation -use std::ops::Deref; use std::sync::{Arc, Weak}; use std::collections::HashSet; use jsonrpc_core::*; @@ -27,6 +26,7 @@ use util::Mutex; use v1::traits::EthFilter; use v1::types::{BlockNumber, Index, Filter, Log, H256 as RpcH256, U256 as RpcU256}; use v1::helpers::{PollFilter, PollManager}; +use v1::helpers::params::expect_no_params; use v1::impls::eth::pending_logs; /// Eth filter rpc implementation. @@ -76,28 +76,22 @@ impl EthFilter for EthFilterClient where fn new_block_filter(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let mut polls = self.polls.lock(); - let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); - to_value(&RpcU256::from(id)) - }, - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + let mut polls = self.polls.lock(); + let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number)); + to_value(&RpcU256::from(id)) } fn new_pending_transaction_filter(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let mut polls = self.polls.lock(); - let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); - let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); + try!(expect_no_params(params)); - to_value(&RpcU256::from(id)) - }, - _ => Err(Error::invalid_params()) - } + let mut polls = self.polls.lock(); + let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(); + let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); + + to_value(&RpcU256::from(id)) } fn filter_changes(&self, params: Params) -> Result { @@ -165,7 +159,7 @@ impl EthFilter for EthFilterClient where // additionally retrieve pending logs if include_pending { - let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter); + let pending_logs = pending_logs(&*take_weak!(self.miner), &filter); // remove logs about which client was already notified about let new_pending_logs: Vec<_> = pending_logs.iter() @@ -206,7 +200,7 @@ impl EthFilter for EthFilterClient where .collect::>(); if include_pending { - logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter)); + logs.extend(pending_logs(&*take_weak!(self.miner), &filter)); } to_value(&logs) diff --git a/rpc/src/v1/impls/eth_signing.rs b/rpc/src/v1/impls/eth_signing.rs index 8cedd865a..98aec52a2 100644 --- a/rpc/src/v1/impls/eth_signing.rs +++ b/rpc/src/v1/impls/eth_signing.rs @@ -23,10 +23,10 @@ use ethcore::client::MiningBlockChainClient; use util::{U256, Address, H256, Mutex}; use transient_hashmap::TransientHashMap; use ethcore::account_provider::AccountProvider; -use v1::helpers::{SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationsQueue, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest}; +use v1::helpers::{errors, SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationsQueue, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest}; +use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch}; use v1::traits::EthSigning; use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U256 as RpcU256}; -use v1::impls::{default_gas_price, sign_and_dispatch, request_rejected_error, request_not_found_error, signer_disabled_error}; fn fill_optional_fields(request: TRequest, client: &C, miner: &M) -> FilledRequest where C: MiningBlockChainClient, M: MinerService { @@ -151,10 +151,10 @@ impl EthSigning for EthSigningQueueClient let res = match pending.get(&id) { Some(ref promise) => match promise.result() { ConfirmationResult::Waiting => { return Ok(Value::Null); } - ConfirmationResult::Rejected => Err(request_rejected_error()), + ConfirmationResult::Rejected => Err(errors::request_rejected()), ConfirmationResult::Confirmed(rpc_response) => rpc_response, }, - _ => { return Err(request_not_found_error()); } + _ => { return Err(errors::request_not_found()); } }; pending.remove(&id); res @@ -217,16 +217,16 @@ impl EthSigning for EthSigningUnsafeClient where fn post_sign(&self, _: Params) -> Result { // We don't support this in non-signer mode. - Err(signer_disabled_error()) + Err(errors::signer_disabled()) } fn post_transaction(&self, _: Params) -> Result { // We don't support this in non-signer mode. - Err(signer_disabled_error()) + Err(errors::signer_disabled()) } fn check_request(&self, _: Params) -> Result { // We don't support this in non-signer mode. - Err(signer_disabled_error()) + Err(errors::signer_disabled()) } } diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index 4d1d59dd8..e5ab2962a 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -18,34 +18,48 @@ use util::{RotatingLogger}; use util::misc::version_data; use std::sync::{Arc, Weak}; -use std::ops::Deref; use std::collections::{BTreeMap}; -use ethcore::client::{MiningBlockChainClient}; -use jsonrpc_core::*; +use ethsync::{SyncProvider, ManageNetwork}; use ethcore::miner::MinerService; +use ethcore::client::{MiningBlockChainClient}; + +use jsonrpc_core::*; use v1::traits::Ethcore; -use v1::types::{Bytes, U256}; -use v1::helpers::{SigningQueue, ConfirmationsQueue, NetworkSettings}; -use v1::impls::signer_disabled_error; +use v1::types::{Bytes, U256, Peers}; +use v1::helpers::{errors, SigningQueue, ConfirmationsQueue, NetworkSettings}; +use v1::helpers::params::expect_no_params; /// Ethcore implementation. -pub struct EthcoreClient where +pub struct EthcoreClient where C: MiningBlockChainClient, - M: MinerService { + M: MinerService, + S: SyncProvider { client: Weak, miner: Weak, + sync: Weak, + net: Weak, logger: Arc, settings: Arc, confirmations_queue: Option>, } -impl EthcoreClient where C: MiningBlockChainClient, M: MinerService { +impl EthcoreClient where C: MiningBlockChainClient, M: MinerService, S: SyncProvider { /// Creates new `EthcoreClient`. - pub fn new(client: &Arc, miner: &Arc, logger: Arc, settings: Arc, queue: Option>) -> Self { + pub fn new( + client: &Arc, + miner: &Arc, + sync: &Arc, + net: &Arc, + logger: Arc, + settings: Arc, + queue: Option> + ) -> Self { EthcoreClient { client: Arc::downgrade(client), miner: Arc::downgrade(miner), + sync: Arc::downgrade(sync), + net: Arc::downgrade(net), logger: logger, settings: settings, confirmations_queue: queue, @@ -59,66 +73,86 @@ impl EthcoreClient where C: MiningBlockChainClient, M: MinerService } } -impl Ethcore for EthcoreClient where M: MinerService + 'static, C: MiningBlockChainClient + 'static { +impl Ethcore for EthcoreClient where M: MinerService + 'static, C: MiningBlockChainClient + 'static, S: SyncProvider + 'static { - fn transactions_limit(&self, _: Params) -> Result { + fn transactions_limit(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&take_weak!(self.miner).transactions_limit()) } - fn min_gas_price(&self, _: Params) -> Result { + fn min_gas_price(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&U256::from(take_weak!(self.miner).minimal_gas_price())) } - fn extra_data(&self, _: Params) -> Result { + fn extra_data(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&Bytes::new(take_weak!(self.miner).extra_data())) } - fn gas_floor_target(&self, _: Params) -> Result { + fn gas_floor_target(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&U256::from(take_weak!(self.miner).gas_floor_target())) } - fn gas_ceil_target(&self, _: Params) -> Result { + fn gas_ceil_target(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&U256::from(take_weak!(self.miner).gas_ceil_target())) } - fn dev_logs(&self, _params: Params) -> Result { + fn dev_logs(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); let logs = self.logger.logs(); - to_value(&logs.deref().as_slice()) + to_value(&logs.as_slice()) } - fn dev_logs_levels(&self, _params: Params) -> Result { + fn dev_logs_levels(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&self.logger.levels()) } - fn net_chain(&self, _params: Params) -> Result { + fn net_chain(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&self.settings.chain) } - fn net_max_peers(&self, _params: Params) -> Result { + fn net_peers(&self, params: Params) -> Result { try!(self.active()); - to_value(&self.settings.max_peers) + try!(expect_no_params(params)); + + let sync_status = take_weak!(self.sync).status(); + let net_config = take_weak!(self.net).network_config(); + + to_value(&Peers { + active: sync_status.num_active_peers, + connected: sync_status.num_peers, + max: sync_status.current_max_peers(net_config.min_peers, net_config.max_peers), + }) } - fn net_port(&self, _params: Params) -> Result { + fn net_port(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&self.settings.network_port) } - fn node_name(&self, _params: Params) -> Result { + fn node_name(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); to_value(&self.settings.name) } - fn rpc_settings(&self, _params: Params) -> Result { + fn rpc_settings(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); let mut map = BTreeMap::new(); map.insert("enabled".to_owned(), Value::Bool(self.settings.rpc_enabled)); map.insert("interface".to_owned(), Value::String(self.settings.rpc_interface.clone())); @@ -128,30 +162,29 @@ impl Ethcore for EthcoreClient where M: MinerService + 'static, C: M fn default_extra_data(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => to_value(&Bytes::new(version_data())), - _ => Err(Error::invalid_params()), - } + try!(expect_no_params(params)); + to_value(&Bytes::new(version_data())) } fn gas_price_statistics(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => match take_weak!(self.client).gas_price_statistics(100, 8) { - Ok(stats) => to_value(&stats - .into_iter() - .map(|x| to_value(&U256::from(x)).expect("x must be U256; qed")) - .collect::>()), - _ => Err(Error::internal_error()), - }, - _ => Err(Error::invalid_params()), + try!(expect_no_params(params)); + + match take_weak!(self.client).gas_price_statistics(100, 8) { + Ok(stats) => to_value(&stats + .into_iter() + .map(|x| to_value(&U256::from(x)).expect("x must be U256; qed")) + .collect::>()), + _ => Err(Error::internal_error()), } } - fn unsigned_transactions_count(&self, _params: Params) -> Result { + fn unsigned_transactions_count(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); + match self.confirmations_queue { - None => Err(signer_disabled_error()), + None => Err(errors::signer_disabled()), Some(ref queue) => to_value(&queue.len()), } } diff --git a/rpc/src/v1/impls/ethcore_set.rs b/rpc/src/v1/impls/ethcore_set.rs index 2c02c51ac..a5e037b5f 100644 --- a/rpc/src/v1/impls/ethcore_set.rs +++ b/rpc/src/v1/impls/ethcore_set.rs @@ -20,6 +20,8 @@ use jsonrpc_core::*; use ethcore::miner::MinerService; use ethcore::client::MiningBlockChainClient; use ethsync::ManageNetwork; +use v1::helpers::errors; +use v1::helpers::params::expect_no_params; use v1::traits::EthcoreSet; use v1::types::{Bytes, H160, U256}; @@ -117,7 +119,7 @@ impl EthcoreSet for EthcoreSetClient where from_params::<(String,)>(params).and_then(|(peer,)| { match take_weak!(self.net).add_reserved_peer(peer) { Ok(()) => to_value(&true), - Err(_) => Err(Error::invalid_params()), + Err(e) => Err(errors::invalid_params("Peer address", e)), } }) } @@ -127,29 +129,33 @@ impl EthcoreSet for EthcoreSetClient where from_params::<(String,)>(params).and_then(|(peer,)| { match take_weak!(self.net).remove_reserved_peer(peer) { Ok(()) => to_value(&true), - Err(_) => Err(Error::invalid_params()), + Err(e) => Err(errors::invalid_params("Peer address", e)), } }) } - fn drop_non_reserved_peers(&self, _: Params) -> Result { + fn drop_non_reserved_peers(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); take_weak!(self.net).deny_unreserved_peers(); to_value(&true) } - fn accept_non_reserved_peers(&self, _: Params) -> Result { + fn accept_non_reserved_peers(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); take_weak!(self.net).accept_unreserved_peers(); to_value(&true) } - fn start_network(&self, _: Params) -> Result { + fn start_network(&self, params: Params) -> Result { + try!(expect_no_params(params)); take_weak!(self.net).start_network(); Ok(Value::Bool(true)) } - fn stop_network(&self, _: Params) -> Result { + fn stop_network(&self, params: Params) -> Result { + try!(expect_no_params(params)); take_weak!(self.net).stop_network(); Ok(Value::Bool(true)) } diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index e21014eff..c0bd76c4c 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -25,21 +25,17 @@ macro_rules! take_weak { } } -macro_rules! rpc_unimplemented { - () => (Err(Error::internal_error())) -} - -mod web3; mod eth; mod eth_filter; mod eth_signing; +mod ethcore; +mod ethcore_set; mod net; mod personal; mod personal_signer; -mod ethcore; -mod ethcore_set; -mod traces; mod rpc; +mod traces; +mod web3; pub use self::web3::Web3Client; pub use self::eth::{EthClient, EthClientOptions}; @@ -53,202 +49,3 @@ pub use self::ethcore_set::EthcoreSetClient; pub use self::traces::TracesClient; pub use self::rpc::RpcClient; -use serde; -use v1::helpers::TransactionRequest; -use v1::types::{H256 as RpcH256, H520 as RpcH520, BlockNumber}; -use ethcore::error::Error as EthcoreError; -use ethcore::miner::MinerService; -use ethcore::client::MiningBlockChainClient; -use ethcore::transaction::{Action, SignedTransaction, Transaction}; -use ethcore::account_provider::{AccountProvider, Error as AccountError}; -use util::numbers::*; -use util::rlp::encode; -use util::bytes::ToPretty; -use jsonrpc_core::{Error, ErrorCode, Value, to_value, from_params, Params}; - -mod error_codes { - // NOTE [ToDr] Codes from [-32099, -32000] - pub const UNSUPPORTED_REQUEST_CODE: i64 = -32000; - pub const NO_WORK_CODE: i64 = -32001; - pub const NO_AUTHOR_CODE: i64 = -32002; - pub const UNKNOWN_ERROR: i64 = -32009; - pub const TRANSACTION_ERROR: i64 = -32010; - pub const ACCOUNT_LOCKED: i64 = -32020; - pub const PASSWORD_INVALID: i64 = -32021; - pub const SIGNER_DISABLED: i64 = -32030; - pub const REQUEST_REJECTED: i64 = -32040; - pub const REQUEST_NOT_FOUND: i64 = -32041; -} - -fn params_len(params: &Params) -> usize { - match params { - &Params::Array(ref vec) => vec.len(), - _ => 0, - } -} - -/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`. -pub fn from_params_default_second(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize { - match params_len(¶ms) { - 1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)), - _ => from_params::<(F, BlockNumber)>(params), - } -} - -/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`. -pub fn from_params_default_third(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize { - match params_len(¶ms) { - 2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)), - _ => from_params::<(F1, F2, BlockNumber)>(params) - } -} - - -fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result - where C: MiningBlockChainClient, M: MinerService { - let hash = RpcH256::from(signed_transaction.hash()); - - let import = miner.import_own_transaction(client, signed_transaction); - - import - .map_err(transaction_error) - .and_then(|_| to_value(&hash)) -} - -fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result { - accounts.sign_with_password(address, pass, hash) - .map_err(password_error) - .and_then(|hash| to_value(&RpcH520::from(hash))) -} - -fn prepare_transaction(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService { - Transaction { - nonce: request.nonce - .or_else(|| miner - .last_nonce(&request.from) - .map(|nonce| nonce + U256::one())) - .unwrap_or_else(|| client.latest_nonce(&request.from)), - - action: request.to.map_or(Action::Create, Action::Call), - gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()), - gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)), - value: request.value.unwrap_or_else(U256::zero), - data: request.data.map_or_else(Vec::new, |b| b.to_vec()), - } -} - -fn unlock_sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result - where C: MiningBlockChainClient, M: MinerService { - - let address = request.from; - let signed_transaction = { - let t = prepare_transaction(client, miner, request); - let hash = t.hash(); - let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(password_error)); - t.with_signature(signature) - }; - - trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); - dispatch_transaction(&*client, &*miner, signed_transaction) -} - -fn sign_and_dispatch(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result - where C: MiningBlockChainClient, M: MinerService { - - let signed_transaction = { - let t = prepare_transaction(client, miner, request); - let hash = t.hash(); - let signature = try!(account_provider.sign(address, hash).map_err(signing_error)); - t.with_signature(signature) - }; - - trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); - dispatch_transaction(&*client, &*miner, signed_transaction) -} - -fn default_gas_price(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService { - client - .gas_price_statistics(100, 8) - .map(|x| x[4]) - .unwrap_or_else(|_| miner.sensible_gas_price()) -} - -fn signer_disabled_error() -> Error { - Error { - code: ErrorCode::ServerError(error_codes::SIGNER_DISABLED), - message: "Trusted Signer is disabled. This API is not available.".into(), - data: None - } -} - -fn signing_error(error: AccountError) -> Error { - Error { - code: ErrorCode::ServerError(error_codes::ACCOUNT_LOCKED), - message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(), - data: Some(Value::String(format!("{:?}", error))), - } -} - -fn password_error(error: AccountError) -> Error { - Error { - code: ErrorCode::ServerError(error_codes::PASSWORD_INVALID), - message: "Account password is invalid or account does not exist.".into(), - data: Some(Value::String(format!("{:?}", error))), - } -} - -/// Error returned when request is rejected (in Trusted Signer). -pub fn request_rejected_error() -> Error { - Error { - code: ErrorCode::ServerError(error_codes::REQUEST_REJECTED), - message: "Request has been rejected.".into(), - data: None, - } -} - -/// Error returned when request is not found in queue. -pub fn request_not_found_error() -> Error { - Error { - code: ErrorCode::ServerError(error_codes::REQUEST_NOT_FOUND), - message: "Request not found.".into(), - data: None, - } -} - -fn transaction_error(error: EthcoreError) -> Error { - use ethcore::error::TransactionError::*; - - if let EthcoreError::Transaction(e) = error { - let msg = match e { - AlreadyImported => "Transaction with the same hash was already imported.".into(), - Old => "Transaction nonce is too low. Try incrementing the nonce.".into(), - TooCheapToReplace => { - "Transaction fee is too low. There is another transaction with same nonce in the queue. Try increasing the fee or incrementing the nonce.".into() - }, - LimitReached => { - "There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into() - }, - InsufficientGasPrice { minimal, got } => { - format!("Transaction fee is too low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got) - }, - InsufficientBalance { balance, cost } => { - format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance) - }, - GasLimitExceeded { limit, got } => { - format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) - }, - InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), - }; - Error { - code: ErrorCode::ServerError(error_codes::TRANSACTION_ERROR), - message: msg, - data: None, - } - } else { - Error { - code: ErrorCode::ServerError(error_codes::UNKNOWN_ERROR), - message: "Unknown error when sending transaction.".into(), - data: Some(Value::String(format!("{:?}", error))), - } - } -} diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 0bbfeca6c..9c22a3638 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -19,6 +19,7 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; use ethsync::SyncProvider; use v1::traits::Net; +use v1::helpers::params::expect_no_params; /// Net rpc implementation. pub struct NetClient where S: SyncProvider { @@ -35,15 +36,18 @@ impl NetClient where S: SyncProvider { } impl Net for NetClient where S: SyncProvider + 'static { - fn version(&self, _: Params) -> Result { + fn version(&self, params: Params) -> Result { + try!(expect_no_params(params)); Ok(Value::String(format!("{}", take_weak!(self.sync).status().network_id).to_owned())) } - fn peer_count(&self, _params: Params) -> Result { + fn peer_count(&self, params: Params) -> Result { + try!(expect_no_params(params)); Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned())) } - fn is_listening(&self, _: Params) -> Result { + fn is_listening(&self, params: Params) -> Result { + try!(expect_no_params(params)); // right now (11 march 2016), we are always listening for incoming connections Ok(Value::Bool(true)) } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 958efe3a8..26156ca23 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -20,8 +20,9 @@ use std::collections::{BTreeMap}; use jsonrpc_core::*; use v1::traits::Personal; use v1::types::{H160 as RpcH160, TransactionRequest}; -use v1::impls::unlock_sign_and_dispatch; -use v1::helpers::{TransactionRequest as TRequest}; +use v1::helpers::{errors, TransactionRequest as TRequest}; +use v1::helpers::params::expect_no_params; +use v1::helpers::dispatch::unlock_sign_and_dispatch; use ethcore::account_provider::AccountProvider; use util::Address; use ethcore::client::MiningBlockChainClient; @@ -57,8 +58,10 @@ impl PersonalClient where C: MiningBlockChainClient, M: MinerService impl Personal for PersonalClient where C: MiningBlockChainClient, M: MinerService { - fn signer_enabled(&self, _: Params) -> Result { + fn signer_enabled(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); + self.signer_port .map(|v| to_value(&v)) .unwrap_or_else(|| to_value(&false)) @@ -66,14 +69,11 @@ impl Personal for PersonalClient where C: MiningBl fn accounts(&self, params: Params) -> Result { try!(self.active()); - match params { - Params::None => { - let store = take_weak!(self.accounts); - let accounts = try!(store.accounts().map_err(|_| Error::internal_error())); - to_value(&accounts.into_iter().map(Into::into).collect::>()) - }, - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + + let store = take_weak!(self.accounts); + let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e))); + to_value(&accounts.into_iter().map(Into::into).collect::>()) } fn new_account(&self, params: Params) -> Result { @@ -83,7 +83,7 @@ impl Personal for PersonalClient where C: MiningBl let store = take_weak!(self.accounts); match store.new_account(&pass) { Ok(address) => to_value(&RpcH160::from(address)), - Err(_) => Err(Error::internal_error()) + Err(e) => Err(errors::account("Could not create account.", e)), } } ) @@ -124,7 +124,7 @@ impl Personal for PersonalClient where C: MiningBl let store = take_weak!(self.accounts); from_params::<(RpcH160, _)>(params).and_then(|(addr, name)| { let addr: Address = addr.into(); - store.set_account_name(addr, name).map_err(|_| Error::invalid_params()).map(|_| Value::Null) + store.set_account_name(addr, name).map_err(|e| errors::account("Could not set account name.", e)).map(|_| Value::Null) }) } @@ -133,14 +133,16 @@ impl Personal for PersonalClient where C: MiningBl let store = take_weak!(self.accounts); from_params::<(RpcH160, _)>(params).and_then(|(addr, meta)| { let addr: Address = addr.into(); - store.set_account_meta(addr, meta).map_err(|_| Error::invalid_params()).map(|_| Value::Null) + store.set_account_meta(addr, meta).map_err(|e| errors::account("Could not set account meta.", e)).map(|_| Value::Null) }) } - fn accounts_info(&self, _: Params) -> Result { + fn accounts_info(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); let store = take_weak!(self.accounts); - Ok(Value::Object(try!(store.accounts_info().map_err(|_| Error::invalid_params())).into_iter().map(|(a, v)| { + let info = try!(store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))); + Ok(Value::Object(info.into_iter().map(|(a, v)| { let m = map![ "name".to_owned() => to_value(&v.name).unwrap(), "meta".to_owned() => to_value(&v.meta).unwrap(), diff --git a/rpc/src/v1/impls/personal_signer.rs b/rpc/src/v1/impls/personal_signer.rs index 2dfce57af..bd58fde7d 100644 --- a/rpc/src/v1/impls/personal_signer.rs +++ b/rpc/src/v1/impls/personal_signer.rs @@ -23,8 +23,9 @@ use ethcore::client::MiningBlockChainClient; use ethcore::miner::MinerService; use v1::traits::PersonalSigner; use v1::types::{TransactionModification, ConfirmationRequest, U256}; -use v1::impls::{unlock_sign_and_dispatch, signature_with_password}; -use v1::helpers::{SigningQueue, ConfirmationsQueue, ConfirmationPayload}; +use v1::helpers::{errors, SigningQueue, ConfirmationsQueue, ConfirmationPayload}; +use v1::helpers::params::expect_no_params; +use v1::helpers::dispatch::{unlock_sign_and_dispatch, signature_with_password}; /// Transactions confirmation (personal) rpc implementation. pub struct SignerClient where C: MiningBlockChainClient, M: MinerService { @@ -55,8 +56,9 @@ impl SignerClient where C: MiningBlockChainClient, impl PersonalSigner for SignerClient where C: MiningBlockChainClient, M: MinerService { - fn requests_to_confirm(&self, _params: Params) -> Result { + fn requests_to_confirm(&self, params: Params) -> Result { try!(self.active()); + try!(expect_no_params(params)); let queue = take_weak!(self.queue); to_value(&queue.requests().into_iter().map(From::from).collect::>()) } @@ -91,7 +93,7 @@ impl PersonalSigner for SignerClient where C: Mini queue.request_confirmed(id, Ok(response.clone())); } result - }).unwrap_or_else(|| Err(Error::invalid_params())) + }).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id))) } ) } diff --git a/rpc/src/v1/impls/rpc.rs b/rpc/src/v1/impls/rpc.rs index ebbef5025..fafc92fe5 100644 --- a/rpc/src/v1/impls/rpc.rs +++ b/rpc/src/v1/impls/rpc.rs @@ -18,6 +18,7 @@ use std::collections::BTreeMap; use jsonrpc_core::*; use v1::traits::Rpc; +use v1::helpers::params::expect_no_params; /// RPC generic methods implementation. pub struct RpcClient { @@ -39,7 +40,8 @@ impl RpcClient { } impl Rpc for RpcClient { - fn rpc_modules(&self, _: Params) -> Result { + fn rpc_modules(&self, params: Params) -> Result { + try!(expect_no_params(params)); let modules = self.modules.iter() .fold(BTreeMap::new(), |mut map, (k, v)| { map.insert(k.to_owned(), Value::String(v.to_owned())); @@ -48,7 +50,8 @@ impl Rpc for RpcClient { Ok(Value::Object(modules)) } - fn modules(&self, _: Params) -> Result { + fn modules(&self, params: Params) -> Result { + try!(expect_no_params(params)); let modules = self.modules.iter() .filter(|&(k, _v)| { self.valid_apis.contains(k) diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index d8d2b0257..e5f84d9ef 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -23,9 +23,9 @@ use ethcore::client::{BlockChainClient, CallAnalytics, TransactionID, TraceId}; use ethcore::miner::MinerService; use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; use v1::traits::Traces; -use v1::helpers::CallRequest as CRequest; +use v1::helpers::{errors, CallRequest as CRequest}; +use v1::helpers::params::from_params_default_third; use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256}; -use v1::impls::from_params_default_third; fn to_call_analytics(flags: Vec) -> CallAnalytics { CallAnalytics { @@ -144,7 +144,7 @@ impl Traces for TracesClient where C: BlockChainClient + 'static, M: Ok(e) => to_value(&TraceResults::from(e)), _ => Ok(Value::Null), }, - Err(_) => Err(Error::invalid_params()), + Err(e) => Err(errors::invalid_params("Transaction is not valid RLP", e)), } }) } diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index 3f993f21c..d4ff4f7aa 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -19,6 +19,7 @@ use jsonrpc_core::*; use util::version; use v1::traits::Web3; use v1::types::{H256, Bytes}; +use v1::helpers::params::expect_no_params; use util::sha3::Hashable; /// Web3 rpc implementation. @@ -31,10 +32,8 @@ impl Web3Client { impl Web3 for Web3Client { fn client_version(&self, params: Params) -> Result { - match params { - Params::None => Ok(Value::String(version().to_owned().replace("Parity/", "Parity//"))), - _ => Err(Error::invalid_params()) - } + try!(expect_no_params(params)); + Ok(Value::String(version().to_owned().replace("Parity/", "Parity//"))) } fn sha3(&self, params: Params) -> Result { diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index c462bd333..897fcf623 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -18,8 +18,9 @@ //! //! Compliant with ethereum rpc. -mod impls; +#[macro_use] mod helpers; +mod impls; pub mod traits; pub mod tests; diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index f4cfec4fd..cf7bb8eb1 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -15,13 +15,16 @@ // along with Parity. If not, see . use std::sync::Arc; +use util::log::RotatingLogger; +use util::U256; +use ethsync::ManageNetwork; +use ethcore::client::{TestBlockChainClient}; + use jsonrpc_core::IoHandler; use v1::{Ethcore, EthcoreClient}; -use v1::tests::helpers::TestMinerService; -use v1::helpers::ConfirmationsQueue; -use ethcore::client::{TestBlockChainClient}; -use util::log::RotatingLogger; -use v1::helpers::NetworkSettings; +use v1::helpers::{ConfirmationsQueue, NetworkSettings}; +use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; +use super::manage_network::TestManageNetwork; fn miner_service() -> Arc { Arc::new(TestMinerService::default()) @@ -31,6 +34,13 @@ fn client_service() -> Arc { Arc::new(TestBlockChainClient::default()) } +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { + network_id: U256::from(3), + num_peers: 120, + })) +} + fn logger() -> Arc { Arc::new(RotatingLogger::new("rpc=trace".to_owned())) } @@ -39,8 +49,6 @@ fn settings() -> Arc { Arc::new(NetworkSettings { name: "mynode".to_owned(), chain: "testchain".to_owned(), - min_peers: 25, - max_peers: 25, network_port: 30303, rpc_enabled: true, rpc_interface: "all".to_owned(), @@ -48,16 +56,26 @@ fn settings() -> Arc { }) } -fn ethcore_client(client: &Arc, miner: &Arc) -> EthcoreClient { - EthcoreClient::new(client, miner, logger(), settings(), None) +fn network_service() -> Arc { + Arc::new(TestManageNetwork) +} + +fn ethcore_client( + client: &Arc, + miner: &Arc, + sync: &Arc, + net: &Arc) -> EthcoreClient { + EthcoreClient::new(client, miner, sync, net, logger(), settings(), None) } #[test] fn rpc_ethcore_extra_data() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x01020304","id":1}"#; @@ -72,8 +90,10 @@ fn rpc_ethcore_default_extra_data() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#; let response = format!(r#"{{"jsonrpc":"2.0","result":"0x{}","id":1}}"#, misc::version_data().to_hex()); @@ -85,8 +105,10 @@ fn rpc_ethcore_default_extra_data() { fn rpc_ethcore_gas_floor_target() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x3039","id":1}"#; @@ -98,8 +120,10 @@ fn rpc_ethcore_gas_floor_target() { fn rpc_ethcore_min_gas_price() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x01312d00","id":1}"#; @@ -111,10 +135,12 @@ fn rpc_ethcore_min_gas_price() { fn rpc_ethcore_dev_logs() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let logger = logger(); logger.append("a".to_owned()); logger.append("b".to_owned()); - let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings(), None).to_delegate(); + let ethcore = EthcoreClient::new(&client, &miner, &sync, &net, logger.clone(), settings(), None).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); @@ -128,8 +154,10 @@ fn rpc_ethcore_dev_logs() { fn rpc_ethcore_dev_logs_levels() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"rpc=trace","id":1}"#; @@ -141,8 +169,10 @@ fn rpc_ethcore_dev_logs_levels() { fn rpc_ethcore_transactions_limit() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":1024,"id":1}"#; @@ -154,8 +184,10 @@ fn rpc_ethcore_transactions_limit() { fn rpc_ethcore_net_chain() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"testchain","id":1}"#; @@ -164,14 +196,16 @@ fn rpc_ethcore_net_chain() { } #[test] -fn rpc_ethcore_net_max_peers() { +fn rpc_ethcore_net_peers() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); - let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":25,"id":1}"#; + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPeers", "params":[], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50},"id":1}"#; assert_eq!(io.handle_request(request), Some(response.to_owned())); } @@ -180,8 +214,10 @@ fn rpc_ethcore_net_max_peers() { fn rpc_ethcore_net_port() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":30303,"id":1}"#; @@ -193,8 +229,10 @@ fn rpc_ethcore_net_port() { fn rpc_ethcore_rpc_settings() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":{"enabled":true,"interface":"all","port":8545},"id":1}"#; @@ -206,8 +244,10 @@ fn rpc_ethcore_rpc_settings() { fn rpc_ethcore_node_name() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"mynode","id":1}"#; @@ -219,9 +259,11 @@ fn rpc_ethcore_node_name() { fn rpc_ethcore_unsigned_transactions_count() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); let queue = Arc::new(ConfirmationsQueue::default()); - let ethcore = EthcoreClient::new(&client, &miner, logger(), settings(), Some(queue)).to_delegate(); + let ethcore = EthcoreClient::new(&client, &miner, &sync, &net, logger(), settings(), Some(queue)).to_delegate(); io.add_delegate(ethcore); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#; @@ -234,8 +276,10 @@ fn rpc_ethcore_unsigned_transactions_count() { fn rpc_ethcore_unsigned_transactions_count_when_signer_disabled() { let miner = miner_service(); let client = client_service(); + let sync = sync_provider(); + let net = network_service(); let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); + io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#; diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index a5032d3e2..fb4b9492b 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -45,8 +45,8 @@ pub trait Ethcore: Sized + Send + Sync + 'static { /// Returns chain name fn net_chain(&self, _: Params) -> Result; - /// Returns max peers - fn net_max_peers(&self, _: Params) -> Result; + /// Returns peers details + fn net_peers(&self, _: Params) -> Result; /// Returns network port fn net_port(&self, _: Params) -> Result; @@ -79,7 +79,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static { delegate.add_method("ethcore_devLogs", Ethcore::dev_logs); delegate.add_method("ethcore_devLogsLevels", Ethcore::dev_logs_levels); delegate.add_method("ethcore_netChain", Ethcore::net_chain); - delegate.add_method("ethcore_netMaxPeers", Ethcore::net_max_peers); + delegate.add_method("ethcore_netPeers", Ethcore::net_peers); delegate.add_method("ethcore_netPort", Ethcore::net_port); delegate.add_method("ethcore_rpcSettings", Ethcore::rpc_settings); delegate.add_method("ethcore_nodeName", Ethcore::node_name); diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index f51271123..312e93818 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -40,7 +40,7 @@ pub use self::filter::Filter; pub use self::hash::{H64, H160, H256, H520, H2048}; pub use self::index::Index; pub use self::log::Log; -pub use self::sync::{SyncStatus, SyncInfo}; +pub use self::sync::{SyncStatus, SyncInfo, Peers}; pub use self::transaction::Transaction; pub use self::transaction_request::TransactionRequest; pub use self::receipt::Receipt; diff --git a/rpc/src/v1/types/sync.rs b/rpc/src/v1/types/sync.rs index 49f422c86..cf94120ec 100644 --- a/rpc/src/v1/types/sync.rs +++ b/rpc/src/v1/types/sync.rs @@ -31,6 +31,17 @@ pub struct SyncInfo { pub highest_block: U256, } +/// Peers info +#[derive(Default, Debug, Serialize, PartialEq)] +pub struct Peers { + /// Number of active peers + pub active: usize, + /// Number of connected peers + pub connected: usize, + /// Max number of peers + pub max: u32, +} + /// Sync status #[derive(Debug, PartialEq)] pub enum SyncStatus { @@ -53,7 +64,7 @@ impl Serialize for SyncStatus { #[cfg(test)] mod tests { use serde_json; - use super::{SyncInfo, SyncStatus}; + use super::{SyncInfo, SyncStatus, Peers}; #[test] fn test_serialize_sync_info() { @@ -62,6 +73,13 @@ mod tests { assert_eq!(serialized, r#"{"startingBlock":"0x00","currentBlock":"0x00","highestBlock":"0x00"}"#); } + #[test] + fn test_serialize_peers() { + let t = Peers::default(); + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!(serialized, r#"{"active":0,"connected":0,"max":0}"#); + } + #[test] fn test_serialize_sync_status() { let t = SyncStatus::None; diff --git a/signer/Cargo.toml b/signer/Cargo.toml index 5d433cedc..90d531b4c 100644 --- a/signer/Cargo.toml +++ b/signer/Cargo.toml @@ -12,14 +12,14 @@ rustc_version = "0.1" [dependencies] rand = "0.3.14" -jsonrpc-core = "2.0" +jsonrpc-core = "2.1" log = "0.3" env_logger = "0.3" ws = { git = "https://github.com/ethcore/ws-rs.git", branch = "mio-upstream-stable" } ethcore-util = { path = "../util" } ethcore-io = { path = "../util/io" } ethcore-rpc = { path = "../rpc" } -parity-dapps-signer = { git = "https://github.com/ethcore/parity-ui.git", version = "0.6", optional = true} +parity-dapps-signer = { git = "https://github.com/ethcore/parity-ui.git", version = "1.4", optional = true} clippy = { version = "0.0.80", optional = true} diff --git a/sync/src/api.rs b/sync/src/api.rs index c3dc3bf4a..4603ac52e 100644 --- a/sync/src/api.rs +++ b/sync/src/api.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::ops::*; use std::sync::Arc; use network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId, NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, NetworkError}; @@ -75,7 +74,7 @@ pub struct EthSync { impl EthSync { /// Creates and register protocol with the network service pub fn new(config: SyncConfig, chain: Arc, network_config: NetworkConfiguration) -> Result, NetworkError> { - let chain_sync = ChainSync::new(config, chain.deref()); + let chain_sync = ChainSync::new(config, &*chain); let service = try!(NetworkService::new(try!(network_config.into_basic()))); let sync = Arc::new(EthSync{ network: service, @@ -108,20 +107,20 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { - ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, self.chain.deref()), *peer, packet_id, data); + ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, &*self.chain), *peer, packet_id, data); } fn connected(&self, io: &NetworkContext, peer: &PeerId) { - self.sync.write().on_peer_connected(&mut NetSyncIo::new(io, self.chain.deref()), *peer); + self.sync.write().on_peer_connected(&mut NetSyncIo::new(io, &*self.chain), *peer); } fn disconnected(&self, io: &NetworkContext, peer: &PeerId) { - self.sync.write().on_peer_aborting(&mut NetSyncIo::new(io, self.chain.deref()), *peer); + self.sync.write().on_peer_aborting(&mut NetSyncIo::new(io, &*self.chain), *peer); } fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { - self.sync.write().maintain_peers(&mut NetSyncIo::new(io, self.chain.deref())); - self.sync.write().maintain_sync(&mut NetSyncIo::new(io, self.chain.deref())); + self.sync.write().maintain_peers(&mut NetSyncIo::new(io, &*self.chain)); + self.sync.write().maintain_sync(&mut NetSyncIo::new(io, &*self.chain)); } } @@ -135,7 +134,7 @@ impl ChainNotify for EthSync { _duration: u64) { self.network.with_context(ETH_PROTOCOL, |context| { - let mut sync_io = NetSyncIo::new(context, self.handler.chain.deref()); + let mut sync_io = NetSyncIo::new(context, &*self.handler.chain); self.handler.sync.write().chain_new_blocks( &mut sync_io, &imported, @@ -204,7 +203,7 @@ impl ManageNetwork for EthSync { fn stop_network(&self) { self.network.with_context(ETH_PROTOCOL, |context| { - let mut sync_io = NetSyncIo::new(context, self.handler.chain.deref()); + let mut sync_io = NetSyncIo::new(context, &*self.handler.chain); self.handler.sync.write().abort(&mut sync_io); }); self.stop(); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 71d27127b..80ed82596 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -187,6 +187,15 @@ impl SyncStatus { pub fn is_major_syncing(&self) -> bool { self.state != SyncState::Idle && self.state != SyncState::NewBlocks } + + /// Returns max no of peers to display in informants + pub fn current_max_peers(&self, min_peers: u32, max_peers: u32) -> u32 { + if self.num_peers as u32 > min_peers { + max_peers + } else { + min_peers + } + } } #[derive(PartialEq, Eq, Debug, Clone)] @@ -1760,7 +1769,7 @@ mod tests { let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - let peers = sync.get_lagging_peers(&chain_info, &mut io); + let peers = sync.get_lagging_peers(&chain_info, &io); let peer_count = sync.propagate_new_hashes(&chain_info, &mut io, &peers); // 1 message should be send @@ -1779,7 +1788,7 @@ mod tests { let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - let peers = sync.get_lagging_peers(&chain_info, &mut io); + let peers = sync.get_lagging_peers(&chain_info, &io); let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[], &peers); // 1 message should be send @@ -1799,7 +1808,7 @@ mod tests { let mut sync = dummy_sync_with_peer(client.block_hash_delta_minus(5), &client); let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - let peers = sync.get_lagging_peers(&chain_info, &mut io); + let peers = sync.get_lagging_peers(&chain_info, &io); let peer_count = sync.propagate_blocks(&chain_info, &mut io, &[hash.clone()], &peers); // 1 message should be send @@ -1906,7 +1915,7 @@ mod tests { let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - let peers = sync.get_lagging_peers(&chain_info, &mut io); + let peers = sync.get_lagging_peers(&chain_info, &io); sync.propagate_new_hashes(&chain_info, &mut io, &peers); let data = &io.queue[0].data.clone(); @@ -1925,7 +1934,7 @@ mod tests { let chain_info = client.chain_info(); let mut io = TestIo::new(&mut client, &mut queue, None); - let peers = sync.get_lagging_peers(&chain_info, &mut io); + let peers = sync.get_lagging_peers(&chain_info, &io); sync.propagate_blocks(&chain_info, &mut io, &[], &peers); let data = &io.queue[0].data.clone(); diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 94dcc2a9d..d8d3d0711 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -27,7 +27,7 @@ fn two_peers() { net.peer_mut(2).chain.add_blocks(1000, EachBlockWith::Uncle); net.sync(); assert!(net.peer(0).chain.block(BlockID::Number(1000)).is_some()); - assert_eq!(net.peer(0).chain.blocks.read().deref(), net.peer(1).chain.blocks.read().deref()); + assert_eq!(*net.peer(0).chain.blocks.read(), *net.peer(1).chain.blocks.read()); } #[test] @@ -37,7 +37,7 @@ fn long_chain() { net.peer_mut(1).chain.add_blocks(50000, EachBlockWith::Nothing); net.sync(); assert!(net.peer(0).chain.block(BlockID::Number(50000)).is_some()); - assert_eq!(net.peer(0).chain.blocks.read().deref(), net.peer(1).chain.blocks.read().deref()); + assert_eq!(*net.peer(0).chain.blocks.read(), *net.peer(1).chain.blocks.read()); } #[test] @@ -71,7 +71,7 @@ fn empty_blocks() { } net.sync(); assert!(net.peer(0).chain.block(BlockID::Number(1000)).is_some()); - assert_eq!(net.peer(0).chain.blocks.read().deref(), net.peer(1).chain.blocks.read().deref()); + assert_eq!(*net.peer(0).chain.blocks.read(), *net.peer(1).chain.blocks.read()); } #[test] @@ -89,10 +89,10 @@ fn forked() { // peer 1 has the best chain of 601 blocks let peer1_chain = net.peer(1).chain.numbers.read().clone(); net.sync(); - assert_eq!(net.peer(0).chain.difficulty.read().deref(), net.peer(1).chain.difficulty.read().deref()); - assert_eq!(net.peer(0).chain.numbers.read().deref(), &peer1_chain); - assert_eq!(net.peer(1).chain.numbers.read().deref(), &peer1_chain); - assert_eq!(net.peer(2).chain.numbers.read().deref(), &peer1_chain); + assert_eq!(*net.peer(0).chain.difficulty.read(), *net.peer(1).chain.difficulty.read()); + assert_eq!(&*net.peer(0).chain.numbers.read(), &peer1_chain); + assert_eq!(&*net.peer(1).chain.numbers.read(), &peer1_chain); + assert_eq!(&*net.peer(2).chain.numbers.read(), &peer1_chain); } #[test] @@ -222,3 +222,4 @@ fn high_td_attach() { assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5); } + diff --git a/test.sh b/test.sh index 773a7127e..666f10d06 100755 --- a/test.sh +++ b/test.sh @@ -1,11 +1,11 @@ #!/bin/sh # Running Parity Full Test Sute -FEATURES="--features json-tests" +FEATURES="json-tests ipc" case $1 in --no-json) - FEATURES="" + FEATURES="ipc" shift # past argument=value ;; *) @@ -14,5 +14,5 @@ case $1 in esac . ./scripts/targets.sh -cargo test --release $FEATURES $TARGETS $1 \ +cargo test --release --features "$FEATURES" $TARGETS $1 \ diff --git a/util/io/src/panics.rs b/util/io/src/panics.rs index 8db875bdf..f67e925a7 100644 --- a/util/io/src/panics.rs +++ b/util/io/src/panics.rs @@ -17,7 +17,6 @@ //! Panic utilities use std::thread; -use std::ops::DerefMut; use std::sync::Arc; use std::default::Default; @@ -91,7 +90,7 @@ impl PanicHandler { /// You should use `catch_panic` instead of calling this method explicitly. pub fn notify_all(&self, r: String) { let mut listeners = self.listeners.lock(); - for listener in listeners.deref_mut() { + for mut listener in &mut **listeners { listener.call(&r); } } diff --git a/util/network/src/host.rs b/util/network/src/host.rs index bc5e5e6ca..dfadd12d8 100644 --- a/util/network/src/host.rs +++ b/util/network/src/host.rs @@ -787,7 +787,7 @@ impl Host { let entry = NodeEntry { id: s.id().unwrap().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } }; self.nodes.write().add_node(Node::new(entry.id.clone(), entry.endpoint.clone())); let mut discovery = self.discovery.lock(); - if let Some(ref mut discovery) = *discovery.deref_mut() { + if let Some(ref mut discovery) = *discovery { discovery.add_node(entry); } } diff --git a/util/network/src/tests.rs b/util/network/src/tests.rs index 9c3753813..3a19cbbab 100644 --- a/util/network/src/tests.rs +++ b/util/network/src/tests.rs @@ -46,7 +46,7 @@ impl TestProtocol { } pub fn got_packet(&self) -> bool { - self.packet.lock().deref()[..] == b"hello"[..] + self.packet.lock()[..] == b"hello"[..] } pub fn got_timeout(&self) -> bool { diff --git a/util/src/hash.rs b/util/src/hash.rs index 690c37b8f..7bc12f2e9 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -577,9 +577,9 @@ impl Hasher for PlainHasher { } } -/// Specialized version of HashMap with H256 keys and fast hashing function. +/// Specialized version of `HashMap` with H256 keys and fast hashing function. pub type H256FastMap = HashMap>; -/// Specialized version of HashSet with H256 keys and fast hashing function. +/// Specialized version of `HashSet` with H256 keys and fast hashing function. pub type H256FastSet = HashSet>; #[cfg(test)] diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 17c3b82fa..1ec46233c 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -74,7 +74,7 @@ impl HashDB for ArchiveDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter(self.column) { - let h = H256::from_slice(key.deref()); + let h = H256::from_slice(&*key); ret.insert(h, 1); } diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index a5cbfc83f..8e890b2a1 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -263,7 +263,7 @@ impl HashDB for EarlyMergeDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter(self.column) { - let h = H256::from_slice(key.deref()); + let h = H256::from_slice(&*key); ret.insert(h, 1); } diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index 97fa5959a..5143b9999 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -66,7 +66,8 @@ pub struct OverlayRecentDB { #[derive(PartialEq)] struct JournalOverlay { - backing_overlay: MemoryDB, + backing_overlay: MemoryDB, // Nodes added in the history period + pending_overlay: H256FastMap, // Nodes being transfered from backing_overlay to backing db journal: HashMap>, latest_era: Option, } @@ -173,7 +174,11 @@ impl OverlayRecentDB { } } trace!("Recovered {} overlay entries, {} journal entries", count, journal.len()); - JournalOverlay { backing_overlay: overlay, journal: journal, latest_era: latest_era } + JournalOverlay { + backing_overlay: overlay, + pending_overlay: HashMap::default(), + journal: journal, + latest_era: latest_era } } } @@ -194,6 +199,7 @@ impl JournalDB for OverlayRecentDB { let mut mem = self.transaction_overlay.mem_used(); let overlay = self.journal_overlay.read(); mem += overlay.backing_overlay.mem_used(); + mem += overlay.pending_overlay.heap_size_of_children(); mem += overlay.journal.heap_size_of_children(); mem } @@ -209,14 +215,19 @@ impl JournalDB for OverlayRecentDB { fn latest_era(&self) -> Option { self.journal_overlay.read().latest_era } fn state(&self, key: &H256) -> Option { - let v = self.journal_overlay.read().backing_overlay.get(&to_short_key(key)).map(|v| v.to_vec()); - v.or_else(|| self.backing.get_by_prefix(self.column, &key[0..DB_PREFIX_LEN]).map(|b| b.to_vec())) + let journal_overlay = self.journal_overlay.read(); + let key = to_short_key(key); + journal_overlay.backing_overlay.get(&key).map(|v| v.to_vec()) + .or_else(|| journal_overlay.pending_overlay.get(&key).map(|v| v.clone())) + .or_else(|| self.backing.get_by_prefix(self.column, &key[0..DB_PREFIX_LEN]).map(|b| b.to_vec())) } fn commit(&mut self, batch: &DBTransaction, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // record new commit's details. trace!("commit: #{} ({}), end era: {:?}", now, id, end); let mut journal_overlay = self.journal_overlay.write(); + // flush previous changes + journal_overlay.pending_overlay.clear(); { let mut r = RlpStream::new_list(3); let mut tx = self.transaction_overlay.drain(); @@ -280,7 +291,8 @@ impl JournalDB for OverlayRecentDB { } // apply canon inserts first for (k, v) in canon_insertions { - try!(batch.put_vec(self.column, &k, v)); + try!(batch.put(self.column, &k, &v)); + journal_overlay.pending_overlay.insert(to_short_key(&k), v); } // update the overlay for k in overlay_deletions { @@ -298,6 +310,10 @@ impl JournalDB for OverlayRecentDB { Ok(0) } + fn flush(&self) { + self.journal_overlay.write().pending_overlay.clear(); + } + fn inject(&mut self, batch: &DBTransaction) -> Result { let mut ops = 0; for (key, (value, rc)) in self.transaction_overlay.drain() { @@ -329,7 +345,7 @@ impl HashDB for OverlayRecentDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter(self.column) { - let h = H256::from_slice(key.deref()); + let h = H256::from_slice(&*key); ret.insert(h, 1); } @@ -345,14 +361,19 @@ impl HashDB for OverlayRecentDB { match k { Some((d, rc)) if rc > 0 => Some(d), _ => { - let v = self.journal_overlay.read().backing_overlay.get(&to_short_key(key)).map(|v| v.to_vec()); + let v = { + let journal_overlay = self.journal_overlay.read(); + let key = to_short_key(key); + journal_overlay.backing_overlay.get(&key).map(|v| v.to_vec()) + .or_else(|| journal_overlay.pending_overlay.get(&key).map(|v| v.clone())) + }; match v { Some(x) => { - Some(&self.transaction_overlay.denote(key, x).0) + Some(self.transaction_overlay.denote(key, x).0) } _ => { if let Some(x) = self.payload(key) { - Some(&self.transaction_overlay.denote(key, x).0) + Some(self.transaction_overlay.denote(key, x).0) } else { None @@ -920,4 +941,4 @@ mod tests { assert!(jdb.get(&key).is_none()); } -} \ No newline at end of file +} diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index b29a45212..9b837d68d 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -190,7 +190,7 @@ impl JournalDB for RefCountedDB { for remove in self.removes.drain(..) { self.forward.remove(&remove); } - self.forward.commit_to_batch(&batch) + self.forward.commit_to_batch(batch) } } diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index 2d3047a22..96715604e 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -57,12 +57,18 @@ pub trait JournalDB: HashDB { /// Get backing database. fn backing(&self) -> &Arc; + /// Clear internal strucutres. This should called after changes have been written + /// to the backing strage + fn flush(&self) {} + /// Commit all changes in a single batch #[cfg(test)] fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { let batch = self.backing().transaction(); let res = try!(self.commit(&batch, now, id, end)); - self.backing().write(batch).map(|_| res).map_err(Into::into) + let result = self.backing().write(batch).map(|_| res).map_err(Into::into); + self.flush(); + result } /// Inject all changes in a single batch. diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index f88e74034..0aa48e45f 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -105,10 +105,10 @@ impl DBTransaction { } } -struct DBColumnOverlay { - insertions: HashMap, Bytes>, - compressed_insertions: HashMap, Bytes>, - deletions: HashSet>, +enum KeyState { + Insert(Bytes), + InsertCompressed(Bytes), + Delete, } /// Compaction profile for the database settings @@ -198,7 +198,7 @@ pub struct Database { db: DB, write_opts: WriteOptions, cfs: Vec, - overlay: RwLock>, + overlay: RwLock, KeyState>>>, } impl Database { @@ -275,11 +275,7 @@ impl Database { Ok(Database { db: db, write_opts: write_opts, - overlay: RwLock::new((0..(cfs.len() + 1)).map(|_| DBColumnOverlay { - insertions: HashMap::new(), - compressed_insertions: HashMap::new(), - deletions: HashSet::new(), - }).collect()), + overlay: RwLock::new((0..(cfs.len() + 1)).map(|_| HashMap::new()).collect()), cfs: cfs, }) } @@ -302,21 +298,15 @@ impl Database { match op { DBOp::Insert { col, key, value } => { let c = Self::to_overlay_column(col); - overlay[c].deletions.remove(&key); - overlay[c].compressed_insertions.remove(&key); - overlay[c].insertions.insert(key, value); + overlay[c].insert(key, KeyState::Insert(value)); }, DBOp::InsertCompressed { col, key, value } => { let c = Self::to_overlay_column(col); - overlay[c].deletions.remove(&key); - overlay[c].insertions.remove(&key); - overlay[c].compressed_insertions.insert(key, value); + overlay[c].insert(key, KeyState::InsertCompressed(value)); }, DBOp::Delete { col, key } => { let c = Self::to_overlay_column(col); - overlay[c].insertions.remove(&key); - overlay[c].compressed_insertions.remove(&key); - overlay[c].deletions.insert(key); + overlay[c].insert(key, KeyState::Delete); }, } }; @@ -328,34 +318,34 @@ impl Database { let batch = WriteBatch::new(); let mut overlay = self.overlay.write(); - let mut c = 0; - for column in overlay.iter_mut() { - let insertions = mem::replace(&mut column.insertions, HashMap::new()); - let compressed_insertions = mem::replace(&mut column.compressed_insertions, HashMap::new()); - let deletions = mem::replace(&mut column.deletions, HashSet::new()); - for d in deletions.into_iter() { - if c > 0 { - try!(batch.delete_cf(self.cfs[c - 1], &d)); - } else { - try!(batch.delete(&d)); + for (c, column) in overlay.iter_mut().enumerate() { + let column_data = mem::replace(column, HashMap::new()); + for (key, state) in column_data.into_iter() { + match state { + KeyState::Delete => { + if c > 0 { + try!(batch.delete_cf(self.cfs[c - 1], &key)); + } else { + try!(batch.delete(&key)); + } + }, + KeyState::Insert(value) => { + if c > 0 { + try!(batch.put_cf(self.cfs[c - 1], &key, &value)); + } else { + try!(batch.put(&key, &value)); + } + }, + KeyState::InsertCompressed(value) => { + let compressed = UntrustedRlp::new(&value).compress(RlpType::Blocks); + if c > 0 { + try!(batch.put_cf(self.cfs[c - 1], &key, &compressed)); + } else { + try!(batch.put(&key, &value)); + } + } } } - for (key, value) in insertions.into_iter() { - if c > 0 { - try!(batch.put_cf(self.cfs[c - 1], &key, &value)); - } else { - try!(batch.put(&key, &value)); - } - } - for (key, value) in compressed_insertions.into_iter() { - let compressed = UntrustedRlp::new(&value).compress(RlpType::Blocks); - if c > 0 { - try!(batch.put_cf(self.cfs[c - 1], &key, &compressed)); - } else { - try!(batch.put(&key, &compressed)); - } - } - c += 1; } self.db.write_opt(batch, &self.write_opts) } @@ -385,14 +375,19 @@ impl Database { /// Get value by key. pub fn get(&self, col: Option, key: &[u8]) -> Result, String> { let overlay = &self.overlay.read()[Self::to_overlay_column(col)]; - overlay.insertions.get(key).or_else(|| overlay.compressed_insertions.get(key)).map_or_else(|| - col.map_or_else( - || self.db.get(key).map(|r| r.map(|v| v.to_vec())), - |c| self.db.get_cf(self.cfs[c as usize], key).map(|r| r.map(|v| v.to_vec()))), - |value| Ok(Some(value.clone()))) + match overlay.get(key) { + Some(&KeyState::Insert(ref value)) | Some(&KeyState::InsertCompressed(ref value)) => Ok(Some(value.clone())), + Some(&KeyState::Delete) => Ok(None), + None => { + col.map_or_else( + || self.db.get(key).map(|r| r.map(|v| v.to_vec())), + |c| self.db.get_cf(self.cfs[c as usize], key).map(|r| r.map(|v| v.to_vec()))) + }, + } } - /// Get value by partial key. Prefix size should match configured prefix size. + /// Get value by partial key. Prefix size should match configured prefix size. Only searches flushed values. + // TODO: support prefix seek for unflushed ata pub fn get_by_prefix(&self, col: Option, prefix: &[u8]) -> Option> { let mut iter = col.map_or_else(|| self.db.iterator(IteratorMode::From(prefix, Direction::Forward)), |c| self.db.iterator_cf(self.cfs[c as usize], IteratorMode::From(prefix, Direction::Forward)).unwrap()); @@ -403,13 +398,9 @@ impl Database { } } - /// Check if there is anything in the database. - pub fn is_empty(&self, col: Option) -> bool { - self.iter(col).next().is_none() - } - - /// Get database iterator. + /// Get database iterator for flushed data. pub fn iter(&self, col: Option) -> DatabaseIterator { + //TODO: iterate over overlay col.map_or_else(|| DatabaseIterator { iter: self.db.iterator(IteratorMode::Start) }, |c| DatabaseIterator { iter: self.db.iterator_cf(self.cfs[c as usize], IteratorMode::Start).unwrap() }) } @@ -421,7 +412,6 @@ mod tests { use super::*; use devtools::*; use std::str::FromStr; - use std::ops::Deref; fn test_db(config: &DatabaseConfig) { let path = RandomTempPath::create_dir(); @@ -435,13 +425,13 @@ mod tests { batch.put(None, &key2, b"dog").unwrap(); db.write(batch).unwrap(); - assert_eq!(db.get(None, &key1).unwrap().unwrap().deref(), b"cat"); + assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"cat"); let contents: Vec<_> = db.iter(None).collect(); assert_eq!(contents.len(), 2); - assert_eq!(&*contents[0].0, key1.deref()); + assert_eq!(&*contents[0].0, &*key1); assert_eq!(&*contents[0].1, b"cat"); - assert_eq!(&*contents[1].0, key2.deref()); + assert_eq!(&*contents[1].0, &*key2); assert_eq!(&*contents[1].1, b"dog"); let batch = db.transaction(); @@ -459,17 +449,27 @@ mod tests { transaction.delete(None, &key1).unwrap(); db.write(transaction).unwrap(); assert!(db.get(None, &key1).unwrap().is_none()); - assert_eq!(db.get(None, &key3).unwrap().unwrap().deref(), b"elephant"); + assert_eq!(&*db.get(None, &key3).unwrap().unwrap(), b"elephant"); - assert_eq!(db.get_by_prefix(None, &key3).unwrap().deref(), b"elephant"); - assert_eq!(db.get_by_prefix(None, &key2).unwrap().deref(), b"dog"); + assert_eq!(&*db.get_by_prefix(None, &key3).unwrap(), b"elephant"); + assert_eq!(&*db.get_by_prefix(None, &key2).unwrap(), b"dog"); + + let transaction = db.transaction(); + transaction.put(None, &key1, b"horse").unwrap(); + transaction.delete(None, &key3).unwrap(); + db.write_buffered(transaction).unwrap(); + assert!(db.get(None, &key3).unwrap().is_none()); + assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"horse"); + + db.flush().unwrap(); + assert!(db.get(None, &key3).unwrap().is_none()); + assert_eq!(&*db.get(None, &key1).unwrap().unwrap(), b"horse"); } #[test] fn kvdb() { let path = RandomTempPath::create_dir(); - let smoke = Database::open_default(path.as_path().to_str().unwrap()).unwrap(); - assert!(smoke.is_empty(None)); + let _ = Database::open_default(path.as_path().to_str().unwrap()).unwrap(); test_db(&DatabaseConfig::default()); } } diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index 7310ef536..bce0a83e8 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -22,7 +22,6 @@ use bytes::*; use rlp::*; use hashdb::*; use memorydb::*; -use std::ops::*; use std::sync::*; use std::collections::HashMap; use kvdb::{Database, DBTransaction}; @@ -130,7 +129,7 @@ impl HashDB for OverlayDB { fn keys(&self) -> HashMap { let mut ret: HashMap = HashMap::new(); for (key, _) in self.backing.iter(self.column) { - let h = H256::from_slice(key.deref()); + let h = H256::from_slice(&*key); let r = self.payload(&h).unwrap().1; ret.insert(h, r as i32); } @@ -305,7 +304,7 @@ fn playpen() { batch.put(None, b"test", b"test2").unwrap(); db.write(batch).unwrap(); match db.get(None, b"test") { - Ok(Some(value)) => println!("Got value {:?}", value.deref()), + Ok(Some(value)) => println!("Got value {:?}", &*value), Ok(None) => println!("No value for that key"), Err(..) => println!("Gah"), } @@ -314,4 +313,4 @@ fn playpen() { db.write(batch).unwrap(); } fs::remove_dir_all("/tmp/test").unwrap(); -} \ No newline at end of file +} diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index 5da3a3822..eb70a7c13 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::ops::Deref; -use std::default::Default; use elastic_array::*; use rlp::bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; @@ -293,7 +291,7 @@ impl<'a> Encodable for &'a[u8] { impl Encodable for Vec { fn rlp_append(&self, s: &mut RlpStream) { - s.append_value(&U8Slice(self.deref())) + s.append_value(&U8Slice(self)) } } @@ -334,7 +332,7 @@ impl<'a, T> Encodable for &'a[T] where T: Encodable { impl Encodable for Vec where T: Encodable { fn rlp_append(&self, s: &mut RlpStream) { - Encodable::rlp_append(&self.deref(), s); + Encodable::rlp_append(&self.as_slice(), s); } } diff --git a/util/src/rlp/rlptraits.rs b/util/src/rlp/rlptraits.rs index 1e6ef5917..5eca7ca03 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -15,7 +15,6 @@ // along with Parity. If not, see . //! Common RLP traits -use std::ops::Deref; use rlp::bytes::VecLike; use rlp::{DecoderError, UntrustedRlp}; use rlp::rlpstream::RlpStream; @@ -244,7 +243,7 @@ pub trait ByteEncodable { fn bytes_len(&self) -> usize; } -/// Structure encodable to RLP. Implement this trait for +/// Structure encodable to RLP. Implement this trait for pub trait Encodable { /// Append a value to the stream fn rlp_append(&self, s: &mut RlpStream); @@ -257,7 +256,7 @@ pub trait Encodable { } /// Get the hash or RLP encoded representation - fn rlp_sha3(&self) -> H256 { self.rlp_bytes().deref().sha3() } + fn rlp_sha3(&self) -> H256 { (&*self.rlp_bytes()).sha3() } } /// Encodable wrapper trait required to handle special case of encoding a &[u8] as string and not as list diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index f7704c387..ec0d9a59f 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -192,7 +192,7 @@ impl<'db> TrieDB<'db> { where 'db: 'key { let root_rlp = try!(self.root_data()); - self.get_from_node(&root_rlp, key) + self.get_from_node(root_rlp, key) } /// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no