Merge branch 'master' into binary-serializer
Conflicts: ipc/codegen/src/codegen.rs
This commit is contained in:
commit
4c5425dbde
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -364,7 +364,7 @@ dependencies = [
|
|||||||
"jsonrpc-core 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jsonrpc-core 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-http-server 5.0.1 (git+https://github.com/debris/jsonrpc-http-server.git)",
|
"jsonrpc-http-server 5.0.1 (git+https://github.com/debris/jsonrpc-http-server.git)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-status 0.1.7 (git+https://github.com/tomusdrw/parity-status.git)",
|
"parity-status 0.2.2 (git+https://github.com/tomusdrw/parity-status.git)",
|
||||||
"parity-wallet 0.1.1 (git+https://github.com/tomusdrw/parity-wallet.git)",
|
"parity-wallet 0.1.1 (git+https://github.com/tomusdrw/parity-wallet.git)",
|
||||||
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
||||||
"url 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -754,8 +754,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-status"
|
name = "parity-status"
|
||||||
version = "0.1.7"
|
version = "0.2.2"
|
||||||
source = "git+https://github.com/tomusdrw/parity-status.git#5b7010eb7ecc38e80ab506902e083dc0dd48c43f"
|
source = "git+https://github.com/tomusdrw/parity-status.git#fb9cb1ebe33e97fde5ae6ef8f3a94685d3f6f2aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
"parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)",
|
||||||
]
|
]
|
||||||
|
@ -30,7 +30,7 @@ use blockchain::bloom_indexer::BloomIndexer;
|
|||||||
use blockchain::tree_route::TreeRoute;
|
use blockchain::tree_route::TreeRoute;
|
||||||
use blockchain::update::ExtrasUpdate;
|
use blockchain::update::ExtrasUpdate;
|
||||||
use blockchain::{CacheSize, ImportRoute};
|
use blockchain::{CacheSize, ImportRoute};
|
||||||
use db::{Writable, Readable, Key};
|
use db::{Writable, Readable, Key, CacheUpdatePolicy};
|
||||||
|
|
||||||
const BLOOM_INDEX_SIZE: usize = 16;
|
const BLOOM_INDEX_SIZE: usize = 16;
|
||||||
const BLOOM_LEVELS: u8 = 3;
|
const BLOOM_LEVELS: u8 = 3;
|
||||||
@ -183,7 +183,7 @@ impl BlockProvider for BlockChain {
|
|||||||
/// Returns true if the given block is known
|
/// Returns true if the given block is known
|
||||||
/// (though not necessarily a part of the canon chain).
|
/// (though not necessarily a part of the canon chain).
|
||||||
fn is_known(&self, hash: &H256) -> bool {
|
fn is_known(&self, hash: &H256) -> bool {
|
||||||
self.query_extras_exist(hash, &self.block_details)
|
self.extras_db.exists_with_cache(&self.block_details, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do not store tracing information.
|
// We do not store tracing information.
|
||||||
@ -466,28 +466,22 @@ impl BlockChain {
|
|||||||
batch.put(b"best", &update.info.hash).unwrap();
|
batch.put(b"best", &update.info.hash).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut write_details = self.block_details.write().unwrap();
|
for hash in update.block_details.keys().cloned() {
|
||||||
for (hash, details) in update.block_details.into_iter() {
|
self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash));
|
||||||
batch.write(&hash, &details);
|
|
||||||
self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone()));
|
|
||||||
write_details.insert(hash, details);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut write_details = self.block_details.write().unwrap();
|
||||||
|
batch.extend_with_cache(&mut write_details, update.block_details, CacheUpdatePolicy::Overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut write_receipts = self.block_receipts.write().unwrap();
|
let mut write_receipts = self.block_receipts.write().unwrap();
|
||||||
for (hash, receipt) in &update.block_receipts {
|
batch.extend_with_cache(&mut write_receipts, update.block_receipts, CacheUpdatePolicy::Remove);
|
||||||
batch.write(hash, receipt);
|
|
||||||
write_receipts.remove(hash);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut write_blocks_blooms = self.blocks_blooms.write().unwrap();
|
let mut write_blocks_blooms = self.blocks_blooms.write().unwrap();
|
||||||
for (bloom_hash, blocks_bloom) in &update.blocks_blooms {
|
batch.extend_with_cache(&mut write_blocks_blooms, update.blocks_blooms, CacheUpdatePolicy::Remove);
|
||||||
batch.write(bloom_hash, blocks_bloom);
|
|
||||||
write_blocks_blooms.remove(bloom_hash);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These cached values must be updated last and togeterh
|
// These cached values must be updated last and togeterh
|
||||||
@ -508,15 +502,8 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (number, hash) in &update.block_hashes {
|
batch.extend_with_cache(&mut write_hashes, update.block_hashes, CacheUpdatePolicy::Remove);
|
||||||
batch.write(number, hash);
|
batch.extend_with_cache(&mut write_txs, update.transactions_addresses, CacheUpdatePolicy::Remove);
|
||||||
write_hashes.remove(number);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (hash, tx_address) in &update.transactions_addresses {
|
|
||||||
batch.write(hash, tx_address);
|
|
||||||
write_txs.remove(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update extras database
|
// update extras database
|
||||||
self.extras_db.write(batch).unwrap();
|
self.extras_db.write(batch).unwrap();
|
||||||
@ -751,32 +738,8 @@ impl BlockChain {
|
|||||||
T: ExtrasIndexable + Clone + Decodable,
|
T: ExtrasIndexable + Clone + Decodable,
|
||||||
K: Key<T> + Eq + Hash + Clone,
|
K: Key<T> + Eq + Hash + Clone,
|
||||||
H256: From<K> {
|
H256: From<K> {
|
||||||
{
|
|
||||||
let read = cache.read().unwrap();
|
|
||||||
if let Some(v) = read.get(hash) {
|
|
||||||
return Some(v.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.note_used(CacheID::Extras(T::index(), H256::from(hash.clone())));
|
self.note_used(CacheID::Extras(T::index(), H256::from(hash.clone())));
|
||||||
|
self.extras_db.read_with_cache(cache, hash)
|
||||||
self.extras_db.read(hash).map(|t: T| {
|
|
||||||
let mut write = cache.write().unwrap();
|
|
||||||
write.insert(hash.clone(), t.clone());
|
|
||||||
t
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_extras_exist<K, T>(&self, hash: &K, cache: &RwLock<HashMap<K, T>>) -> bool where
|
|
||||||
K: Key<T> + Eq + Hash + Clone {
|
|
||||||
{
|
|
||||||
let read = cache.read().unwrap();
|
|
||||||
if let Some(_) = read.get(hash) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.extras_db.exists::<T>(hash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current cache size.
|
/// Get current cache size.
|
||||||
|
@ -16,9 +16,18 @@
|
|||||||
|
|
||||||
//! Extras db utils.
|
//! Extras db utils.
|
||||||
|
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use std::collections::HashMap;
|
||||||
use util::{H264, DBTransaction, Database};
|
use util::{H264, DBTransaction, Database};
|
||||||
use util::rlp::{encode, Encodable, decode, Decodable};
|
use util::rlp::{encode, Encodable, decode, Decodable};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CacheUpdatePolicy {
|
||||||
|
Overwrite,
|
||||||
|
Remove,
|
||||||
|
}
|
||||||
|
|
||||||
/// Should be used to get database key associated with given value.
|
/// Should be used to get database key associated with given value.
|
||||||
pub trait Key<T> {
|
pub trait Key<T> {
|
||||||
/// Returns db key.
|
/// Returns db key.
|
||||||
@ -27,16 +36,82 @@ pub trait Key<T> {
|
|||||||
|
|
||||||
/// Should be used to write value into database.
|
/// Should be used to write value into database.
|
||||||
pub trait Writable {
|
pub trait Writable {
|
||||||
/// Writes key into database.
|
/// Writes the value into the database.
|
||||||
fn write<T>(&self, key: &Key<T>, value: &T) where T: Encodable;
|
fn write<T>(&self, key: &Key<T>, value: &T) where T: Encodable;
|
||||||
|
|
||||||
|
/// Writes the value into the database and updates the cache.
|
||||||
|
fn write_with_cache<K, T>(&self, cache: &mut HashMap<K, T>, key: K, value: T, policy: CacheUpdatePolicy) where
|
||||||
|
K: Key<T> + Hash + Eq,
|
||||||
|
T: Encodable {
|
||||||
|
self.write(&key, &value);
|
||||||
|
match policy {
|
||||||
|
CacheUpdatePolicy::Overwrite => {
|
||||||
|
cache.insert(key, value);
|
||||||
|
},
|
||||||
|
CacheUpdatePolicy::Remove => {
|
||||||
|
cache.remove(&key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the values into the database and updates the cache.
|
||||||
|
fn extend_with_cache<K, T>(&self, cache: &mut HashMap<K, T>, values: HashMap<K, T>, policy: CacheUpdatePolicy)
|
||||||
|
where K: Key<T> + Hash + Eq, T: Encodable {
|
||||||
|
match policy {
|
||||||
|
CacheUpdatePolicy::Overwrite => {
|
||||||
|
for (key, value) in values.into_iter() {
|
||||||
|
self.write(&key, &value);
|
||||||
|
cache.insert(key, value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CacheUpdatePolicy::Remove => {
|
||||||
|
for (key, value) in &values {
|
||||||
|
self.write(key, value);
|
||||||
|
cache.remove(key);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should be used to read values from database.
|
/// Should be used to read values from database.
|
||||||
pub trait Readable {
|
pub trait Readable {
|
||||||
/// Returns value for given key.
|
/// Returns value for given key.
|
||||||
fn read<T>(&self, key: &Key<T>) -> Option<T> where T: Decodable;
|
fn read<T>(&self, key: &Key<T>) -> Option<T> where T: Decodable;
|
||||||
|
|
||||||
|
/// Returns value for given key either in cache or in database.
|
||||||
|
fn read_with_cache<K, T>(&self, cache: &RwLock<HashMap<K, T>>, key: &K) -> Option<T> where
|
||||||
|
K: Key<T> + Eq + Hash + Clone,
|
||||||
|
T: Clone + Decodable {
|
||||||
|
{
|
||||||
|
let read = cache.read().unwrap();
|
||||||
|
if let Some(v) = read.get(key) {
|
||||||
|
return Some(v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.read(key).map(|value: T|{
|
||||||
|
let mut write = cache.write().unwrap();
|
||||||
|
write.insert(key.clone(), value.clone());
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if given value exists.
|
/// Returns true if given value exists.
|
||||||
fn exists<T>(&self, key: &Key<T>) -> bool;
|
fn exists<T>(&self, key: &Key<T>) -> bool;
|
||||||
|
|
||||||
|
/// Returns true if given value exists either in cache or in database.
|
||||||
|
fn exists_with_cache<K, T>(&self, cache: &RwLock<HashMap<K, T>>, key: &K) -> bool where
|
||||||
|
K: Eq + Hash + Key<T> {
|
||||||
|
{
|
||||||
|
let read = cache.read().unwrap();
|
||||||
|
if read.get(key).is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.exists::<T>(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Writable for DBTransaction {
|
impl Writable for DBTransaction {
|
||||||
|
2
hook.sh
2
hook.sh
@ -4,7 +4,7 @@ echo "#!/bin/sh\n" > $FILE
|
|||||||
# Exit on any error
|
# Exit on any error
|
||||||
echo "set -e" >> $FILE
|
echo "set -e" >> $FILE
|
||||||
# Run release build
|
# Run release build
|
||||||
echo "cargo build --release --features dev" >> $FILE
|
echo "cargo build --features dev" >> $FILE
|
||||||
# Build tests
|
# Build tests
|
||||||
echo "cargo test --no-run --features dev \\" >> $FILE
|
echo "cargo test --no-run --features dev \\" >> $FILE
|
||||||
echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethcore-webapp" >> $FILE
|
echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethcore-webapp" >> $FILE
|
||||||
|
@ -77,7 +77,7 @@ fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
|
|||||||
pub struct BinHandshake {
|
pub struct BinHandshake {
|
||||||
api_version: String,
|
api_version: String,
|
||||||
protocol_version: String,
|
protocol_version: String,
|
||||||
_reserved: Vec<u8>,
|
reserved: Vec<u8>,
|
||||||
}
|
}
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
@ -305,8 +305,8 @@ pub fn strip_ptr(ty: &P<ast::Ty>) -> P<ast::Ty> {
|
|||||||
else { ty.clone() }
|
else { ty.clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_ptr(ty: &P<ast::Ty>) -> bool {
|
fn has_ptr(ty: &P<ast::Ty>) -> bool {
|
||||||
if let ast::TyKind::Rptr(_, ref ptr_mut) = ty.node {
|
if let ast::TyKind::Rptr(_, ref _ptr_mut) = ty.node {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else { false }
|
else { false }
|
||||||
@ -625,7 +625,7 @@ fn push_client_implementation(
|
|||||||
let payload = BinHandshake {
|
let payload = BinHandshake {
|
||||||
protocol_version: $item_ident::protocol_version().to_string(),
|
protocol_version: $item_ident::protocol_version().to_string(),
|
||||||
api_version: $item_ident::api_version().to_string(),
|
api_version: $item_ident::api_version().to_string(),
|
||||||
_reserved: vec![0u8; 64],
|
reserved: vec![0u8; 64],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut socket_ref = self.socket.borrow_mut();
|
let mut socket_ref = self.socket.borrow_mut();
|
||||||
|
@ -139,11 +139,11 @@ pub fn push_bin_box(
|
|||||||
|
|
||||||
let serialize_impl = quote_item!(cx,
|
let serialize_impl = quote_item!(cx,
|
||||||
impl ::serde::ser::Serialize for $ident {
|
impl ::serde::ser::Serialize for $ident {
|
||||||
fn serialize<__S>(&self, _serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
|
fn serialize<__S>(&self, serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
|
||||||
where __S: ::serde::ser::Serializer
|
where __S: ::serde::ser::Serializer
|
||||||
{
|
{
|
||||||
let &$ident(ref val) = self;
|
let &$ident(ref val) = self;
|
||||||
_serializer.serialize_bytes(val.as_slice())
|
serializer.serialize_bytes(val.as_slice())
|
||||||
}
|
}
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
//! Engine deserialization.
|
//! Engine deserialization.
|
||||||
|
|
||||||
use serde::{Deserializer, Error};
|
use serde::Deserializer;
|
||||||
use serde::de::Visitor;
|
use serde::de::Visitor;
|
||||||
use spec::Ethash;
|
use spec::Ethash;
|
||||||
|
|
||||||
|
@ -247,11 +247,11 @@ impl MinerService for Miner {
|
|||||||
match import {
|
match import {
|
||||||
Ok(ref res) => {
|
Ok(ref res) => {
|
||||||
trace!(target: "own_tx", "Imported transaction to {:?} (hash: {:?})", res, hash);
|
trace!(target: "own_tx", "Imported transaction to {:?} (hash: {:?})", res, hash);
|
||||||
trace!(target: "own_tx", "Status: {:?}", self.status());
|
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
|
||||||
},
|
},
|
||||||
Err(ref e) => {
|
Err(ref e) => {
|
||||||
trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash);
|
trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash);
|
||||||
trace!(target: "own_tx", "Status: {:?}", self.status());
|
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
import
|
import
|
||||||
|
@ -230,7 +230,7 @@ impl TransactionSet {
|
|||||||
by_hash.remove(&order.hash)
|
by_hash.remove(&order.hash)
|
||||||
.expect("Hash found in `by_priorty` matches the one dropped; so it is included in `by_hash`");
|
.expect("Hash found in `by_priorty` matches the one dropped; so it is included in `by_hash`");
|
||||||
|
|
||||||
let max = removed.get(&sender).map(|val| cmp::max(*val, nonce)).unwrap_or(nonce);
|
let max = removed.get(&sender).map_or(nonce, |val| cmp::max(*val, nonce));
|
||||||
removed.insert(sender, max);
|
removed.insert(sender, max);
|
||||||
removed
|
removed
|
||||||
}))
|
}))
|
||||||
|
223
parity/cli.rs
Normal file
223
parity/cli.rs
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use util::version;
|
||||||
|
|
||||||
|
pub const USAGE: &'static str = r#"
|
||||||
|
Parity. Ethereum Client.
|
||||||
|
By Wood/Paronyan/Kotewicz/Drwięga/Volf.
|
||||||
|
Copyright 2015, 2016 Ethcore (UK) Limited
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
parity daemon <pid-file> [options]
|
||||||
|
parity account (new | list) [options]
|
||||||
|
parity [options]
|
||||||
|
|
||||||
|
Protocol Options:
|
||||||
|
--chain CHAIN Specify the blockchain type. CHAIN may be either a
|
||||||
|
JSON chain specification file or olympic, frontier,
|
||||||
|
homestead, mainnet, morden, or testnet
|
||||||
|
[default: homestead].
|
||||||
|
-d --db-path PATH Specify the database & configuration directory path
|
||||||
|
[default: $HOME/.parity].
|
||||||
|
--keys-path PATH Specify the path for JSON key files to be found
|
||||||
|
[default: $HOME/.parity/keys].
|
||||||
|
--identity NAME Specify your node's name.
|
||||||
|
|
||||||
|
Account Options:
|
||||||
|
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
|
||||||
|
ACCOUNTS is a comma-delimited list of addresses.
|
||||||
|
--password FILE Provide a file containing a password for unlocking
|
||||||
|
an account.
|
||||||
|
|
||||||
|
Networking Options:
|
||||||
|
--port PORT Override the port on which the node should listen
|
||||||
|
[default: 30303].
|
||||||
|
--peers NUM Try to maintain that many peers [default: 25].
|
||||||
|
--nat METHOD Specify method to use for determining public
|
||||||
|
address. Must be one of: any, none, upnp,
|
||||||
|
extip:<IP> [default: any].
|
||||||
|
--network-id INDEX Override the network identifier from the chain we
|
||||||
|
are on.
|
||||||
|
--bootnodes NODES Override the bootnodes from our chain. NODES should
|
||||||
|
be comma-delimited enodes.
|
||||||
|
--no-discovery Disable new peer discovery.
|
||||||
|
--node-key KEY Specify node secret key, either as 64-character hex
|
||||||
|
string or input to SHA3 operation.
|
||||||
|
|
||||||
|
API and Console Options:
|
||||||
|
-j --jsonrpc Enable the JSON-RPC API server.
|
||||||
|
--jsonrpc-port PORT Specify the port portion of the JSONRPC API server
|
||||||
|
[default: 8545].
|
||||||
|
--jsonrpc-interface IP Specify the hostname portion of the JSONRPC API
|
||||||
|
server, IP should be an interface's IP address, or
|
||||||
|
all (all interfaces) or local [default: local].
|
||||||
|
--jsonrpc-cors URL Specify CORS header for JSON-RPC API responses.
|
||||||
|
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC
|
||||||
|
interface. APIS is a comma-delimited list of API
|
||||||
|
name. Possible name are web3, eth and net.
|
||||||
|
[default: web3,eth,net,personal,ethcore].
|
||||||
|
-w --webapp Enable the web applications server (e.g.
|
||||||
|
status page).
|
||||||
|
--webapp-port PORT Specify the port portion of the WebApps server
|
||||||
|
[default: 8080].
|
||||||
|
--webapp-interface IP Specify the hostname portion of the WebApps
|
||||||
|
server, IP should be an interface's IP address, or
|
||||||
|
all (all interfaces) or local [default: local].
|
||||||
|
--webapp-user USERNAME Specify username for WebApps server. It will be
|
||||||
|
used in HTTP Basic Authentication Scheme.
|
||||||
|
If --webapp-pass is not specified you will be
|
||||||
|
asked for password on startup.
|
||||||
|
--webapp-pass PASSWORD Specify password for WebApps server. Use only in
|
||||||
|
conjunction with --webapp-user.
|
||||||
|
|
||||||
|
Sealing/Mining Options:
|
||||||
|
--force-sealing Force the node to author new blocks as if it were
|
||||||
|
always sealing/mining.
|
||||||
|
--usd-per-tx USD Amount of USD to be paid for a basic transaction
|
||||||
|
[default: 0.005]. The minimum gas price is set
|
||||||
|
accordingly.
|
||||||
|
--usd-per-eth SOURCE USD value of a single ETH. SOURCE may be either an
|
||||||
|
amount in USD or a web service [default: etherscan].
|
||||||
|
--gas-floor-target GAS Amount of gas per block to target when sealing a new
|
||||||
|
block [default: 4712388].
|
||||||
|
--author ADDRESS Specify the block author (aka "coinbase") address
|
||||||
|
for sending block rewards from sealed blocks
|
||||||
|
[default: 0037a6b811ffeb6e072da21179d11b1406371c63].
|
||||||
|
--extra-data STRING Specify a custom extra-data for authored blocks, no
|
||||||
|
more than 32 characters.
|
||||||
|
--tx-limit LIMIT Limit of transactions kept in the queue (waiting to
|
||||||
|
be included in next block) [default: 1024].
|
||||||
|
|
||||||
|
Footprint Options:
|
||||||
|
--pruning METHOD Configure pruning of the state/storage trie. METHOD
|
||||||
|
may be one of auto, archive, basic, fast, light:
|
||||||
|
archive - keep all state trie data. No pruning.
|
||||||
|
basic - reference count in disk DB. Slow but light.
|
||||||
|
fast - maintain journal overlay. Fast but 50MB used.
|
||||||
|
light - early merges with partial tracking. Fast
|
||||||
|
and light. Experimental!
|
||||||
|
auto - use the method most recently synced or
|
||||||
|
default to archive if none synced [default: auto].
|
||||||
|
--cache-pref-size BYTES Specify the prefered size of the blockchain cache in
|
||||||
|
bytes [default: 16384].
|
||||||
|
--cache-max-size BYTES Specify the maximum size of the blockchain cache in
|
||||||
|
bytes [default: 262144].
|
||||||
|
--queue-max-size BYTES Specify the maximum size of memory to use for block
|
||||||
|
queue [default: 52428800].
|
||||||
|
--cache MEGABYTES Set total amount of discretionary memory to use for
|
||||||
|
the entire system, overrides other cache and queue
|
||||||
|
options.
|
||||||
|
|
||||||
|
Geth-compatibility Options:
|
||||||
|
--datadir PATH Equivalent to --db-path PATH.
|
||||||
|
--testnet Equivalent to --chain testnet.
|
||||||
|
--networkid INDEX Equivalent to --network-id INDEX.
|
||||||
|
--maxpeers COUNT Equivalent to --peers COUNT.
|
||||||
|
--nodekey KEY Equivalent to --node-key KEY.
|
||||||
|
--nodiscover Equivalent to --no-discovery.
|
||||||
|
--rpc Equivalent to --jsonrpc.
|
||||||
|
--rpcaddr IP Equivalent to --jsonrpc-interface IP.
|
||||||
|
--rpcport PORT Equivalent to --jsonrpc-port PORT.
|
||||||
|
--rpcapi APIS Equivalent to --jsonrpc-apis APIS.
|
||||||
|
--rpccorsdomain URL Equivalent to --jsonrpc-cors URL.
|
||||||
|
--gasprice WEI Minimum amount of Wei per GAS to be paid for a
|
||||||
|
transaction to be accepted for mining. Overrides
|
||||||
|
--basic-tx-usd.
|
||||||
|
--etherbase ADDRESS Equivalent to --author ADDRESS.
|
||||||
|
--extradata STRING Equivalent to --extra-data STRING.
|
||||||
|
|
||||||
|
Miscellaneous Options:
|
||||||
|
-l --logging LOGGING Specify the logging level. Must conform to the same
|
||||||
|
format as RUST_LOG.
|
||||||
|
-v --version Show information about version.
|
||||||
|
-h --help Show this screen.
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[derive(Debug, RustcDecodable)]
|
||||||
|
pub struct Args {
|
||||||
|
pub cmd_daemon: bool,
|
||||||
|
pub cmd_account: bool,
|
||||||
|
pub cmd_new: bool,
|
||||||
|
pub cmd_list: bool,
|
||||||
|
pub arg_pid_file: String,
|
||||||
|
pub flag_chain: String,
|
||||||
|
pub flag_db_path: String,
|
||||||
|
pub flag_identity: String,
|
||||||
|
pub flag_unlock: Option<String>,
|
||||||
|
pub flag_password: Vec<String>,
|
||||||
|
pub flag_cache: Option<usize>,
|
||||||
|
pub flag_keys_path: String,
|
||||||
|
pub flag_bootnodes: Option<String>,
|
||||||
|
pub flag_network_id: Option<String>,
|
||||||
|
pub flag_pruning: String,
|
||||||
|
pub flag_port: u16,
|
||||||
|
pub flag_peers: usize,
|
||||||
|
pub flag_no_discovery: bool,
|
||||||
|
pub flag_nat: String,
|
||||||
|
pub flag_node_key: Option<String>,
|
||||||
|
pub flag_cache_pref_size: usize,
|
||||||
|
pub flag_cache_max_size: usize,
|
||||||
|
pub flag_queue_max_size: usize,
|
||||||
|
pub flag_jsonrpc: bool,
|
||||||
|
pub flag_jsonrpc_interface: String,
|
||||||
|
pub flag_jsonrpc_port: u16,
|
||||||
|
pub flag_jsonrpc_cors: Option<String>,
|
||||||
|
pub flag_jsonrpc_apis: String,
|
||||||
|
pub flag_webapp: bool,
|
||||||
|
pub flag_webapp_port: u16,
|
||||||
|
pub flag_webapp_interface: String,
|
||||||
|
pub flag_webapp_user: Option<String>,
|
||||||
|
pub flag_webapp_pass: Option<String>,
|
||||||
|
pub flag_force_sealing: bool,
|
||||||
|
pub flag_author: String,
|
||||||
|
pub flag_usd_per_tx: String,
|
||||||
|
pub flag_usd_per_eth: String,
|
||||||
|
pub flag_gas_floor_target: String,
|
||||||
|
pub flag_extra_data: Option<String>,
|
||||||
|
pub flag_tx_limit: usize,
|
||||||
|
pub flag_logging: Option<String>,
|
||||||
|
pub flag_version: bool,
|
||||||
|
// geth-compatibility...
|
||||||
|
pub flag_nodekey: Option<String>,
|
||||||
|
pub flag_nodiscover: bool,
|
||||||
|
pub flag_maxpeers: Option<usize>,
|
||||||
|
pub flag_datadir: Option<String>,
|
||||||
|
pub flag_extradata: Option<String>,
|
||||||
|
pub flag_etherbase: Option<String>,
|
||||||
|
pub flag_gasprice: Option<String>,
|
||||||
|
pub flag_rpc: bool,
|
||||||
|
pub flag_rpcaddr: Option<String>,
|
||||||
|
pub flag_rpcport: Option<u16>,
|
||||||
|
pub flag_rpccorsdomain: Option<String>,
|
||||||
|
pub flag_rpcapi: Option<String>,
|
||||||
|
pub flag_testnet: bool,
|
||||||
|
pub flag_networkid: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_version() {
|
||||||
|
println!("\
|
||||||
|
Parity
|
||||||
|
version {}
|
||||||
|
Copyright 2015, 2016 Ethcore (UK) Limited
|
||||||
|
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
||||||
|
This is free software: you are free to change and redistribute it.
|
||||||
|
There is NO WARRANTY, to the extent permitted by law.
|
||||||
|
|
||||||
|
By Wood/Paronyan/Kotewicz/Drwięga/Volf.\
|
||||||
|
", version());
|
||||||
|
}
|
||||||
|
|
253
parity/configuration.rs
Normal file
253
parity/configuration.rs
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use std::net::{SocketAddr, IpAddr};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use cli::{USAGE, Args};
|
||||||
|
use docopt::Docopt;
|
||||||
|
|
||||||
|
use die::*;
|
||||||
|
use util::*;
|
||||||
|
use util::keys::store::AccountService;
|
||||||
|
use util::network_settings::NetworkSettings;
|
||||||
|
use ethcore::client::{append_path, get_db_path, ClientConfig};
|
||||||
|
use ethcore::ethereum;
|
||||||
|
use ethcore::spec::Spec;
|
||||||
|
use ethsync::SyncConfig;
|
||||||
|
use price_info::PriceInfo;
|
||||||
|
|
||||||
|
pub struct Configuration {
|
||||||
|
pub args: Args
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Configuration {
|
||||||
|
pub fn parse() -> Self {
|
||||||
|
Configuration {
|
||||||
|
args: Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> String {
|
||||||
|
let d = self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path);
|
||||||
|
d.replace("$HOME", env::home_dir().unwrap().to_str().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn author(&self) -> Address {
|
||||||
|
let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author);
|
||||||
|
Address::from_str(clean_0x(d)).unwrap_or_else(|_| {
|
||||||
|
die!("{}: Invalid address for --author. Must be 40 hex characters, with or without the 0x at the beginning.", d)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gas_floor_target(&self) -> U256 {
|
||||||
|
let d = &self.args.flag_gas_floor_target;
|
||||||
|
U256::from_dec_str(d).unwrap_or_else(|_| {
|
||||||
|
die!("{}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number.", d)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gas_price(&self) -> U256 {
|
||||||
|
match self.args.flag_gasprice.as_ref() {
|
||||||
|
Some(d) => {
|
||||||
|
U256::from_dec_str(d).unwrap_or_else(|_| {
|
||||||
|
die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", d)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let usd_per_tx: f32 = FromStr::from_str(&self.args.flag_usd_per_tx).unwrap_or_else(|_| {
|
||||||
|
die!("{}: Invalid basic transaction price given in USD. Must be a decimal number.", self.args.flag_usd_per_tx)
|
||||||
|
});
|
||||||
|
let usd_per_eth = match self.args.flag_usd_per_eth.as_str() {
|
||||||
|
"etherscan" => PriceInfo::get().map_or_else(|| {
|
||||||
|
die!("Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth.")
|
||||||
|
}, |x| x.ethusd),
|
||||||
|
x => FromStr::from_str(x).unwrap_or_else(|_| die!("{}: Invalid ether price given in USD. Must be a decimal number.", x))
|
||||||
|
};
|
||||||
|
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
|
||||||
|
let gas_per_tx: f32 = 21000.0;
|
||||||
|
let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx;
|
||||||
|
info!("Using a conversion rate of Ξ1 = US${} ({} wei/gas)", usd_per_eth, wei_per_gas);
|
||||||
|
U256::from_dec_str(&format!("{:.0}", wei_per_gas)).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extra_data(&self) -> Bytes {
|
||||||
|
match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) {
|
||||||
|
Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(),
|
||||||
|
None => version_data(),
|
||||||
|
Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys_path(&self) -> String {
|
||||||
|
self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spec(&self) -> Spec {
|
||||||
|
if self.args.flag_testnet {
|
||||||
|
return ethereum::new_morden();
|
||||||
|
}
|
||||||
|
match self.args.flag_chain.as_ref() {
|
||||||
|
"frontier" | "homestead" | "mainnet" => ethereum::new_frontier(),
|
||||||
|
"morden" | "testnet" => ethereum::new_morden(),
|
||||||
|
"olympic" => ethereum::new_olympic(),
|
||||||
|
f => Spec::load(contents(f).unwrap_or_else(|_| {
|
||||||
|
die!("{}: Couldn't read chain specification file. Sure it exists?", f)
|
||||||
|
}).as_ref()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize_enode(e: &str) -> Option<String> {
|
||||||
|
if is_valid_node_url(e) {
|
||||||
|
Some(e.to_owned())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_nodes(&self, spec: &Spec) -> Vec<String> {
|
||||||
|
match self.args.flag_bootnodes {
|
||||||
|
Some(ref x) if !x.is_empty() => x.split(',').map(|s| {
|
||||||
|
Self::normalize_enode(s).unwrap_or_else(|| {
|
||||||
|
die!("{}: Invalid node address format given for a boot node.", s)
|
||||||
|
})
|
||||||
|
}).collect(),
|
||||||
|
Some(_) => Vec::new(),
|
||||||
|
None => spec.nodes().clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn net_addresses(&self) -> (Option<SocketAddr>, Option<SocketAddr>) {
|
||||||
|
let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), self.args.flag_port));
|
||||||
|
let public_address = if self.args.flag_nat.starts_with("extip:") {
|
||||||
|
let host = &self.args.flag_nat[6..];
|
||||||
|
let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host));
|
||||||
|
Some(SocketAddr::new(host, self.args.flag_port))
|
||||||
|
} else {
|
||||||
|
listen_address
|
||||||
|
};
|
||||||
|
(listen_address, public_address)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn net_settings(&self, spec: &Spec) -> NetworkConfiguration {
|
||||||
|
let mut ret = NetworkConfiguration::new();
|
||||||
|
ret.nat_enabled = self.args.flag_nat == "any" || self.args.flag_nat == "upnp";
|
||||||
|
ret.boot_nodes = self.init_nodes(spec);
|
||||||
|
let (listen, public) = self.net_addresses();
|
||||||
|
ret.listen_address = listen;
|
||||||
|
ret.public_address = public;
|
||||||
|
ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3()));
|
||||||
|
ret.discovery_enabled = !self.args.flag_no_discovery && !self.args.flag_nodiscover;
|
||||||
|
ret.ideal_peers = self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32;
|
||||||
|
let mut net_path = PathBuf::from(&self.path());
|
||||||
|
net_path.push("network");
|
||||||
|
ret.config_path = Some(net_path.to_str().unwrap().to_owned());
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_best_db(&self, spec: &Spec) -> Option<journaldb::Algorithm> {
|
||||||
|
let mut ret = None;
|
||||||
|
let mut latest_era = None;
|
||||||
|
let jdb_types = [journaldb::Algorithm::Archive, journaldb::Algorithm::EarlyMerge, journaldb::Algorithm::OverlayRecent, journaldb::Algorithm::RefCounted];
|
||||||
|
for i in jdb_types.into_iter() {
|
||||||
|
let db = journaldb::new(&append_path(&get_db_path(&Path::new(&self.path()), *i, spec.genesis_header().hash()), "state"), *i);
|
||||||
|
trace!(target: "parity", "Looking for best DB: {} at {:?}", i, db.latest_era());
|
||||||
|
match (latest_era, db.latest_era()) {
|
||||||
|
(Some(best), Some(this)) if best >= this => {}
|
||||||
|
(_, None) => {}
|
||||||
|
(_, Some(this)) => {
|
||||||
|
latest_era = Some(this);
|
||||||
|
ret = Some(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn client_config(&self, spec: &Spec) -> ClientConfig {
|
||||||
|
let mut client_config = ClientConfig::default();
|
||||||
|
match self.args.flag_cache {
|
||||||
|
Some(mb) => {
|
||||||
|
client_config.blockchain.max_cache_size = mb * 1024 * 1024;
|
||||||
|
client_config.blockchain.pref_cache_size = client_config.blockchain.max_cache_size * 3 / 4;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
client_config.blockchain.pref_cache_size = self.args.flag_cache_pref_size;
|
||||||
|
client_config.blockchain.max_cache_size = self.args.flag_cache_max_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client_config.pruning = match self.args.flag_pruning.as_str() {
|
||||||
|
"archive" => journaldb::Algorithm::Archive,
|
||||||
|
"light" => journaldb::Algorithm::EarlyMerge,
|
||||||
|
"fast" => journaldb::Algorithm::OverlayRecent,
|
||||||
|
"basic" => journaldb::Algorithm::RefCounted,
|
||||||
|
"auto" => self.find_best_db(spec).unwrap_or(journaldb::Algorithm::OverlayRecent),
|
||||||
|
_ => { die!("Invalid pruning method given."); }
|
||||||
|
};
|
||||||
|
trace!(target: "parity", "Using pruning strategy of {}", client_config.pruning);
|
||||||
|
client_config.name = self.args.flag_identity.clone();
|
||||||
|
client_config.queue.max_mem_use = self.args.flag_queue_max_size;
|
||||||
|
client_config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sync_config(&self, spec: &Spec) -> SyncConfig {
|
||||||
|
let mut sync_config = SyncConfig::default();
|
||||||
|
sync_config.network_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref()).map_or(spec.network_id(), |id| {
|
||||||
|
U256::from_str(id).unwrap_or_else(|_| die!("{}: Invalid index given with --network-id/--networkid", id))
|
||||||
|
});
|
||||||
|
sync_config
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn account_service(&self) -> AccountService {
|
||||||
|
// Secret Store
|
||||||
|
let passwords = self.args.flag_password.iter().flat_map(|filename| {
|
||||||
|
BufReader::new(&File::open(filename).unwrap_or_else(|_| die!("{} Unable to read password file. Ensure it exists and permissions are correct.", filename)))
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.unwrap())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
let account_service = AccountService::new_in(Path::new(&self.keys_path()));
|
||||||
|
if let Some(ref unlocks) = self.args.flag_unlock {
|
||||||
|
for d in unlocks.split(',') {
|
||||||
|
let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| {
|
||||||
|
die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d)
|
||||||
|
});
|
||||||
|
if passwords.iter().find(|p| account_service.unlock_account_no_expire(&a, p).is_ok()).is_none() {
|
||||||
|
die!("No password given to unlock account {}. Pass the password using `--password`.", a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
account_service
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn network_settings(&self) -> NetworkSettings {
|
||||||
|
NetworkSettings {
|
||||||
|
name: self.args.flag_identity.clone(),
|
||||||
|
chain: self.args.flag_chain.clone(),
|
||||||
|
max_peers: self.args.flag_maxpeers.unwrap_or(self.args.flag_peers),
|
||||||
|
network_port: self.args.flag_port,
|
||||||
|
rpc_enabled: self.args.flag_rpc || self.args.flag_jsonrpc,
|
||||||
|
rpc_interface: self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()),
|
||||||
|
rpc_port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
54
parity/die.rs
Normal file
54
parity/die.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std;
|
||||||
|
use ethcore;
|
||||||
|
use util::UtilError;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! die {
|
||||||
|
($($arg:tt)*) => (die_with_message(&format!("{}", format_args!($($arg)*))));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn die_with_error(e: ethcore::error::Error) -> ! {
|
||||||
|
use ethcore::error::Error;
|
||||||
|
|
||||||
|
match e {
|
||||||
|
Error::Util(UtilError::StdIo(e)) => die_with_io_error(e),
|
||||||
|
_ => die!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn die_with_io_error(e: std::io::Error) -> ! {
|
||||||
|
match e.kind() {
|
||||||
|
std::io::ErrorKind::PermissionDenied => {
|
||||||
|
die!("No permissions to bind to specified port.")
|
||||||
|
},
|
||||||
|
std::io::ErrorKind::AddrInUse => {
|
||||||
|
die!("Specified address is already in use. Please make sure that nothing is listening on the same port or try using a different one.")
|
||||||
|
},
|
||||||
|
std::io::ErrorKind::AddrNotAvailable => {
|
||||||
|
die!("Could not use specified interface or given address is invalid.")
|
||||||
|
},
|
||||||
|
_ => die!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn die_with_message(msg: &str) -> ! {
|
||||||
|
println!("ERROR: {}", msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
// while not included in binary
|
// while not included in binary
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
#![cfg_attr(feature="dev", allow(used_underscore_binding))]
|
||||||
|
|
||||||
pub mod service;
|
pub mod service;
|
||||||
|
|
||||||
@ -41,6 +42,12 @@ pub struct Hypervisor {
|
|||||||
processes: RwLock<HashMap<BinaryId, Child>>,
|
processes: RwLock<HashMap<BinaryId, Child>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Hypervisor {
|
||||||
|
fn default() -> Self {
|
||||||
|
Hypervisor::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Hypervisor {
|
impl Hypervisor {
|
||||||
/// initializes the Hypervisor service with the open ipc socket for incoming clients
|
/// initializes the Hypervisor service with the open ipc socket for incoming clients
|
||||||
pub fn new() -> Hypervisor {
|
pub fn new() -> Hypervisor {
|
||||||
@ -116,6 +123,7 @@ impl Hypervisor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::sync::atomic::{AtomicBool,Ordering};
|
use std::sync::atomic::{AtomicBool,Ordering};
|
||||||
|
89
parity/informant.rs
Normal file
89
parity/informant.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use ethsync::{EthSync, SyncProvider};
|
||||||
|
use ethcore::client::*;
|
||||||
|
use number_prefix::{binary_prefix, Standalone, Prefixed};
|
||||||
|
|
||||||
|
pub struct Informant {
|
||||||
|
chain_info: RwLock<Option<BlockChainInfo>>,
|
||||||
|
cache_info: RwLock<Option<BlockChainCacheSize>>,
|
||||||
|
report: RwLock<Option<ClientReport>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Informant {
|
||||||
|
fn default() -> Self {
|
||||||
|
Informant {
|
||||||
|
chain_info: RwLock::new(None),
|
||||||
|
cache_info: RwLock::new(None),
|
||||||
|
report: RwLock::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Informant {
|
||||||
|
fn format_bytes(b: usize) -> String {
|
||||||
|
match binary_prefix(b as f64) {
|
||||||
|
Standalone(bytes) => format!("{} bytes", bytes),
|
||||||
|
Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&self, client: &Client, sync: &EthSync) {
|
||||||
|
// 5 seconds betwen calls. TODO: calculate this properly.
|
||||||
|
let dur = 5usize;
|
||||||
|
|
||||||
|
let chain_info = client.chain_info();
|
||||||
|
let queue_info = client.queue_info();
|
||||||
|
let cache_info = client.blockchain_cache_info();
|
||||||
|
let sync_info = sync.status();
|
||||||
|
|
||||||
|
let mut write_report = self.report.write().unwrap();
|
||||||
|
let report = client.report();
|
||||||
|
|
||||||
|
if let (_, _, &Some(ref last_report)) = (
|
||||||
|
self.chain_info.read().unwrap().deref(),
|
||||||
|
self.cache_info.read().unwrap().deref(),
|
||||||
|
write_report.deref()
|
||||||
|
) {
|
||||||
|
println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} db, {} chain, {} queue, {} sync ]",
|
||||||
|
chain_info.best_block_number,
|
||||||
|
chain_info.best_block_hash,
|
||||||
|
(report.blocks_imported - last_report.blocks_imported) / dur,
|
||||||
|
(report.transactions_applied - last_report.transactions_applied) / dur,
|
||||||
|
(report.gas_processed - last_report.gas_processed) / From::from(dur),
|
||||||
|
|
||||||
|
sync_info.num_active_peers,
|
||||||
|
sync_info.num_peers,
|
||||||
|
sync_info.last_imported_block_number.unwrap_or(chain_info.best_block_number),
|
||||||
|
queue_info.unverified_queue_size,
|
||||||
|
queue_info.verified_queue_size,
|
||||||
|
|
||||||
|
Informant::format_bytes(report.state_db_mem),
|
||||||
|
Informant::format_bytes(cache_info.total()),
|
||||||
|
Informant::format_bytes(queue_info.mem_used),
|
||||||
|
Informant::format_bytes(sync_info.mem_used),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
*self.chain_info.write().unwrap().deref_mut() = Some(chain_info);
|
||||||
|
*self.cache_info.write().unwrap().deref_mut() = Some(cache_info);
|
||||||
|
*write_report.deref_mut() = Some(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
54
parity/io_handler.rs
Normal file
54
parity/io_handler.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use ethcore::client::Client;
|
||||||
|
use ethcore::service::NetSyncMessage;
|
||||||
|
use ethsync::EthSync;
|
||||||
|
use util::keys::store::AccountService;
|
||||||
|
use util::{TimerToken, IoHandler, IoContext};
|
||||||
|
|
||||||
|
use informant::Informant;
|
||||||
|
|
||||||
|
const INFO_TIMER: TimerToken = 0;
|
||||||
|
|
||||||
|
const ACCOUNT_TICK_TIMER: TimerToken = 10;
|
||||||
|
const ACCOUNT_TICK_MS: u64 = 60000;
|
||||||
|
|
||||||
|
pub struct ClientIoHandler {
|
||||||
|
pub client: Arc<Client>,
|
||||||
|
pub sync: Arc<EthSync>,
|
||||||
|
pub accounts: Arc<AccountService>,
|
||||||
|
pub info: Informant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoHandler<NetSyncMessage> for ClientIoHandler {
|
||||||
|
fn initialize(&self, io: &IoContext<NetSyncMessage>) {
|
||||||
|
io.register_timer(INFO_TIMER, 5000).expect("Error registering timer");
|
||||||
|
io.register_timer(ACCOUNT_TICK_TIMER, ACCOUNT_TICK_MS).expect("Error registering account timer");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timeout(&self, _io: &IoContext<NetSyncMessage>, timer: TimerToken) {
|
||||||
|
match timer {
|
||||||
|
INFO_TIMER => { self.info.tick(&self.client, &self.sync); }
|
||||||
|
ACCOUNT_TICK_TIMER => { self.accounts.tick(); },
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
1017
parity/main.rs
1017
parity/main.rs
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,19 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use rustc_serialize::json::Json;
|
use rustc_serialize::json::Json;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use hyper::Client;
|
use hyper::Client;
|
||||||
|
112
parity/rpc.rs
Normal file
112
parity/rpc.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use ethcore::client::Client;
|
||||||
|
use ethsync::EthSync;
|
||||||
|
use ethminer::Miner;
|
||||||
|
use util::RotatingLogger;
|
||||||
|
use util::keys::store::{AccountService};
|
||||||
|
use util::network_settings::NetworkSettings;
|
||||||
|
use die::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "rpc")]
|
||||||
|
pub use ethcore_rpc::Server as RpcServer;
|
||||||
|
#[cfg(feature = "rpc")]
|
||||||
|
use ethcore_rpc::{RpcServerError, RpcServer as Server};
|
||||||
|
#[cfg(not(feature = "rpc"))]
|
||||||
|
pub struct RpcServer;
|
||||||
|
|
||||||
|
pub struct Configuration {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub interface: String,
|
||||||
|
pub port: u16,
|
||||||
|
pub apis: String,
|
||||||
|
pub cors: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Dependencies {
|
||||||
|
pub client: Arc<Client>,
|
||||||
|
pub sync: Arc<EthSync>,
|
||||||
|
pub secret_store: Arc<AccountService>,
|
||||||
|
pub miner: Arc<Miner>,
|
||||||
|
pub logger: Arc<RotatingLogger>,
|
||||||
|
pub settings: Arc<NetworkSettings>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(conf: Configuration, deps: Dependencies) -> Option<RpcServer> {
|
||||||
|
if !conf.enabled {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let interface = match conf.interface.as_str() {
|
||||||
|
"all" => "0.0.0.0",
|
||||||
|
"local" => "127.0.0.1",
|
||||||
|
x => x,
|
||||||
|
};
|
||||||
|
let apis = conf.apis.split(',').collect();
|
||||||
|
let url = format!("{}:{}", interface, conf.port);
|
||||||
|
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url));
|
||||||
|
|
||||||
|
Some(setup_rpc_server(deps, &addr, conf.cors, apis))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "rpc"))]
|
||||||
|
pub fn setup_rpc_server(
|
||||||
|
_deps: Dependencies,
|
||||||
|
_url: &SocketAddr,
|
||||||
|
_cors_domain: Option<String>,
|
||||||
|
_apis: Vec<&str>,
|
||||||
|
) -> ! {
|
||||||
|
die!("Your Parity version has been compiled without JSON-RPC support.")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rpc")]
|
||||||
|
pub fn setup_rpc_server(
|
||||||
|
deps: Dependencies,
|
||||||
|
url: &SocketAddr,
|
||||||
|
cors_domain: Option<String>,
|
||||||
|
apis: Vec<&str>,
|
||||||
|
) -> RpcServer {
|
||||||
|
use ethcore_rpc::v1::*;
|
||||||
|
|
||||||
|
let server = Server::new();
|
||||||
|
for api in apis.into_iter() {
|
||||||
|
match api {
|
||||||
|
"web3" => server.add_delegate(Web3Client::new().to_delegate()),
|
||||||
|
"net" => server.add_delegate(NetClient::new(&deps.sync).to_delegate()),
|
||||||
|
"eth" => {
|
||||||
|
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner).to_delegate());
|
||||||
|
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
|
||||||
|
},
|
||||||
|
"personal" => server.add_delegate(PersonalClient::new(&deps.secret_store).to_delegate()),
|
||||||
|
"ethcore" => server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()),
|
||||||
|
_ => {
|
||||||
|
die!("{}: Invalid API name to be enabled.", api);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let start_result = server.start_http(url, cors_domain);
|
||||||
|
match start_result {
|
||||||
|
Err(RpcServerError::IoError(err)) => die_with_io_error(err),
|
||||||
|
Err(e) => die!("{:?}", e),
|
||||||
|
Ok(server) => server,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
60
parity/setup_log.rs
Normal file
60
parity/setup_log.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use time;
|
||||||
|
use env_logger::LogBuilder;
|
||||||
|
use util::{RotatingLogger};
|
||||||
|
|
||||||
|
/// Sets up the logger
|
||||||
|
pub fn setup_log(init: &Option<String>) -> Arc<RotatingLogger> {
|
||||||
|
use rlog::*;
|
||||||
|
|
||||||
|
let mut levels = String::new();
|
||||||
|
let mut builder = LogBuilder::new();
|
||||||
|
builder.filter(None, LogLevelFilter::Info);
|
||||||
|
|
||||||
|
if env::var("RUST_LOG").is_ok() {
|
||||||
|
let lvl = &env::var("RUST_LOG").unwrap();
|
||||||
|
levels.push_str(&lvl);
|
||||||
|
levels.push_str(",");
|
||||||
|
builder.parse(lvl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref s) = *init {
|
||||||
|
levels.push_str(s);
|
||||||
|
builder.parse(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
let logs = Arc::new(RotatingLogger::new(levels));
|
||||||
|
let logger = logs.clone();
|
||||||
|
let format = move |record: &LogRecord| {
|
||||||
|
let timestamp = time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now()).unwrap();
|
||||||
|
let format = if max_log_level() <= LogLevelFilter::Info {
|
||||||
|
format!("{}{}", timestamp, record.args())
|
||||||
|
} else {
|
||||||
|
format!("{}{}:{}: {}", timestamp, record.level(), record.target(), record.args())
|
||||||
|
};
|
||||||
|
logger.append(format.clone());
|
||||||
|
format
|
||||||
|
};
|
||||||
|
builder.format(format);
|
||||||
|
builder.init().unwrap();
|
||||||
|
logs
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ use std::collections::*;
|
|||||||
use std::fs::{File, create_dir_all};
|
use std::fs::{File, create_dir_all};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[cfg_attr(feature="dev", allow(enum_variant_names))]
|
#[cfg_attr(feature="dev", allow(enum_variant_names))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -99,7 +100,7 @@ fn with_locked_version<F>(db_path: Option<&str>, script: F) -> Result<usize, Err
|
|||||||
let mut path = env::home_dir().expect("Applications should have a home dir");
|
let mut path = env::home_dir().expect("Applications should have a home dir");
|
||||||
path.push(".parity");
|
path.push(".parity");
|
||||||
path
|
path
|
||||||
}, |s| ::std::path::PathBuf::from(s));
|
}, PathBuf::from);
|
||||||
try!(create_dir_all(&path).map_err(|_| Error::CannotCreateConfigPath));
|
try!(create_dir_all(&path).map_err(|_| Error::CannotCreateConfigPath));
|
||||||
path.push("ver.lock");
|
path.push("ver.lock");
|
||||||
|
|
||||||
|
119
parity/webapp.rs
Normal file
119
parity/webapp.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use ethcore::client::Client;
|
||||||
|
use ethsync::EthSync;
|
||||||
|
use ethminer::Miner;
|
||||||
|
use util::RotatingLogger;
|
||||||
|
use util::keys::store::{AccountService};
|
||||||
|
use util::network_settings::NetworkSettings;
|
||||||
|
use die::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "webapp")]
|
||||||
|
pub use ethcore_webapp::Server as WebappServer;
|
||||||
|
#[cfg(not(feature = "webapp"))]
|
||||||
|
pub struct WebappServer;
|
||||||
|
|
||||||
|
pub struct Configuration {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub interface: String,
|
||||||
|
pub port: u16,
|
||||||
|
pub user: Option<String>,
|
||||||
|
pub pass: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Dependencies {
|
||||||
|
pub client: Arc<Client>,
|
||||||
|
pub sync: Arc<EthSync>,
|
||||||
|
pub secret_store: Arc<AccountService>,
|
||||||
|
pub miner: Arc<Miner>,
|
||||||
|
pub logger: Arc<RotatingLogger>,
|
||||||
|
pub settings: Arc<NetworkSettings>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(configuration: Configuration, deps: Dependencies) -> Option<WebappServer> {
|
||||||
|
if !configuration.enabled {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let interface = match configuration.interface.as_str() {
|
||||||
|
"all" => "0.0.0.0",
|
||||||
|
"local" => "127.0.0.1",
|
||||||
|
x => x,
|
||||||
|
};
|
||||||
|
let url = format!("{}:{}", interface, configuration.port);
|
||||||
|
let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid Webapps listen host/port given.", url));
|
||||||
|
|
||||||
|
let auth = configuration.user.as_ref().map(|username| {
|
||||||
|
let password = configuration.pass.as_ref().map_or_else(|| {
|
||||||
|
use rpassword::read_password;
|
||||||
|
println!("Type password for WebApps server (user: {}): ", username);
|
||||||
|
let pass = read_password().unwrap();
|
||||||
|
println!("OK, got it. Starting server...");
|
||||||
|
pass
|
||||||
|
}, |pass| pass.to_owned());
|
||||||
|
(username.to_owned(), password)
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(setup_webapp_server(deps, &addr, auth))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "webapp"))]
|
||||||
|
pub fn setup_webapp_server(
|
||||||
|
_deps: Dependencies,
|
||||||
|
_url: &SocketAddr,
|
||||||
|
_auth: Option<(String, String)>,
|
||||||
|
) -> ! {
|
||||||
|
die!("Your Parity version has been compiled without WebApps support.")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "webapp")]
|
||||||
|
pub fn setup_webapp_server(
|
||||||
|
deps: Dependencies,
|
||||||
|
url: &SocketAddr,
|
||||||
|
auth: Option<(String, String)>
|
||||||
|
) -> WebappServer {
|
||||||
|
use ethcore_rpc::v1::*;
|
||||||
|
use ethcore_webapp as webapp;
|
||||||
|
|
||||||
|
let server = webapp::ServerBuilder::new();
|
||||||
|
server.add_delegate(Web3Client::new().to_delegate());
|
||||||
|
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
|
||||||
|
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner).to_delegate());
|
||||||
|
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
|
||||||
|
server.add_delegate(PersonalClient::new(&deps.secret_store).to_delegate());
|
||||||
|
server.add_delegate(EthcoreClient::new(&deps.miner, deps.logger, deps.settings).to_delegate());
|
||||||
|
|
||||||
|
let start_result = match auth {
|
||||||
|
None => {
|
||||||
|
server.start_unsecure_http(url)
|
||||||
|
},
|
||||||
|
Some((username, password)) => {
|
||||||
|
server.start_basic_auth_http(url, &username, &password)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
match start_result {
|
||||||
|
Err(webapp::ServerError::IoError(err)) => die_with_io_error(err),
|
||||||
|
Err(e) => die!("{:?}", e),
|
||||||
|
Ok(handle) => handle,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
//! Ethcore-specific rpc implementation.
|
//! Ethcore-specific rpc implementation.
|
||||||
use util::{U256, Address, RotatingLogger};
|
use util::{U256, Address, RotatingLogger};
|
||||||
|
use util::network_settings::NetworkSettings;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::*;
|
||||||
use ethminer::{MinerService};
|
use ethminer::{MinerService};
|
||||||
use v1::traits::Ethcore;
|
use v1::traits::Ethcore;
|
||||||
@ -28,14 +30,16 @@ pub struct EthcoreClient<M>
|
|||||||
where M: MinerService {
|
where M: MinerService {
|
||||||
miner: Weak<M>,
|
miner: Weak<M>,
|
||||||
logger: Arc<RotatingLogger>,
|
logger: Arc<RotatingLogger>,
|
||||||
|
settings: Arc<NetworkSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> EthcoreClient<M> where M: MinerService {
|
impl<M> EthcoreClient<M> where M: MinerService {
|
||||||
/// Creates new `EthcoreClient`.
|
/// Creates new `EthcoreClient`.
|
||||||
pub fn new(miner: &Arc<M>, logger: Arc<RotatingLogger>) -> Self {
|
pub fn new(miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>) -> Self {
|
||||||
EthcoreClient {
|
EthcoreClient {
|
||||||
miner: Arc::downgrade(miner),
|
miner: Arc::downgrade(miner),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
settings: settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,4 +106,27 @@ impl<M> Ethcore for EthcoreClient<M> where M: MinerService + 'static {
|
|||||||
to_value(&self.logger.levels())
|
to_value(&self.logger.levels())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn net_chain(&self, _params: Params) -> Result<Value, Error> {
|
||||||
|
to_value(&self.settings.chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn net_max_peers(&self, _params: Params) -> Result<Value, Error> {
|
||||||
|
to_value(&self.settings.max_peers)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn net_port(&self, _params: Params) -> Result<Value, Error> {
|
||||||
|
to_value(&self.settings.network_port)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn node_name(&self, _params: Params) -> Result<Value, Error> {
|
||||||
|
to_value(&self.settings.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rpc_settings(&self, _params: Params) -> Result<Value, Error> {
|
||||||
|
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()));
|
||||||
|
map.insert("port".to_owned(), Value::U64(self.settings.rpc_port as u64));
|
||||||
|
Ok(Value::Object(map))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use v1::tests::helpers::TestMinerService;
|
|||||||
use util::numbers::*;
|
use util::numbers::*;
|
||||||
use rustc_serialize::hex::FromHex;
|
use rustc_serialize::hex::FromHex;
|
||||||
use util::log::RotatingLogger;
|
use util::log::RotatingLogger;
|
||||||
|
use util::network_settings::NetworkSettings;
|
||||||
|
|
||||||
|
|
||||||
fn miner_service() -> Arc<TestMinerService> {
|
fn miner_service() -> Arc<TestMinerService> {
|
||||||
@ -32,10 +33,26 @@ fn logger() -> Arc<RotatingLogger> {
|
|||||||
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
|
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn settings() -> Arc<NetworkSettings> {
|
||||||
|
Arc::new(NetworkSettings {
|
||||||
|
name: "mynode".to_owned(),
|
||||||
|
chain: "testchain".to_owned(),
|
||||||
|
max_peers: 25,
|
||||||
|
network_port: 30303,
|
||||||
|
rpc_enabled: true,
|
||||||
|
rpc_interface: "all".to_owned(),
|
||||||
|
rpc_port: 8545,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ethcore_client(miner: &Arc<TestMinerService>) -> EthcoreClient<TestMinerService> {
|
||||||
|
EthcoreClient::new(&miner, logger(), settings())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_extra_data() {
|
fn rpc_ethcore_extra_data() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -49,7 +66,7 @@ fn rpc_ethcore_extra_data() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_gas_floor_target() {
|
fn rpc_ethcore_gas_floor_target() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -62,7 +79,7 @@ fn rpc_ethcore_gas_floor_target() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_min_gas_price() {
|
fn rpc_ethcore_min_gas_price() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -75,7 +92,7 @@ fn rpc_ethcore_min_gas_price() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_set_min_gas_price() {
|
fn rpc_ethcore_set_min_gas_price() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -89,7 +106,7 @@ fn rpc_ethcore_set_min_gas_price() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_set_gas_floor_target() {
|
fn rpc_ethcore_set_gas_floor_target() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -103,7 +120,7 @@ fn rpc_ethcore_set_gas_floor_target() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_set_extra_data() {
|
fn rpc_ethcore_set_extra_data() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -117,7 +134,7 @@ fn rpc_ethcore_set_extra_data() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_set_author() {
|
fn rpc_ethcore_set_author() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -134,7 +151,7 @@ fn rpc_ethcore_dev_logs() {
|
|||||||
let logger = logger();
|
let logger = logger();
|
||||||
logger.append("a".to_owned());
|
logger.append("a".to_owned());
|
||||||
logger.append("b".to_owned());
|
logger.append("b".to_owned());
|
||||||
let ethcore = EthcoreClient::new(&miner, logger.clone()).to_delegate();
|
let ethcore = EthcoreClient::new(&miner, logger.clone(), settings()).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -147,7 +164,7 @@ fn rpc_ethcore_dev_logs() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_dev_logs_levels() {
|
fn rpc_ethcore_dev_logs_levels() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -156,9 +173,10 @@ fn rpc_ethcore_dev_logs_levels() {
|
|||||||
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
fn rpc_ethcore_set_transactions_limit() {
|
fn rpc_ethcore_set_transactions_limit() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -169,11 +187,10 @@ fn rpc_ethcore_set_transactions_limit() {
|
|||||||
assert_eq!(miner.transactions_limit(), 10_240_240);
|
assert_eq!(miner.transactions_limit(), 10_240_240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_ethcore_transactions_limit() {
|
fn rpc_ethcore_transactions_limit() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let ethcore = EthcoreClient::new(&miner, logger()).to_delegate();
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(ethcore);
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
@ -182,3 +199,68 @@ fn rpc_ethcore_transactions_limit() {
|
|||||||
|
|
||||||
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_ethcore_net_chain() {
|
||||||
|
let miner = miner_service();
|
||||||
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
|
let io = IoHandler::new();
|
||||||
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":"testchain","id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_ethcore_net_max_peers() {
|
||||||
|
let miner = miner_service();
|
||||||
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
|
let io = IoHandler::new();
|
||||||
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":25,"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_ethcore_net_port() {
|
||||||
|
let miner = miner_service();
|
||||||
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
|
let io = IoHandler::new();
|
||||||
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":30303,"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_ethcore_rpc_settings() {
|
||||||
|
let miner = miner_service();
|
||||||
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
|
let io = IoHandler::new();
|
||||||
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
|
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}"#;
|
||||||
|
|
||||||
|
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_ethcore_node_name() {
|
||||||
|
let miner = miner_service();
|
||||||
|
let ethcore = ethcore_client(&miner).to_delegate();
|
||||||
|
let io = IoHandler::new();
|
||||||
|
io.add_delegate(ethcore);
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":"mynode","id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
@ -54,6 +54,21 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
|
|||||||
/// Returns logs levels
|
/// Returns logs levels
|
||||||
fn dev_logs_levels(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
fn dev_logs_levels(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Returns chain name
|
||||||
|
fn net_chain(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Returns max peers
|
||||||
|
fn net_max_peers(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Returns network port
|
||||||
|
fn net_port(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Returns rpc settings
|
||||||
|
fn rpc_settings(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
|
/// Returns node name
|
||||||
|
fn node_name(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
|
||||||
|
|
||||||
/// Should be used to convert object to io delegate.
|
/// Should be used to convert object to io delegate.
|
||||||
fn to_delegate(self) -> IoDelegate<Self> {
|
fn to_delegate(self) -> IoDelegate<Self> {
|
||||||
let mut delegate = IoDelegate::new(Arc::new(self));
|
let mut delegate = IoDelegate::new(Arc::new(self));
|
||||||
@ -69,6 +84,11 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
|
|||||||
delegate.add_method("ethcore_transactionsLimit", Ethcore::transactions_limit);
|
delegate.add_method("ethcore_transactionsLimit", Ethcore::transactions_limit);
|
||||||
delegate.add_method("ethcore_devLogs", Ethcore::dev_logs);
|
delegate.add_method("ethcore_devLogs", Ethcore::dev_logs);
|
||||||
delegate.add_method("ethcore_devLogsLevels", Ethcore::dev_logs_levels);
|
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_netPort", Ethcore::net_port);
|
||||||
|
delegate.add_method("ethcore_rpcSettings", Ethcore::rpc_settings);
|
||||||
|
delegate.add_method("ethcore_nodeName", Ethcore::node_name);
|
||||||
|
|
||||||
delegate
|
delegate
|
||||||
}
|
}
|
||||||
|
@ -495,6 +495,8 @@ fn populate_big_types() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn raw_bytes_from_tuple() {
|
fn raw_bytes_from_tuple() {
|
||||||
|
type Tup = (Vec<u16>, u16);
|
||||||
|
|
||||||
let tup = (vec![1u16, 1u16, 1u16, 1u16], 10u16);
|
let tup = (vec![1u16, 1u16, 1u16, 1u16], 10u16);
|
||||||
let bytes = vec![
|
let bytes = vec![
|
||||||
// map
|
// map
|
||||||
@ -507,8 +509,6 @@ fn raw_bytes_from_tuple() {
|
|||||||
// 10u16
|
// 10u16
|
||||||
10u8, 0u8];
|
10u8, 0u8];
|
||||||
|
|
||||||
type Tup = (Vec<u16>, u16);
|
|
||||||
|
|
||||||
let tup_from = Tup::from_bytes(&bytes).unwrap();
|
let tup_from = Tup::from_bytes(&bytes).unwrap();
|
||||||
assert_eq!(tup, tup_from);
|
assert_eq!(tup, tup_from);
|
||||||
|
|
||||||
|
@ -147,6 +147,7 @@ pub mod log;
|
|||||||
pub mod panics;
|
pub mod panics;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
|
pub mod network_settings;
|
||||||
|
|
||||||
pub use common::*;
|
pub use common::*;
|
||||||
pub use misc::*;
|
pub use misc::*;
|
||||||
|
35
util/src/network_settings.rs
Normal file
35
util/src/network_settings.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
//! Structure to hold network settings configured from CLI
|
||||||
|
|
||||||
|
/// Networking & RPC settings
|
||||||
|
pub struct NetworkSettings {
|
||||||
|
/// Node name
|
||||||
|
pub name: String,
|
||||||
|
/// Name of the chain we are connected to
|
||||||
|
pub chain: String,
|
||||||
|
/// Ideal number of peers
|
||||||
|
pub max_peers: usize,
|
||||||
|
/// Networking port
|
||||||
|
pub network_port: u16,
|
||||||
|
/// Is JSON-RPC server enabled?
|
||||||
|
pub rpc_enabled: bool,
|
||||||
|
/// Interface that JSON-RPC listens on
|
||||||
|
pub rpc_interface: String,
|
||||||
|
/// Port for JSON-RPC server
|
||||||
|
pub rpc_port: u16,
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ ethcore-rpc = { path = "../rpc" }
|
|||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" }
|
parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" }
|
||||||
# List of apps
|
# List of apps
|
||||||
parity-status = { git = "https://github.com/tomusdrw/parity-status.git", version = "0.1.7" }
|
parity-status = { git = "https://github.com/tomusdrw/parity-status.git", version = "0.2.2" }
|
||||||
parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true }
|
parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true }
|
||||||
clippy = { version = "0.0.63", optional = true}
|
clippy = { version = "0.0.63", optional = true}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user