diff --git a/Cargo.lock b/Cargo.lock index 6b2a7b494..ba5b4021a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,7 +311,7 @@ version = "0.5.6" source = "git+https://github.com/paritytech/rust-secp256k1#b6b67055edc929057e97d64f036c78ad91f58a7f" dependencies = [ "arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -794,7 +794,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -824,10 +824,10 @@ dependencies = [ [[package]] name = "gcc" -version = "0.3.43" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -900,7 +900,7 @@ name = "hidapi" version = "0.3.1" source = "git+https://github.com/paritytech/hidapi-rs#9a127c1dca7e327e4fdd428406a76c9f5ef48563" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1193,7 +1193,7 @@ name = "libusb-sys" version = "0.2.3" source = "git+https://github.com/paritytech/libusb-sys#c10b1180646c9dc3f23a9b6bb825abcd3b7487ce" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1264,10 +1264,10 @@ dependencies = [ [[package]] name = "miniz-sys" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1372,7 +1372,7 @@ name = "nanomsg-sys" version = "0.5.0" source = "git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7#673b79beef6e149273899850d7692335a481a920" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1545,7 +1545,7 @@ name = "openssl-sys" version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1824,7 +1824,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#7dc30d69a4e15b1fc22d3d25939a177f0979df07" +source = "git+https://github.com/paritytech/js-precompiled.git#d046d5b5393e90617f4d9a51a5af90fbe516793d" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2036,17 +2036,6 @@ dependencies = [ "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rayon" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rayon" version = "0.7.0" @@ -2109,7 +2098,7 @@ name = "ring" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2142,7 +2131,7 @@ name = "rocksdb-sys" version = "0.3.0" source = "git+https://github.com/paritytech/rust-rocksdb#4364caec4dd5da1a1d78c39276774ee65bf55c7d" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2197,7 +2186,7 @@ name = "rust-crypto" version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2359,7 +2348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "sha3" version = "0.1.0" dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2934,7 +2923,7 @@ dependencies = [ "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" "checksum futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8e51e7f9c150ba7fd4cee9df8bf6ea3dea5b63b68955ddad19ccd35b71dcfb4d" "checksum futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bb982bb25cd8fa5da6a8eb3a460354c984ff1113da82bcb4f0b0862b5795db82" -"checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d" +"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" @@ -2981,7 +2970,7 @@ dependencies = [ "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74cc2587bf97c49f3f5bab62860d6abf3902ca73b66b51d9b049fbdcd727bd2" "checksum mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e50bf542f81754ef69e5cea856946a3819f7c09ea97b4903c8bc8a89f74e7b6" -"checksum miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1f4d337a01c32e1f2122510fed46393d53ca35a7f429cb0450abaedfa3ed54" +"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" "checksum mio 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ba718a36791275c6782c0445a5f79b5ef4e68c01a4e60ac04aae28290e4957" "checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "" "checksum mio-uds 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "78437f00d9615c366932cbfe79790b5c2945706ba67cf78378ffacc0069ed9de" @@ -3037,7 +3026,6 @@ dependencies = [ "checksum quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6683b0e23d80813b1a535841f0048c1537d3f86d63c999e8373b39a9b0eb74a" "checksum quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6732e32663c9c271bfc7c1823486b471f18c47a2dbf87c066897b7b51afc83be" "checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" -"checksum rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50c575b58c2b109e2fbc181820cbe177474f35610ff9e357dc75f6bac854ffbf" "checksum rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c83adcb08e5b922e804fe1918142b422602ef11f2fd670b0b52218cb5984a20" "checksum rayon-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "767d91bacddf07d442fe39257bf04fd95897d1c47c545d009f6beb03efd038f8" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 78f1efde4..3b48ab321 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -453,11 +453,14 @@ impl Ethash { let parent_has_uncles = parent.uncles_hash() != &sha3::SHA3_EMPTY_LIST_RLP; let min_difficulty = self.ethash_params.minimum_difficulty; + let difficulty_hardfork = header.number() >= self.ethash_params.difficulty_hardfork_transition; - let difficulty_bound_divisor = match difficulty_hardfork { - true => self.ethash_params.difficulty_hardfork_bound_divisor, - false => self.ethash_params.difficulty_bound_divisor, + let difficulty_bound_divisor = if difficulty_hardfork { + self.ethash_params.difficulty_hardfork_bound_divisor + } else { + self.ethash_params.difficulty_bound_divisor }; + let duration_limit = self.ethash_params.duration_limit; let frontier_limit = self.ethash_params.homestead_transition; @@ -483,7 +486,10 @@ impl Ethash { if diff_inc <= threshold { *parent.difficulty() + *parent.difficulty() / difficulty_bound_divisor * (threshold - diff_inc).into() } else { - *parent.difficulty() - *parent.difficulty() / difficulty_bound_divisor * min(diff_inc - threshold, 99).into() + let multiplier = min(diff_inc - threshold, 99).into(); + parent.difficulty().saturating_sub( + *parent.difficulty() / difficulty_bound_divisor * multiplier + ) } }; target = max(min_difficulty, target); diff --git a/ethkey/cli/Cargo.toml b/ethkey/cli/Cargo.toml index 3ea931e25..b8183e674 100644 --- a/ethkey/cli/Cargo.toml +++ b/ethkey/cli/Cargo.toml @@ -7,8 +7,8 @@ authors = ["Parity Technologies "] ethkey = { path = "../" } serde = "1.0" serde_derive = "1.0" -rustc-hex = "1.0" docopt = "0.8" +rustc-hex = "1.0" [[bin]] name = "ethkey" diff --git a/js/package.json b/js/package.json index 36fc6754e..0c22c0c3a 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.7.96", + "version": "1.7.97", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", diff --git a/js/src/api/api.js b/js/src/api/api.js index 9a208ade9..220c3be29 100644 --- a/js/src/api/api.js +++ b/js/src/api/api.js @@ -21,6 +21,7 @@ import Contract from './contract'; import { Db, Eth, Parity, Net, Personal, Shh, Signer, Trace, Web3 } from './rpc'; import Subscriptions from './subscriptions'; +import Pubsub from './pubsub'; import util from './util'; import { isFunction } from './util/types'; @@ -46,10 +47,13 @@ export default class Api extends EventEmitter { this._trace = new Trace(transport); this._web3 = new Web3(transport); + if (isFunction(transport.subscribe)) { + this._pubsub = new Pubsub(transport); + } + if (allowSubscriptions) { this._subscriptions = new Subscriptions(this); } - // Doing a request here in test env would cause an error if (LocalAccountsMiddleware && process.env.NODE_ENV !== 'test') { const middleware = this.parity @@ -67,6 +71,13 @@ export default class Api extends EventEmitter { } } + get pubsub () { + if (!this._pubsub) { + throw Error('Pubsub is only available with a subscribing-supported transport injected!'); + } + return this._pubsub; + } + get db () { return this._db; } diff --git a/js/src/api/pubsub/eth/eth.js b/js/src/api/pubsub/eth/eth.js new file mode 100644 index 000000000..0bbc85bec --- /dev/null +++ b/js/src/api/pubsub/eth/eth.js @@ -0,0 +1,227 @@ +// Copyright 2015-2017 Parity Technologies (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 . +import PubsubBase from '../pubsubBase'; + +import { inAddress, inBlockNumber, inHex, inNumber16, inOptions, inFilter } from '../../format/input'; +import { outAddress, outBlock, outNumber, outTransaction, outSyncing, outReceipt, outLog } from '../../format/output'; + +export default class Eth extends PubsubBase { + constructor (transport) { + super(transport); + this._api = 'parity'; + } + + newHeads (callback) { + return this.addListener('eth', 'newHeads', callback); + } + + logs (callback) { + throw Error('not supported yet'); + } + + // eth API + protocolVersion (callback) { + return this.addListener(this._api, 'eth_protocolVersion', callback); + } + + syncing (callback) { + return this.addListener(this._api, 'eth_syncing', (error, data) => { + error + ? callback(error) + : callback(null, outSyncing(data)); + }); + } + + hashrate (callback) { + return this.addListener(this._api, 'eth_hashrate', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + coinbase (callback) { + return this.addListener(this._api, 'eth_coinbase', (error, data) => { + error + ? callback(error) + : callback(null, outAddress(data)); + }); + } + + mining (callback) { + return this.addListener(this._api, 'eth_mining', callback); + } + + gasPrice (callback) { + return this.addListener(this._api, 'eth_gasPrice', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + accounts (callback) { + return this.addListener(this._api, 'eth_accounts', (error, accounts) => { + error + ? callback(error) + : callback(null, (accounts || []).map(outAddress)); + }); + } + + blockNumber (callback) { + return this.addListener(this._api, 'eth_blockNumber', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + getBalance (callback, address, blockNumber = 'latest') { + return this.addListener(this._api, 'eth_getBalance', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inAddress(address), inBlockNumber(blockNumber)]); + } + + getStorageAt (callback, address, index = 0, blockNumber = 'latest') { + return this.addListener(this._api, 'eth_getStorageAt', callback, [inAddress(address), inNumber16(index), inBlockNumber(blockNumber)]); + } + + getBlockByHash (callback, hash, full = false) { + return this.addListener(this._api, 'eth_getBlockByHash', (error, data) => { + error + ? callback(error) + : callback(null, outBlock(data)); + }, [inHex(hash), full]); + } + + getBlockByNumber (callback, blockNumber = 'latest', full = false) { + return this.addListener(this._api, 'eth_getBlockByNumber', (error, data) => { + error + ? callback(error) + : callback(null, outBlock(data)); + }, [inBlockNumber(blockNumber), full]); + } + + getTransactionCount (callback, address, blockNumber = 'latest') { + return this.addListener(this._api, 'eth_getTransactionCount', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inAddress(address), inBlockNumber(blockNumber)]); + } + + getBlockTransactionCountByHash (callback, hash) { + return this.addListener(this._api, 'eth_getBlockTransactionCountByHash', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inHex(hash)]); + } + + getBlockTransactionCountByNumber (callback, blockNumber = 'latest') { + return this.addListener(this._api, 'eth_getBlockTransactionCountByNumber', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inBlockNumber(blockNumber)]); + } + + getUncleCountByBlockHash (callback, hash) { + return this.addListener(this._api, 'eth_getUncleCountByBlockHash', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inHex(hash)]); + } + + getUncleCountByBlockNumber (callback, blockNumber = 'latest') { + return this.addListener(this._api, 'eth_getUncleCountByBlockNumber', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inBlockNumber(blockNumber)]); + } + + getCode (callback, address, blockNumber = 'latest') { + return this.addListener(this._api, 'eth_getCode', callback, [inAddress(address), inBlockNumber(blockNumber)]); + } + + call (callback, options, blockNumber = 'latest') { + return this.addListener(this._api, 'eth_call', callback, [inOptions(options), inBlockNumber(blockNumber)]); + } + + estimateGas (callback, options) { + return this.addListener(this._api, 'eth_estimateGas', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inOptions(options)]); + } + + getTransactionByHash (callback, hash) { + return this.addListener(this._api, 'eth_getTransactionByHash', (error, data) => { + error + ? callback(error) + : callback(null, outTransaction(data)); + }, [inHex(hash)]); + } + + getTransactionByBlockHashAndIndex (callback, hash, index = 0) { + return this.addListener(this._api, 'eth_getTransactionByBlockHashAndIndex', (error, data) => { + error + ? callback(error) + : callback(null, outTransaction(data)); + }, [inHex(hash), inNumber16(index)]); + } + + getTransactionByBlockNumberAndIndex (callback, blockNumber = 'latest', index = 0) { + return this.addListener(this._api, 'eth_getTransactionByBlockNumberAndIndex', (error, data) => { + error + ? callback(error) + : callback(null, outTransaction(data)); + }, [inBlockNumber(blockNumber), inNumber16(index)]); + } + + getTransactionReceipt (callback, txhash) { + return this.addListener(this._api, 'eth_getTransactionReceipt', (error, data) => { + error + ? callback(error) + : callback(null, outReceipt(data)); + }, [inHex(txhash)]); + } + + getUncleByBlockHashAndIndex (callback, hash, index = 0) { + return this.addListener(this._api, 'eth_getUncleByBlockHashAndIndex', callback, [inHex(hash), inNumber16(index)]); + } + + getUncleByBlockNumberAndIndex (callback, blockNumber = 'latest', index = 0) { + return this.addListener(this._api, 'eth_getUncleByBlockNumberAndIndex', callback, [inBlockNumber(blockNumber), inNumber16(index)]); + } + + getLogs (callback, options) { + return this.addListener(this._api, 'eth_getLogs', (error, logs) => { + error + ? callback(error) + : callback(null, (logs) => logs.map(outLog)); + }, [inFilter(options)]); + } + + getWork (callback) { + return this.addListener(this._api, 'eth_getWork', callback); + } +} diff --git a/js/src/api/pubsub/eth/index.js b/js/src/api/pubsub/eth/index.js new file mode 100644 index 000000000..3b8d1994c --- /dev/null +++ b/js/src/api/pubsub/eth/index.js @@ -0,0 +1,16 @@ +// Copyright 2015-2017 Parity Technologies (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 . +export default from './eth'; diff --git a/js/src/api/pubsub/index.js b/js/src/api/pubsub/index.js new file mode 100644 index 000000000..bf342e1de --- /dev/null +++ b/js/src/api/pubsub/index.js @@ -0,0 +1,16 @@ +// Copyright 2015-2017 Parity Technologies (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 . +export default from './pubsub'; diff --git a/js/src/api/pubsub/net/index.js b/js/src/api/pubsub/net/index.js new file mode 100644 index 000000000..6d13847c5 --- /dev/null +++ b/js/src/api/pubsub/net/index.js @@ -0,0 +1,16 @@ +// Copyright 2015-2017 Parity Technologies (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 . +export default from './net'; diff --git a/js/src/api/pubsub/net/net.js b/js/src/api/pubsub/net/net.js new file mode 100644 index 000000000..e1dc3c4e1 --- /dev/null +++ b/js/src/api/pubsub/net/net.js @@ -0,0 +1,42 @@ +// Copyright 2015-2017 Parity Technologies (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 . +import PubsubBase from '../pubsubBase'; + +import { outNumber } from '../../format/output'; + +export default class Net extends PubsubBase { + constructor (transport) { + super(transport); + this._api = 'parity'; + } + + // net API + version (callback) { + return this.addListener(this._api, 'net_version', callback); + } + + peerCount (callback) { + return this.addListener(this._api, 'net_peerCount', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + listening (callback) { + return this.addListener(this._api, 'net_listening', callback); + } +} diff --git a/js/src/api/pubsub/parity/index.js b/js/src/api/pubsub/parity/index.js new file mode 100644 index 000000000..33ce7aa7f --- /dev/null +++ b/js/src/api/pubsub/parity/index.js @@ -0,0 +1,16 @@ +// Copyright 2015-2017 Parity Technologies (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 . +export default from './parity'; diff --git a/js/src/api/pubsub/parity/parity.js b/js/src/api/pubsub/parity/parity.js new file mode 100644 index 000000000..bf18effa1 --- /dev/null +++ b/js/src/api/pubsub/parity/parity.js @@ -0,0 +1,355 @@ +// Copyright 2015-2017 Parity Technologies (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 . + +import PubsubBase from '../pubsubBase'; +import { inAddress, inBlockNumber, inData, inHex, inDeriveHash, inDeriveIndex } from '../../format/input'; +import { outAccountInfo, outAddress, outBlock, outChainStatus, outHistogram, outHwAccountInfo, outNodeKind, outNumber, outPeers, outTransaction, outAddresses, outRecentDapps, outVaultMeta } from '../../format/output'; + +export default class Parity extends PubsubBase { + constructor (transport) { + super(transport); + this._api = 'parity'; + } + + // parity API + accountsInfo (callback) { + return this.addListener(this._api, 'parity_accountsInfo', (error, data) => { + error + ? callback(error) + : callback(null, outAccountInfo(data)); + }); + } + + hardwareAccountsInfo (callback) { + return this.addListener(this._api, 'parity_hardwareAccountsInfo', (error, data) => { + error + ? callback(error) + : callback(null, outHwAccountInfo(data)); + }); + } + + defaultAccount (callback) { + return this.addListener(this._api, 'parity_defaultAccount', (error, data) => { + error + ? callback(error) + : callback(null, outAddress(data)); + }); + } + + transactionsLimit (callback) { + return this.addListener(this._api, 'parity_transactionsLimit', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + extraData (callback) { + return this.addListener(this._api, 'parity_extraData', callback); + } + + gasFloorTarget (callback) { + return this.addListener(this._api, 'parity_gasFloorTarget', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + gasCeilTarget (callback) { + return this.addListener(this._api, 'parity_gasCeilTarget', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + minGasPrice (callback) { + return this.addListener(this._api, 'parity_minGasPrice', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + devLogs (callback) { + return this.addListener(this._api, 'parity_devLogs', callback); + } + + devLogsLevels (callback) { + return this.addListener(this._api, 'parity_devLogsLevels', callback); + } + + netChain (callback) { + return this.addListener(this._api, 'parity_netChain', callback); + } + + netPeers (callback) { + return this.addListener(this._api, 'parity_netPeers', (error, data) => { + error + ? callback(error) + : callback(null, outPeers(data)); + }); + } + + netPort (callback) { + return this.addListener(this._api, 'parity_netPort', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + rpcSettings (callback) { + return this.addListener(this._api, 'parity_rpcSettings', callback); + } + + nodeName (callback) { + return this.addListener(this._api, 'parity_nodeName', callback); + } + + defaultExtraData (callback) { + return this.addListener(this._api, 'parity_defaultExtraData', callback); + } + + gasPriceHistogram (callback) { + return this.addListener(this._api, 'parity_gasPriceHistogram', (error, data) => { + error + ? callback(error) + : callback(null, outHistogram(data)); + }); + } + + unsignedTransactionsCount (callback) { + return this.addListener(this._api, 'parity_unsignedTransactionsCount', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }); + } + + registryAddress (callback) { + return this.addListener(this._api, 'parity_registryAddress', (error, data) => { + error + ? callback(error) + : callback(null, outAddress(data)); + }); + } + + listAccounts (callback, count, offset = null, blockNumber = 'latest') { + return this.addListener(this._api, 'parity_listAccounts', (error, data) => { + error + ? callback(error) + : callback(null, (data) => (data || []).map(outAddress)); + }, [count, inAddress(offset), inBlockNumber(blockNumber)]); + } + + listStorageKeys (callback, address, count, hash = null, blockNumber = 'latest') { + return this.addListener(this._api, 'parity_listStorageKeys', callback, [inAddress(address), count, inHex(hash), inBlockNumber(blockNumber)]); + } + + pendingTransactions (callback) { + return this.addListener(this._api, 'parity_pendingTransactions', (error, data) => { + error + ? callback(error) + : callback(null, outTransaction(data)); + }); + } + + futureTransactions (callback) { + return this.addListener(this._api, 'parity_futureTransactions', (error, data) => { + error + ? callback(error) + : callback(null, outTransaction(data)); + }); + } + + pendingTransactionsStats (callback) { + return this.addListener(this._api, 'parity_pendingTransactionsStats', callback); + } + + localTransactions (callback) { + return this.addListener(this._api, 'parity_localTransactions', (error, transactions) => { + error + ? callback(error) + : callback(null, transactions => { + Object.values(transactions) + .filter(tx => tx.transaction) + .map(tx => { + tx.transaction = outTransaction(tx.transaction); + }); + return transactions; + }); + }); + } + + dappsUrl (callback) { + return this.addListener(this._api, 'parity_dappsUrl', callback); + } + + wsUrl (callback) { + return this.addListener(this._api, 'parity_wsUrl', callback); + } + + nextNonce (callback, account) { + return this.addListener(this._api, 'parity_nextNonce', (error, data) => { + error + ? callback(error) + : callback(null, outNumber(data)); + }, [inAddress(account)]); + } + + mode (callback) { + return this.addListener(this._api, 'parity_mode', callback); + } + + chain (callback) { + return this.addListener(this._api, 'parity_chain', callback); + } + + enode (callback) { + return this.addListener(this._api, 'parity_enode', callback); + } + + consensusCapability (callback) { + return this.addListener(this._api, 'parity_consensusCapability', callback); + } + + versionInfo (callback) { + return this.addListener(this._api, 'parity_versionInfo', callback); + } + + releasesInfo (callback) { + return this.addListener(this._api, 'parity_releasesInfo', callback); + } + + chainStatus (callback) { + return this.addListener(this._api, 'parity_chainStatus', (error, data) => { + error + ? callback(error) + : callback(null, outChainStatus(data)); + }); + } + + nodeKind (callback) { + return this.addListener(this._api, 'parity_nodeKind', (error, data) => { + error + ? callback(error) + : callback(null, outNodeKind(data)); + }); + } + + getBlockHeaderByNumber (callback, blockNumber = 'latest') { + return this.addListener(this._api, 'parity_getBlockHeaderByNumber', (error, data) => { + error + ? callback(error) + : callback(null, outBlock(data)); + }, [inBlockNumber(blockNumber)]); + } + + cidV0 (callback, data) { + return this.addListener(this._api, 'parity_cidV0', callback, [inData(data)]); + } + + // parity accounts API (only secure API or configured to be exposed) + allAccountsInfo (callback) { + return this._addListener(this._api, 'parity_allAccountsInfo', (error, data) => { + error + ? callback(error) + : callback(null, outAccountInfo(data)); + }); + } + + getDappAddresses (callback, dappId) { + return this._addListener(this._api, 'parity_getDappAddresses', (error, data) => { + error + ? callback(error) + : callback(null, outAddresses(data)); + }, [dappId]); + } + + getDappDefaultAddress (callback, dappId) { + return this._addListener(this._api, 'parity_getDappDefaultAddress', (error, data) => { + error + ? callback(error) + : callback(null, outAddress(data)); + }, [dappId]); + } + + getNewDappsAddresses (callback) { + return this._addListener(this._api, 'parity_getDappDefaultAddress', (error, addresses) => { + error + ? callback(error) + : callback(null, addresses ? addresses.map(outAddress) : null); + }); + } + + getNewDappsDefaultAddress (callback) { + return this._addListener(this._api, 'parity_getNewDappsDefaultAddress', (error, data) => { + error + ? callback(error) + : callback(null, outAddress(data)); + }); + } + + listRecentDapps (callback) { + return this._addListener(this._api, 'parity_listRecentDapps', (error, data) => { + error + ? callback(error) + : callback(null, outRecentDapps(data)); + }); + } + + listGethAccounts (callback) { + return this._addListener(this._api, 'parity_listGethAccounts', (error, data) => { + error + ? callback(error) + : callback(null, outAddresses(data)); + }); + } + + listVaults (callback) { + return this._addListener(this._api, 'parity_listVaults', callback); + } + + listOpenedVaults (callback) { + return this._addListener(this._api, 'parity_listOpenedVaults', callback); + } + + getVaultMeta (callback, vaultName) { + return this._addListener(this._api, 'parity_getVaultMeta', (error, data) => { + error + ? callback(error) + : callback(null, outVaultMeta(data)); + }, [vaultName]); + } + + deriveAddressHash (callback, address, password, hash, shouldSave) { + return this._addListener(this._api, 'parity_deriveAddressHash', (error, data) => { + error + ? callback(error) + : callback(null, outAddress(data)); + }, [inAddress(address), password, inDeriveHash(hash), !!shouldSave]); + } + + deriveAddressIndex (callback, address, password, index, shouldSave) { + return this._addListener(this._api, 'parity_deriveAddressIndex', (error, data) => { + error + ? callback(error) + : callback(null, outAddress(data)); + }, [inAddress(address), password, inDeriveIndex(index), !!shouldSave]); + } +} diff --git a/js/src/api/pubsub/pubsub.js b/js/src/api/pubsub/pubsub.js new file mode 100644 index 000000000..edbc201ae --- /dev/null +++ b/js/src/api/pubsub/pubsub.js @@ -0,0 +1,50 @@ +// Copyright 2015-2017 Parity Technologies (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 . + +import Eth from './eth'; +import Parity from './parity'; +import Net from './net'; + +import { isFunction } from '../util/types'; + +export default class Pubsub { + constructor (transport) { + if (!transport || !isFunction(transport.subscribe)) { + throw new Error('Pubsub API needs transport with subscribe() function defined. (WebSocket)'); + } + + this._eth = new Eth(transport); + this._net = new Net(transport); + this._parity = new Parity(transport); + } + + get net () { + return this._net; + } + + get eth () { + return this._eth; + } + + get parity () { + return this._parity; + } + + unsubscribe (subscriptionIds) { + // subscriptions are namespace independent. Thus we can simply removeListener from any. + return this._parity.removeListener(subscriptionIds); + } +} diff --git a/js/src/api/pubsub/pubsub.spec.js b/js/src/api/pubsub/pubsub.spec.js new file mode 100644 index 000000000..10fcd2edb --- /dev/null +++ b/js/src/api/pubsub/pubsub.spec.js @@ -0,0 +1,613 @@ +// Copyright 2015-2017 Parity Technologies (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 . + +import BigNumber from 'bignumber.js'; +import { TEST_WS_URL, mockWs } from '../../../test/mockRpc'; +import { isBigNumber } from '../../../test/types'; + +import Ws from '../transport/ws'; +import Pubsub from './pubsub'; + +describe('api/pubsub/Pubsub', () => { + let scope; + let instance; + const address = '0x63Cf90D3f0410092FC0fca41846f596223979195'; + + describe('accountsInfo', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: { + '0x63cf90d3f0410092fc0fca41846f596223979195': { + name: 'name', uuid: 'uuid', meta: '{"data":"data"}' + } + }, + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('retrieves the available account info', (done) => { + instance.parity.accountsInfo((error, result) => { + expect(error).to.be.null; + expect(result).to.deep.equal({ + '0x63Cf90D3f0410092FC0fca41846f596223979195': { + name: 'name', uuid: 'uuid', meta: { + data: 'data' + } + } + }); + done(); + }); + }); + }); + + describe('Unsubscribe', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2 }, + { method: 'parity_unsubscribe', reply: true }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('Promise gets resolved on success.', (done) => { + instance.parity.accountsInfo().then(s => { + instance.parity.unsubscribe(s).then(b => { + expect(b).to.be.true; + }); + }); + done(); + }); + }); + + describe('chainStatus', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: { + 'blockGap': [0x123, 0x456] + }, + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('retrieves the chain status', (done) => { + instance.parity.chainStatus((error, result) => { + expect(error).to.be.null; + expect(result).to.deep.equal({ + 'blockGap': [new BigNumber(0x123), new BigNumber(0x456)] + }); + done(); + }); + }); + }); + + describe('gasFloorTarget', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: '0x123456', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the gasfloor, formatted', (done) => { + instance.parity.gasFloorTarget((error, result) => { + expect(error).to.be.null; + expect(isBigNumber(result)).to.be.true; + expect(result.eq(0x123456)).to.be.true; + done(); + }); + }); + }); + + describe('transactionsLimit', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: 1024, + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the tx limit, formatted', (done) => { + instance.parity.transactionsLimit((error, result) => { + expect(error).to.be.null; + expect(isBigNumber(result)).to.be.true; + expect(result.eq(1024)).to.be.true; + done(); + }); + }); + }); + + describe('minGasPrice', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: '0x123456', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the min gasprice, formatted', (done) => { + instance.parity.minGasPrice((error, result) => { + expect(error).to.be.null; + expect(isBigNumber(result)).to.be.true; + expect(result.eq(0x123456)).to.be.true; + done(); + }); + }); + }); + + describe('netPeers', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: { active: 123, connected: 456, max: 789, peers: [] }, + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the peer structure, formatted', (done) => { + instance.parity.netPeers((error, peers) => { + expect(error).to.be.null; + expect(peers.active.eq(123)).to.be.true; + expect(peers.connected.eq(456)).to.be.true; + expect(peers.max.eq(789)).to.be.true; + done(); + }); + }); + }); + + describe('netPort', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: 33030, + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the connected port, formatted', (done) => { + instance.parity.netPort((error, count) => { + expect(error).to.be.null; + expect(isBigNumber(count)).to.be.true; + expect(count.eq(33030)).to.be.true; + done(); + }); + }); + }); + +// Eth API + describe('accounts', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: [address.toLowerCase()], + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns a list of accounts, formatted', (done) => { + instance.eth.accounts((error, accounts) => { + expect(error).to.be.null; + expect(accounts).to.deep.equal([address]); + done(); + }); + }); + }); + + describe('newHeads', () => { + beforeEach(() => { + scope = mockWs([{ method: 'eth_subscribe', reply: 2, subscription: { + method: 'eth_subscription', + params: { + result: '0x123456', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns newHeads for eth_subscribe', (done) => { + instance.eth.newHeads((error, blockNumber) => { + expect(error).to.be.null; + expect(blockNumber).to.equal('0x123456'); + done(); + }); + }); + }); + + describe('blockNumber', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: '0x123456', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the current blockNumber, formatted', (done) => { + instance.eth.blockNumber((error, blockNumber) => { + expect(error).to.be.null; + expect(isBigNumber(blockNumber)).to.be.true; + expect(blockNumber.toString(16)).to.equal('123456'); + done(); + }); + }); + }); + + describe('call', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: [], + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('formats the input options & blockNumber', (done) => { + instance.eth.call((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_call', [{ data: '0x12345678' }, 'earliest']]); + done(); + }, { data: '12345678' }, 'earliest'); + }); + + it('provides a latest blockNumber when not specified', (done) => { + instance.eth.call((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_call', [{ data: '0x12345678' }, 'latest']]); + done(); + }, { data: '12345678' }); + }); + }); + + describe('coinbase', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: address.toLowerCase(), + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the coinbase, formatted', (done) => { + instance.eth.coinbase((error, account) => { + expect(error).to.be.null; + expect(account).to.deep.equal(address); + done(); + }); + }); + }); + + describe('estimateGas', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: '0x123', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('converts the options correctly', (done) => { + instance.eth.estimateGas((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_estimateGas', [{ gas: '0x5208' }]]); + done(); + }, { gas: 21000 }); + }); + + it('returns the gas used, formatted', (done) => { + instance.eth.estimateGas((error, gas) => { + expect(error).to.be.null; + expect(isBigNumber(gas)).to.be.true; + expect(gas.toString(16)).to.deep.equal('123'); + done(); + }); + }); + }); + + describe('gasPrice', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: '0x123', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('returns the gas price, formatted', (done) => { + instance.eth.gasPrice((error, price) => { + expect(error).to.be.null; + expect(isBigNumber(price)).to.be.true; + expect(price.toString(16)).to.deep.equal('123'); + done(); + }); + }); + }); + + describe('getBalance', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: '0x123', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('passes in the address (default blockNumber)', (done) => { + instance.eth.getBalance((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBalance', [address.toLowerCase(), 'latest']]); + done(); + }, address); + }); + + it('passes in the address & blockNumber', (done) => { + instance.eth.getBalance((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBalance', [address.toLowerCase(), '0x456']]); + done(); + }, address, 0x456); + }); + + it('returns the balance', (done) => { + instance.eth.getBalance((error, balance) => { + expect(error).to.be.null; + expect(isBigNumber(balance)).to.be.true; + expect(balance.toString(16)).to.deep.equal('123'); + done(); + }, address); + }); + }); + + describe('getBlockByHash', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: { miner: address.toLowerCase() }, + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('formats the input hash as a hash, default full', (done) => { + instance.eth.getBlockByHash((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByHash', ['0x1234', false]]); + done(); + }, '1234'); + }); + + it('formats the input hash as a hash, full true', (done) => { + instance.eth.getBlockByHash((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByHash', ['0x1234', true]]); + done(); + }, '1234', true); + }); + + it('formats the output into block', (done) => { + instance.eth.getBlockByHash((error, block) => { + expect(error).to.be.null; + expect(block.miner).to.equal(address); + done(); + }, '1234'); + }); + }); + + describe('getBlockByNumber', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: { miner: address.toLowerCase() }, + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('assumes blockNumber latest & full false', (done) => { + instance.eth.getBlockByNumber((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByNumber', ['latest', false]]); + done(); + }); + }); + + it('uses input blockNumber & full false', (done) => { + instance.eth.getBlockByNumber((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByNumber', ['0x1234', false]]); + done(); + }, '0x1234'); + }); + + it('formats the input blockNumber, full true', (done) => { + instance.eth.getBlockByNumber((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getBlockByNumber', ['0x1234', true]]); + done(); + }, 0x1234, true); + }); + + it('formats the output into block', (done) => { + instance.eth.getBlockByNumber((error, block) => { + expect(error).to.be.null; + expect(block.miner).to.equal(address); + done(); + }, 0x1234); + }); + }); + + describe('getTransactionCount', () => { + beforeEach(() => { + scope = mockWs([{ method: 'parity_subscribe', reply: 2, subscription: { + method: 'parity_subscription', + params: { + result: '0x123', + subscription: 2 + } + } }]); + instance = new Pubsub(new Ws(TEST_WS_URL)); + }); + + afterEach(() => { + scope.stop(); + }); + + it('passes in the address (default blockNumber)', (done) => { + instance.eth.getTransactionCount((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getTransactionCount', [address.toLowerCase(), 'latest']]); + done(); + }, address); + }); + + it('passes in the address & blockNumber', (done) => { + instance.eth.getTransactionCount((error) => { + expect(error).to.be.null; + expect(scope.body.parity_subscribe.params).to.deep.equal(['eth_getTransactionCount', [address.toLowerCase(), '0x456']]); + done(); + }, address, 0x456); + }); + + it('returns the count, formatted', (done) => { + instance.eth.getTransactionCount((error, count) => { + expect(error).to.be.null; + expect(isBigNumber(count)).to.be.true; + expect(count.toString(16)).to.equal('123'); + done(); + }, address, 0x456); + }); + }); +}); diff --git a/js/src/api/pubsub/pubsubBase.js b/js/src/api/pubsub/pubsubBase.js new file mode 100644 index 000000000..fcc7525d5 --- /dev/null +++ b/js/src/api/pubsub/pubsubBase.js @@ -0,0 +1,37 @@ +// Copyright 2015-2017 Parity Technologies (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 . + +export default class PubsubBase { + // Provider for websocket pubsub transport + constructor (transport) { + this._transport = transport; + } + + addListener (module, eventName, callback, eventParams) { + return eventParams + ? this._transport.subscribe(module, callback, eventName, eventParams) + : this._transport.subscribe(module, callback, eventName, []); + // this._transport.subscribe(module, callback, eventName); After Patch from tomac is merged to master! => eth_subscribe does not support empty array as params + } + + removeListener (subscriptionIds) { + return this._transport.unsubscribe(subscriptionIds); + } + + unsubscribe (subscriptionIds) { + return this.removeListener(subscriptionIds); + } +} diff --git a/js/src/api/rpc/parity/parity.spec.js b/js/src/api/rpc/parity/parity.spec.js index d7eb41047..6ba7a1c83 100644 --- a/js/src/api/rpc/parity/parity.spec.js +++ b/js/src/api/rpc/parity/parity.spec.js @@ -110,7 +110,7 @@ describe('api/rpc/parity', () => { }); }); - describe('newPeers', () => { + describe('netPeers', () => { it('returns the peer structure, formatted', () => { mockHttp([{ method: 'parity_netPeers', reply: { result: { active: 123, connected: 456, max: 789, peers: [] } } }]); diff --git a/js/src/api/rpc/trace/trace.js b/js/src/api/rpc/trace/trace.js index 29494a9ae..26b19b378 100644 --- a/js/src/api/rpc/trace/trace.js +++ b/js/src/api/rpc/trace/trace.js @@ -28,9 +28,9 @@ export default class Trace { .then(outTraces); } - call (options, blockNumber = 'latest', whatTrace = ['trace']) { + call (options, whatTrace = ['trace'], blockNumber = 'latest') { return this._transport - .execute('trace_call', inOptions(options), inBlockNumber(blockNumber), inTraceType(whatTrace)) + .execute('trace_call', inOptions(options), inTraceType(whatTrace), inBlockNumber(blockNumber)) .then(outTraceReplay); } diff --git a/js/src/api/transport/ws/ws.js b/js/src/api/transport/ws/ws.js index 63cfcc5ec..3c642d5f8 100644 --- a/js/src/api/transport/ws/ws.js +++ b/js/src/api/transport/ws/ws.js @@ -22,12 +22,14 @@ import TransportError from '../error'; /* global WebSocket */ export default class Ws extends JsonRpcBase { - constructor (url, token, autoconnect = true) { + // token is optional (secure API) + constructor (url, token = null, autoconnect = true) { super(); this._url = url; this._token = token; this._messages = {}; + this._subscriptions = { 'eth_subscription': [], 'parity_subscription': [] }; this._sessionHash = null; this._connecting = false; @@ -68,10 +70,6 @@ export default class Ws extends JsonRpcBase { this._reconnectTimeoutId = null; } - const time = parseInt(new Date().getTime() / 1000, 10); - const sha3 = keccak_256(`${this._token}:${time}`); - const hash = `${sha3}_${time}`; - if (this._ws) { this._ws.onerror = null; this._ws.onopen = null; @@ -81,13 +79,23 @@ export default class Ws extends JsonRpcBase { this._ws = null; this._sessionHash = null; } - this._connecting = true; this._connected = false; this._lastError = null; - this._sessionHash = sha3; - this._ws = new WebSocket(this._url, hash); + // rpc secure API + if (this._token) { + const time = parseInt(new Date().getTime() / 1000, 10); + const sha3 = keccak_256(`${this._token}:${time}`); + const hash = `${sha3}_${time}`; + + this._sessionHash = sha3; + this._ws = new WebSocket(this._url, hash); + // non-secure API + } else { + this._ws = new WebSocket(this._url); + } + this._ws.onerror = this._onError; this._ws.onopen = this._onOpen; this._ws.onclose = this._onClose; @@ -194,13 +202,48 @@ export default class Ws extends JsonRpcBase { }, 50); } + _extract = (result) => { + const { result: res, id, method, params } = result; + const msg = this._messages[id]; + + // initial pubsub ACK + if (id && msg.subscription) { + // save subscription to map subId -> messageId + this._subscriptions[msg.subscription][res] = id; + // resolve promise with messageId because subId's can collide (eth/parity) + msg.resolve(id); + // save subId for unsubscribing later + msg.subId = res; + return msg; + } + + // normal message + if (id) { + return msg; + } + + // pubsub format + if (method.includes('subscription')) { + const messageId = this._messages[this._subscriptions[method][params.subscription]]; + + if (messageId) { + return messageId; + } else { + throw Error(`Received Subscription which is already unsubscribed ${JSON.stringify(result)}`); + } + } + + throw Error(`Unknown message format: No ID or subscription ${JSON.stringify(result)}`); + } + _onMessage = (event) => { try { const result = JSON.parse(event.data); - const { method, params, json, resolve, reject } = this._messages[result.id]; + const { method, params, json, resolve, reject, callback, subscription } = this._extract(result); Logging.send(method, params, { json, result }); + result.error = (result.params && result.params.error) || result.error; if (result.error) { this.error(event.data); @@ -211,14 +254,23 @@ export default class Ws extends JsonRpcBase { const error = new TransportError(method, result.error.code, result.error.message); - reject(error); + if (result.id) { + reject(error); + } else { + callback(error); + } delete this._messages[result.id]; return; } - resolve(result.result); - delete this._messages[result.id]; + // if not initial subscription message resolve & delete + if (result.id && !subscription) { + resolve(result.result); + delete this._messages[result.id]; + } else if (result.params) { + callback(null, result.params.result); + } } catch (e) { console.error('ws::_onMessage', event.data, e); } @@ -249,6 +301,43 @@ export default class Ws extends JsonRpcBase { }); } + _methodsFromApi (api) { + const method = `${api}_subscribe`; + const uMethod = `${api}_unsubscribe`; + const subscription = `${api}_subscription`; + + return { method, uMethod, subscription }; + } + + subscribe (api, callback, ...params) { + return new Promise((resolve, reject) => { + const id = this.id; + const { method, uMethod, subscription } = this._methodsFromApi(api); + const json = this.encode(method, params); + + this._messages[id] = { id, method, uMethod, params, json, resolve, reject, callback, subscription }; + + this._send(id); + }); + } + + unsubscribe (messageId) { + return new Promise((resolve, reject) => { + const id = this.id; + const { subId, uMethod, subscription } = this._messages[messageId]; + const params = [subId]; + const json = this.encode(uMethod, params); + const uResolve = (v) => { + delete this._messages[messageId]; + delete this._subscriptions[subscription][subId]; + resolve(v); + }; + + this._messages[id] = { id, method: uMethod, params, json, resolve: uResolve, reject }; + this._send(id); + }); + } + set url (url) { this._url = url; } diff --git a/js/src/jsonrpc/interfaces/eth.js b/js/src/jsonrpc/interfaces/eth.js index c52b9bc7a..d54c57325 100644 --- a/js/src/jsonrpc/interfaces/eth.js +++ b/js/src/jsonrpc/interfaces/eth.js @@ -545,6 +545,39 @@ The following options are possible for the \`defaultBlock\` parameter: input: { type: Data, desc: 'the data send along with the transaction.' + }, + v: { + type: Quantity, + desc: 'the standardised V field of the signature.' + }, + standard_v: { + type: Quantity, + desc: 'the standardised V field of the signature (0 or 1).' + }, + r: { + type: Quantity, + desc: 'the R field of the signature.' + }, + raw: { + type: Data, + desc: 'raw transaction data' + }, + publicKey: { + type: Hash, + desc: 'public key of the signer.' + }, + networkId: { + type: Quantity, + desc: 'the network id of the transaction, if any.' + }, + creates: { + type: Hash, + desc: 'creates contract hash' + }, + condition: { + type: Object, + optional: true, + desc: 'conditional submission, Block number in `block` or timestamp in `time` or `null`. (parity-feature)' } }, example: { @@ -1057,6 +1090,39 @@ The following options are possible for the \`defaultBlock\` parameter: input: { type: Data, desc: 'the data send along with the transaction.' + }, + v: { + type: Quantity, + desc: 'the standardised V field of the signature.' + }, + standard_v: { + type: Quantity, + desc: 'the standardised V field of the signature (0 or 1).' + }, + r: { + type: Quantity, + desc: 'the R field of the signature.' + }, + raw: { + type: Data, + desc: 'raw transaction data' + }, + publicKey: { + type: Hash, + desc: 'public key of the signer.' + }, + networkId: { + type: Quantity, + desc: 'the network id of the transaction, if any.' + }, + creates: { + type: Hash, + desc: 'creates contract hash' + }, + condition: { + type: Object, + optional: true, + desc: 'conditional submission, Block number in `block` or timestamp in `time` or `null`. (parity-feature)' } } } diff --git a/js/test/mockRpc.js b/js/test/mockRpc.js index eb15e98ed..b3c6abc3e 100644 --- a/js/test/mockRpc.js +++ b/js/test/mockRpc.js @@ -70,6 +70,10 @@ export function mockWs (requests) { scope.requests++; mockServer.send(JSON.stringify(response)); + + if (request.method.match('subscribe') && request.subscription) { + mockServer.send(JSON.stringify(request.subscription)); + } }); return scope; diff --git a/parity/configuration.rs b/parity/configuration.rs index adad91e1a..81117db05 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -515,6 +515,10 @@ impl Configuration { } fn miner_options(&self, reseal_min_period: u64) -> Result { + if self.args.flag_force_sealing && reseal_min_period == 0 { + return Err("Force sealing can't be used with reseal_min_period = 0".into()); + } + let reseal = self.args.flag_reseal_on_txs.parse::()?; let options = MinerOptions { @@ -1334,6 +1338,13 @@ mod tests { assert_eq!(conf3.miner_options(min_period).unwrap(), mining_options); } + #[test] + fn should_fail_on_force_reseal_and_reseal_min_period() { + let conf = parse(&["parity", "--chain", "dev", "--force-sealing"]); + + assert!(conf.miner_options(0).is_err()); + } + #[test] fn should_parse_updater_options() { // when diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index ce978422d..ff950d346 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -162,7 +162,7 @@ impl Dispatcher for FullDispatcher accounts.sign(address, Some(pass), hash).map(WithToken::No), SignWith::Token(token) => accounts.sign_with_token(address, token, hash).map(Into::into), }.map_err(|e| match password { - SignWith::Nothing => errors::from_signing_error(e), - _ => errors::from_password_error(e), + SignWith::Nothing => errors::signing(e), + _ => errors::password(e), }) } @@ -570,8 +570,8 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: S SignWith::Password(pass) => accounts.decrypt(address, Some(pass), &DEFAULT_MAC, &msg).map(WithToken::No), SignWith::Token(token) => accounts.decrypt_with_token(address, token, &DEFAULT_MAC, &msg).map(Into::into), }.map_err(|e| match password { - SignWith::Nothing => errors::from_signing_error(e), - _ => errors::from_password_error(e), + SignWith::Nothing => errors::signing(e), + _ => errors::password(e), }) } diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index df7d65067..30e6d7f94 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -221,7 +221,7 @@ pub fn network_disabled() -> Error { } } -pub fn encryption_error(error: T) -> Error { +pub fn encryption(error: T) -> Error { Error { code: ErrorCode::ServerError(codes::ENCRYPTION_ERROR), message: "Encryption error.".into(), @@ -229,7 +229,7 @@ pub fn encryption_error(error: T) -> Error { } } -pub fn encoding_error(error: T) -> Error { +pub fn encoding(error: T) -> Error { Error { code: ErrorCode::ServerError(codes::ENCODING_ERROR), message: "Encoding error.".into(), @@ -237,7 +237,7 @@ pub fn encoding_error(error: T) -> Error { } } -pub fn database_error(error: T) -> Error { +pub fn database(error: T) -> Error { Error { code: ErrorCode::ServerError(codes::DATABASE_ERROR), message: "Database error.".into(), @@ -245,7 +245,7 @@ pub fn database_error(error: T) -> Error { } } -pub fn from_fetch_error(error: T) -> Error { +pub fn fetch(error: T) -> Error { Error { code: ErrorCode::ServerError(codes::FETCH_ERROR), message: "Error while fetching content.".into(), @@ -253,7 +253,7 @@ pub fn from_fetch_error(error: T) -> Error { } } -pub fn from_signing_error(error: AccountError) -> Error { +pub fn signing(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(), @@ -261,7 +261,7 @@ pub fn from_signing_error(error: AccountError) -> Error { } } -pub fn from_password_error(error: AccountError) -> Error { +pub fn password(error: AccountError) -> Error { Error { code: ErrorCode::ServerError(codes::PASSWORD_INVALID), message: "Account password is invalid or account does not exist.".into(), @@ -301,7 +301,7 @@ pub fn transaction_message(error: TransactionError) -> String { } } -pub fn from_transaction_error(error: EthcoreError) -> Error { +pub fn transaction(error: EthcoreError) -> Error { if let EthcoreError::Transaction(e) = error { Error { @@ -318,7 +318,7 @@ pub fn from_transaction_error(error: EthcoreError) -> Error { } } -pub fn from_rlp_error(error: DecoderError) -> Error { +pub fn rlp(error: DecoderError) -> Error { Error { code: ErrorCode::InvalidParams, message: "Invalid RLP.".into(), @@ -326,7 +326,7 @@ pub fn from_rlp_error(error: DecoderError) -> Error { } } -pub fn from_call_error(error: CallError) -> Error { +pub fn call(error: CallError) -> Error { match error { CallError::StatePruned => state_pruned(), CallError::StateCorrupt => state_corrupt(), diff --git a/rpc/src/v1/helpers/ipfs.rs b/rpc/src/v1/helpers/ipfs.rs index 53aa4be35..80ad1c207 100644 --- a/rpc/src/v1/helpers/ipfs.rs +++ b/rpc/src/v1/helpers/ipfs.rs @@ -32,7 +32,7 @@ pub fn cid(content: Bytes) -> Result { let mut buf = Vec::with_capacity(len); buf.resize(len, 0); hasher.result(&mut buf); - let mh = multihash::encode(multihash::Hash::SHA2256, &buf).map_err(errors::encoding_error)?; + let mh = multihash::encode(multihash::Hash::SHA2256, &buf).map_err(errors::encoding)?; let cid = Cid::new(Codec::DagProtobuf, Version::V0, &mh); Ok(cid.to_string().into()) } diff --git a/rpc/src/v1/helpers/secretstore.rs b/rpc/src/v1/helpers/secretstore.rs index d8d63b5fa..246d0fa3f 100644 --- a/rpc/src/v1/helpers/secretstore.rs +++ b/rpc/src/v1/helpers/secretstore.rs @@ -86,13 +86,13 @@ fn decrypt_with_shadow_coefficients(mut decrypted_shadow: Public, mut common_sha let mut shadow_coefficients_sum = shadow_coefficients[0].clone(); for shadow_coefficient in shadow_coefficients.iter().skip(1) { shadow_coefficients_sum.add(shadow_coefficient) - .map_err(errors::encryption_error)?; + .map_err(errors::encryption)?; } math::public_mul_secret(&mut common_shadow_point, &shadow_coefficients_sum) - .map_err(errors::encryption_error)?; + .map_err(errors::encryption)?; math::public_add(&mut decrypted_shadow, &common_shadow_point) - .map_err(errors::encryption_error)?; + .map_err(errors::encryption)?; Ok(decrypted_shadow) } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 499b0a15f..24b41bd6f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -365,7 +365,7 @@ impl Eth for EthClient where BlockNumber::Pending => { match self.miner.balance(&*self.client, &address) { Some(balance) => Ok(balance.into()), - None => Err(errors::database_error("latest balance missing")) + None => Err(errors::database("latest balance missing")) } } id => { @@ -388,7 +388,7 @@ impl Eth for EthClient where BlockNumber::Pending => { match self.miner.storage_at(&*self.client, &address, &H256::from(position)) { Some(s) => Ok(s.into()), - None => Err(errors::database_error("latest storage missing")) + None => Err(errors::database("latest storage missing")) } } id => { @@ -413,13 +413,13 @@ impl Eth for EthClient where .or_else(|| self.miner.nonce(&*self.client, &address)); match nonce { Some(nonce) => Ok(nonce.into()), - None => Err(errors::database_error("latest nonce missing")) + None => Err(errors::database("latest nonce missing")) } } BlockNumber::Pending => { match self.miner.nonce(&*self.client, &address) { Some(nonce) => Ok(nonce.into()), - None => Err(errors::database_error("latest nonce missing")) + None => Err(errors::database("latest nonce missing")) } } id => { @@ -472,7 +472,7 @@ impl Eth for EthClient where BlockNumber::Pending => { match self.miner.code(&*self.client, &address) { Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), - None => Err(errors::database_error("latest code missing")) + None => Err(errors::database("latest code missing")) } } id => { @@ -618,8 +618,8 @@ impl Eth for EthClient where fn send_raw_transaction(&self, raw: Bytes) -> Result { UntrustedRlp::new(&raw.into_vec()).as_val() - .map_err(errors::from_rlp_error) - .and_then(|tx| SignedTransaction::new(tx).map_err(errors::from_transaction_error)) + .map_err(errors::rlp) + .and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction)) .and_then(|signed_transaction| { FullDispatcher::new(self.client.clone(), self.miner.clone()) .dispatch_transaction(signed_transaction.into()) @@ -645,7 +645,7 @@ impl Eth for EthClient where future::done(result .map(|b| b.output.into()) - .map_err(errors::from_call_error) + .map_err(errors::call) ).boxed() } @@ -657,7 +657,7 @@ impl Eth for EthClient where }; future::done(self.client.estimate_gas(&signed, num.unwrap_or_default().into()) .map(Into::into) - .map_err(errors::from_call_error) + .map_err(errors::call) ).boxed() } diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index f50dd82ab..fd03f1226 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -363,18 +363,18 @@ impl Eth for EthClient { let best_header = self.client.best_block_header().decode(); UntrustedRlp::new(&raw.into_vec()).as_val() - .map_err(errors::from_rlp_error) + .map_err(errors::rlp) .and_then(|tx| { self.client.engine().verify_transaction_basic(&tx, &best_header) - .map_err(errors::from_transaction_error)?; + .map_err(errors::transaction)?; - let signed = SignedTransaction::new(tx).map_err(errors::from_transaction_error)?; + let signed = SignedTransaction::new(tx).map_err(errors::transaction)?; let hash = signed.hash(); self.transaction_queue.write().import(signed.into()) .map(|_| hash) .map_err(Into::into) - .map_err(errors::from_transaction_error) + .map_err(errors::transaction) }) .map(Into::into) } diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 273c958fe..481cdb136 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -241,7 +241,7 @@ impl Parity for ParityClient { fn encrypt_message(&self, key: H512, phrase: Bytes) -> Result { ecies::encrypt(&key.into(), &DEFAULT_MAC, &phrase.0) - .map_err(errors::encryption_error) + .map_err(errors::encryption) .map(Into::into) } diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index cab2fa91c..fdeee693f 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -127,9 +127,9 @@ impl ParitySet for ParitySetClient { fn hash_content(&self, url: String) -> BoxFuture { self.fetch.process(self.fetch.fetch(&url).then(move |result| { result - .map_err(errors::from_fetch_error) + .map_err(errors::fetch) .and_then(|response| { - sha3(&mut io::BufReader::new(response)).map_err(errors::from_fetch_error) + sha3(&mut io::BufReader::new(response)).map_err(errors::fetch) }) .map(Into::into) })) diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index c9dbf54a6..2cffdd4e6 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -284,7 +284,7 @@ impl Parity for ParityClient where fn encrypt_message(&self, key: H512, phrase: Bytes) -> Result { ecies::encrypt(&key.into(), &DEFAULT_MAC, &phrase.0) - .map_err(errors::encryption_error) + .map_err(errors::encryption) .map(Into::into) } diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 4be41f7c1..dc771c4f8 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -101,7 +101,7 @@ impl ParitySet for ParitySetClient where } fn set_engine_signer(&self, address: H160, password: String) -> Result { - self.miner.set_engine_signer(address.into(), password).map_err(Into::into).map_err(errors::from_password_error)?; + self.miner.set_engine_signer(address.into(), password).map_err(Into::into).map_err(errors::password)?; Ok(true) } @@ -168,9 +168,9 @@ impl ParitySet for ParitySetClient where fn hash_content(&self, url: String) -> BoxFuture { self.fetch.process(self.fetch.fetch(&url).then(move |result| { result - .map_err(errors::from_fetch_error) + .map_err(errors::fetch) .and_then(|response| { - sha3(&mut io::BufReader::new(response)).map_err(errors::from_fetch_error) + sha3(&mut io::BufReader::new(response)).map_err(errors::fetch) }) .map(Into::into) })) diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index d0b1b7a3c..79f4f0e38 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -133,7 +133,7 @@ impl SignerClient { fn verify_transaction(bytes: Bytes, request: FilledTransactionRequest, process: F) -> Result where F: FnOnce(PendingTransaction) -> Result, { - let signed_transaction = UntrustedRlp::new(&bytes.0).as_val().map_err(errors::from_rlp_error)?; + let signed_transaction = UntrustedRlp::new(&bytes.0).as_val().map_err(errors::rlp)?; let signed_transaction = SignedTransaction::new(signed_transaction).map_err(|e| errors::invalid_params("Invalid signature.", e))?; let sender = signed_transaction.sender(); diff --git a/rpc/src/v1/impls/traces.rs b/rpc/src/v1/impls/traces.rs index 705ad9cab..2c65f4403 100644 --- a/rpc/src/v1/impls/traces.rs +++ b/rpc/src/v1/impls/traces.rs @@ -87,23 +87,23 @@ impl Traces for TracesClient where C: MiningBlockChainClient + 'stat self.client.call(&signed, block.into(), to_call_analytics(flags)) .map(TraceResults::from) - .map_err(errors::from_call_error) + .map_err(errors::call) } fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec, block: Trailing) -> Result { let block = block.unwrap_or_default(); let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?; - let signed = SignedTransaction::new(tx).map_err(errors::from_transaction_error)?; + let signed = SignedTransaction::new(tx).map_err(errors::transaction)?; self.client.call(&signed, block.into(), to_call_analytics(flags)) .map(TraceResults::from) - .map_err(errors::from_call_error) + .map_err(errors::call) } fn replay_transaction(&self, transaction_hash: H256, flags: Vec) -> Result { self.client.replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags)) .map(TraceResults::from) - .map_err(errors::from_call_error) + .map_err(errors::call) } }