Merge branch 'master' into util_deps_cleanup

This commit is contained in:
debris 2017-09-05 14:59:42 +02:00
commit 8b5ce1a772
92 changed files with 2464 additions and 2652 deletions

3
Cargo.lock generated
View File

@ -1866,6 +1866,7 @@ version = "1.8.0"
dependencies = [ dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)", "ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)",
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2148,7 +2149,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-ui-precompiled" name = "parity-ui-precompiled"
version = "1.4.0" version = "1.4.0"
source = "git+https://github.com/paritytech/js-precompiled.git#f34bdb63272fd59edf2062dda44113831964d800" source = "git+https://github.com/paritytech/js-precompiled.git#75e4afa0b77396aa8feefb49276672c3fe885a88"
dependencies = [ dependencies = [
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -11,6 +11,7 @@ log = "0.3"
env_logger = "0.4" env_logger = "0.4"
rustc-hex = "1.0" rustc-hex = "1.0"
docopt = "0.8" docopt = "0.8"
clap = "2"
time = "0.1" time = "0.1"
num_cpus = "1.2" num_cpus = "1.2"
number_prefix = "0.2" number_prefix = "0.2"

View File

@ -1,74 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
//! Trait for fetching chain data.
use std::sync::Arc;
use ethcore::encoded;
use ethcore::engines::{Engine, StateDependentProof};
use ethcore::header::Header;
use ethcore::receipt::Receipt;
use futures::future::IntoFuture;
use bigint::hash::H256;
/// Provides full chain data.
pub trait ChainDataFetcher: Send + Sync + 'static {
/// Error type when data unavailable.
type Error: ::std::fmt::Debug;
/// Future for fetching block body.
type Body: IntoFuture<Item=encoded::Block, Error=Self::Error>;
/// Future for fetching block receipts.
type Receipts: IntoFuture<Item=Vec<Receipt>, Error=Self::Error>;
/// Future for fetching epoch transition
type Transition: IntoFuture<Item=Vec<u8>, Error=Self::Error>;
/// Fetch a block body.
fn block_body(&self, header: &Header) -> Self::Body;
/// Fetch block receipts.
fn block_receipts(&self, header: &Header) -> Self::Receipts;
/// Fetch epoch transition proof at given header.
fn epoch_transition(&self, hash: H256, engine: Arc<Engine>, checker: Arc<StateDependentProof>) -> Self::Transition;
}
/// Fetcher implementation which cannot fetch anything.
pub struct Unavailable;
/// Create a fetcher which has all data unavailable.
pub fn unavailable() -> Unavailable { Unavailable }
impl ChainDataFetcher for Unavailable {
type Error = &'static str;
type Body = Result<encoded::Block, &'static str>;
type Receipts = Result<Vec<Receipt>, &'static str>;
type Transition = Result<Vec<u8>, &'static str>;
fn block_body(&self, _header: &Header) -> Self::Body {
Err("fetching block bodies unavailable")
}
fn block_receipts(&self, _header: &Header) -> Self::Receipts {
Err("fetching block receipts unavailable")
}
fn epoch_transition(&self, _h: H256, _e: Arc<Engine>, _check: Arc<StateDependentProof>) -> Self::Transition {
Err("fetching epoch transition proofs unavailable")
}
}

View File

@ -18,12 +18,11 @@
//! //!
//! Unlike a full node's `BlockChain` this doesn't store much in the database. //! Unlike a full node's `BlockChain` this doesn't store much in the database.
//! It stores candidates for the last 2048-4096 blocks as well as CHT roots for //! It stores candidates for the last 2048-4096 blocks as well as CHT roots for
//! historical blocks all the way to the genesis. If the engine makes use //! historical blocks all the way to the genesis.
//! of epoch transitions, those are stored as well.
//! //!
//! This is separate from the `BlockChain` for two reasons: //! This is separate from the `BlockChain` for two reasons:
//! - It stores only headers (and a pruned subset of them) //! - It stores only headers (and a pruned subset of them)
//! - To allow for flexibility in the database layout.. //! - To allow for flexibility in the database layout once that's incorporated.
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::sync::Arc; use std::sync::Arc;
@ -31,20 +30,15 @@ use std::sync::Arc;
use cht; use cht;
use ethcore::block_status::BlockStatus; use ethcore::block_status::BlockStatus;
use ethcore::error::{BlockImportError, BlockError}; use ethcore::error::BlockError;
use ethcore::encoded; use ethcore::encoded;
use ethcore::header::Header; use ethcore::header::Header;
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use ethcore::spec::Spec;
use ethcore::engines::epoch::{
Transition as EpochTransition,
PendingTransition as PendingEpochTransition
};
use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp, UntrustedRlp}; use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp, UntrustedRlp};
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use bigint::prelude::U256; use bigint::prelude::U256;
use bigint::hash::{H256, H256FastMap, H264}; use bigint::hash::H256;
use util::kvdb::{DBTransaction, KeyValueDB}; use util::kvdb::{DBTransaction, KeyValueDB};
use cache::Cache; use cache::Cache;
@ -60,9 +54,6 @@ const HISTORY: u64 = 2048;
/// The best block key. Maps to an RLP list: [best_era, last_era] /// The best block key. Maps to an RLP list: [best_era, last_era]
const CURRENT_KEY: &'static [u8] = &*b"best_and_latest"; const CURRENT_KEY: &'static [u8] = &*b"best_and_latest";
/// Key storing the last canonical epoch transition.
const LAST_CANONICAL_TRANSITION: &'static [u8] = &*b"canonical_transition";
/// Information about a block. /// Information about a block.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BlockDescriptor { pub struct BlockDescriptor {
@ -110,6 +101,7 @@ impl Encodable for Entry {
impl Decodable for Entry { impl Decodable for Entry {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> { fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
let mut candidates = SmallVec::<[Candidate; 3]>::new(); let mut candidates = SmallVec::<[Candidate; 3]>::new();
for item in rlp.iter() { for item in rlp.iter() {
@ -139,42 +131,6 @@ fn era_key(number: u64) -> String {
format!("candidates_{}", number) format!("candidates_{}", number)
} }
fn pending_transition_key(block_hash: H256) -> H264 {
const LEADING: u8 = 1;
let mut key = H264::default();
key[0] = LEADING;
key.0[1..].copy_from_slice(&block_hash.0[..]);
key
}
fn transition_key(block_hash: H256) -> H264 {
const LEADING: u8 = 2;
let mut key = H264::default();
key[0] = LEADING;
key.0[1..].copy_from_slice(&block_hash.0[..]);
key
}
// encode last canonical transition entry: header and proof.
fn encode_canonical_transition(header: &Header, proof: &[u8]) -> Vec<u8> {
let mut stream = RlpStream::new_list(2);
stream.append(header).append(&proof);
stream.out()
}
// decode last canonical transition entry.
fn decode_canonical_transition(t: &[u8]) -> Result<(Header, &[u8]), DecoderError> {
let rlp = UntrustedRlp::new(t);
Ok((rlp.val_at(0)?, rlp.at(1)?.data()?))
}
/// Pending changes from `insert` to be applied after the database write has finished. /// Pending changes from `insert` to be applied after the database write has finished.
pub struct PendingChanges { pub struct PendingChanges {
best_block: Option<BlockDescriptor>, // new best block. best_block: Option<BlockDescriptor>, // new best block.
@ -185,7 +141,6 @@ pub struct HeaderChain {
genesis_header: encoded::Header, // special-case the genesis. genesis_header: encoded::Header, // special-case the genesis.
candidates: RwLock<BTreeMap<u64, Entry>>, candidates: RwLock<BTreeMap<u64, Entry>>,
best_block: RwLock<BlockDescriptor>, best_block: RwLock<BlockDescriptor>,
live_epoch_proofs: RwLock<H256FastMap<EpochTransition>>,
db: Arc<KeyValueDB>, db: Arc<KeyValueDB>,
col: Option<u32>, col: Option<u32>,
cache: Arc<Mutex<Cache>>, cache: Arc<Mutex<Cache>>,
@ -193,16 +148,8 @@ pub struct HeaderChain {
impl HeaderChain { impl HeaderChain {
/// Create a new header chain given this genesis block and database to read from. /// Create a new header chain given this genesis block and database to read from.
pub fn new( pub fn new(db: Arc<KeyValueDB>, col: Option<u32>, genesis: &[u8], cache: Arc<Mutex<Cache>>) -> Result<Self, String> {
db: Arc<KeyValueDB>, use ethcore::views::HeaderView;
col: Option<u32>,
spec: &Spec,
cache: Arc<Mutex<Cache>>,
) -> Result<Self, String> {
let mut live_epoch_proofs = ::std::collections::HashMap::default();
let genesis = ::rlp::encode(&spec.genesis_header()).into_vec();
let decoded_header = spec.genesis_header();
let chain = if let Some(current) = db.get(col, CURRENT_KEY)? { let chain = if let Some(current) = db.get(col, CURRENT_KEY)? {
let (best_number, highest_number) = { let (best_number, highest_number) = {
@ -213,24 +160,12 @@ impl HeaderChain {
let mut cur_number = highest_number; let mut cur_number = highest_number;
let mut candidates = BTreeMap::new(); let mut candidates = BTreeMap::new();
// load all era entries, referenced headers within them, // load all era entries and referenced headers within them.
// and live epoch proofs.
while let Some(entry) = db.get(col, era_key(cur_number).as_bytes())? { while let Some(entry) = db.get(col, era_key(cur_number).as_bytes())? {
let entry: Entry = ::rlp::decode(&entry); let entry: Entry = ::rlp::decode(&entry);
trace!(target: "chain", "loaded header chain entry for era {} with {} candidates", trace!(target: "chain", "loaded header chain entry for era {} with {} candidates",
cur_number, entry.candidates.len()); cur_number, entry.candidates.len());
for c in &entry.candidates {
let key = transition_key(c.hash);
if let Some(proof) = db.get(col, &*key)? {
live_epoch_proofs.insert(c.hash, EpochTransition {
block_hash: c.hash,
block_number: cur_number,
proof: proof.into_vec(),
});
}
}
candidates.insert(cur_number, entry); candidates.insert(cur_number, entry);
cur_number -= 1; cur_number -= 1;
@ -252,42 +187,29 @@ impl HeaderChain {
}; };
HeaderChain { HeaderChain {
genesis_header: encoded::Header::new(genesis), genesis_header: encoded::Header::new(genesis.to_owned()),
best_block: RwLock::new(best_block), best_block: RwLock::new(best_block),
candidates: RwLock::new(candidates), candidates: RwLock::new(candidates),
live_epoch_proofs: RwLock::new(live_epoch_proofs),
db: db, db: db,
col: col, col: col,
cache: cache, cache: cache,
} }
} else { } else {
let g_view = HeaderView::new(genesis);
HeaderChain { HeaderChain {
genesis_header: encoded::Header::new(genesis), genesis_header: encoded::Header::new(genesis.to_owned()),
best_block: RwLock::new(BlockDescriptor { best_block: RwLock::new(BlockDescriptor {
hash: decoded_header.hash(), hash: g_view.hash(),
number: 0, number: 0,
total_difficulty: *decoded_header.difficulty(), total_difficulty: g_view.difficulty(),
}), }),
candidates: RwLock::new(BTreeMap::new()), candidates: RwLock::new(BTreeMap::new()),
live_epoch_proofs: RwLock::new(live_epoch_proofs),
db: db, db: db,
col: col, col: col,
cache: cache, cache: cache,
} }
}; };
// instantiate genesis epoch data if it doesn't exist.
if let None = chain.db.get(col, LAST_CANONICAL_TRANSITION)? {
let genesis_data = spec.genesis_epoch_data()?;
{
let mut batch = chain.db.transaction();
let data = encode_canonical_transition(&decoded_header, &genesis_data);
batch.put_vec(col, LAST_CANONICAL_TRANSITION, data);
chain.db.write(batch)?;
}
}
Ok(chain) Ok(chain)
} }
@ -296,24 +218,10 @@ impl HeaderChain {
/// This blindly trusts that the data given to it is sensible. /// This blindly trusts that the data given to it is sensible.
/// Returns a set of pending changes to be applied with `apply_pending` /// Returns a set of pending changes to be applied with `apply_pending`
/// before the next call to insert and after the transaction has been written. /// before the next call to insert and after the transaction has been written.
/// pub fn insert(&self, transaction: &mut DBTransaction, header: Header) -> Result<PendingChanges, BlockError> {
/// If the block is an epoch transition, provide the transition along with
/// the header.
pub fn insert(
&self,
transaction: &mut DBTransaction,
header: Header,
transition_proof: Option<Vec<u8>>,
) -> Result<PendingChanges, BlockImportError> {
let hash = header.hash(); let hash = header.hash();
let number = header.number(); let number = header.number();
let parent_hash = *header.parent_hash(); let parent_hash = *header.parent_hash();
let transition = transition_proof.map(|proof| EpochTransition {
block_hash: hash,
block_number: number,
proof: proof,
});
let mut pending = PendingChanges { let mut pending = PendingChanges {
best_block: None, best_block: None,
}; };
@ -329,8 +237,7 @@ impl HeaderChain {
candidates.get(&(number - 1)) candidates.get(&(number - 1))
.and_then(|entry| entry.candidates.iter().find(|c| c.hash == parent_hash)) .and_then(|entry| entry.candidates.iter().find(|c| c.hash == parent_hash))
.map(|c| c.total_difficulty) .map(|c| c.total_difficulty)
.ok_or_else(|| BlockError::UnknownParent(parent_hash)) .ok_or_else(|| BlockError::UnknownParent(parent_hash))?
.map_err(BlockImportError::Block)?
}; };
let total_difficulty = parent_td + *header.difficulty(); let total_difficulty = parent_td + *header.difficulty();
@ -355,13 +262,8 @@ impl HeaderChain {
transaction.put(self.col, era_key(number).as_bytes(), &::rlp::encode(&*cur_era)) transaction.put(self.col, era_key(number).as_bytes(), &::rlp::encode(&*cur_era))
} }
if let Some(transition) = transition { let raw = ::rlp::encode(&header);
transaction.put(self.col, &*transition_key(hash), &transition.proof); transaction.put(self.col, &hash[..], &*raw);
self.live_epoch_proofs.write().insert(hash, transition);
}
let raw = header.encoded().into_inner();
transaction.put_vec(self.col, &hash[..], raw);
let (best_num, is_new_best) = { let (best_num, is_new_best) = {
let cur_best = self.best_block.read(); let cur_best = self.best_block.read();
@ -414,10 +316,8 @@ impl HeaderChain {
let cht_num = cht::block_to_cht_number(earliest_era) let cht_num = cht::block_to_cht_number(earliest_era)
.expect("fails only for number == 0; genesis never imported; qed"); .expect("fails only for number == 0; genesis never imported; qed");
let mut last_canonical_transition = None;
let cht_root = { let cht_root = {
let mut i = earliest_era; let mut i = earliest_era;
let mut live_epoch_proofs = self.live_epoch_proofs.write();
// iterable function which removes the candidates as it goes // iterable function which removes the candidates as it goes
// along. this will only be called until the CHT is complete. // along. this will only be called until the CHT is complete.
@ -428,25 +328,7 @@ impl HeaderChain {
i += 1; i += 1;
// prune old blocks and epoch proofs.
for ancient in &era_entry.candidates { for ancient in &era_entry.candidates {
let maybe_transition = live_epoch_proofs.remove(&ancient.hash);
if let Some(epoch_transition) = maybe_transition {
transaction.delete(self.col, &*transition_key(ancient.hash));
if ancient.hash == era_entry.canonical_hash {
last_canonical_transition = match self.db.get(self.col, &ancient.hash) {
Err(e) => {
warn!(target: "chain", "Error reading from DB: {}\n
", e);
None
}
Ok(None) => panic!("stored candidates always have corresponding headers; qed"),
Ok(Some(header)) => Some((epoch_transition, ::rlp::decode(&header))),
};
}
}
transaction.delete(self.col, &ancient.hash); transaction.delete(self.col, &ancient.hash);
} }
@ -460,12 +342,6 @@ impl HeaderChain {
// write the CHT root to the database. // write the CHT root to the database.
debug!(target: "chain", "Produced CHT {} root: {:?}", cht_num, cht_root); debug!(target: "chain", "Produced CHT {} root: {:?}", cht_num, cht_root);
transaction.put(self.col, cht_key(cht_num).as_bytes(), &::rlp::encode(&cht_root)); transaction.put(self.col, cht_key(cht_num).as_bytes(), &::rlp::encode(&cht_root));
// update the last canonical transition proof
if let Some((epoch_transition, header)) = last_canonical_transition {
let x = encode_canonical_transition(&header, &epoch_transition.proof);
transaction.put_vec(self.col, LAST_CANONICAL_TRANSITION, x);
}
} }
} }
@ -491,7 +367,7 @@ impl HeaderChain {
/// will be returned. /// will be returned.
pub fn block_hash(&self, id: BlockId) -> Option<H256> { pub fn block_hash(&self, id: BlockId) -> Option<H256> {
match id { match id {
BlockId::Earliest | BlockId::Number(0) => Some(self.genesis_hash()), BlockId::Earliest => Some(self.genesis_hash()),
BlockId::Hash(hash) => Some(hash), BlockId::Hash(hash) => Some(hash),
BlockId::Number(num) => { BlockId::Number(num) => {
if self.best_block.read().number < num { return None } if self.best_block.read().number < num { return None }
@ -642,56 +518,6 @@ impl HeaderChain {
false => BlockStatus::Unknown, false => BlockStatus::Unknown,
} }
} }
/// Insert a pending transition.
pub fn insert_pending_transition(&self, batch: &mut DBTransaction, hash: H256, t: PendingEpochTransition) {
let key = pending_transition_key(hash);
batch.put(self.col, &*key, &*::rlp::encode(&t));
}
/// Get pending transition for a specific block hash.
pub fn pending_transition(&self, hash: H256) -> Option<PendingEpochTransition> {
let key = pending_transition_key(hash);
match self.db.get(self.col, &*key) {
Ok(val) => val.map(|x| ::rlp::decode(&x)),
Err(e) => {
warn!(target: "chain", "Error reading from database: {}", e);
None
}
}
}
/// Get the transition to the epoch the given parent hash is part of
/// or transitions to.
/// This will give the epoch that any children of this parent belong to.
///
/// The header corresponding the the parent hash must be stored already.
pub fn epoch_transition_for(&self, parent_hash: H256) -> Option<(Header, Vec<u8>)> {
// slow path: loop back block by block
let live_proofs = self.live_epoch_proofs.read();
for hdr in self.ancestry_iter(BlockId::Hash(parent_hash)) {
if let Some(transition) = live_proofs.get(&hdr.hash()).cloned() {
return Some((hdr.decode(), transition.proof))
}
}
// any blocks left must be descendants of the last canonical transition block.
match self.db.get(self.col, LAST_CANONICAL_TRANSITION) {
Ok(x) => {
let x = x.expect("last canonical transition always instantiated; qed");
let (hdr, proof) = decode_canonical_transition(&x)
.expect("last canonical transition always encoded correctly; qed");
Some((hdr, proof.to_vec()))
}
Err(e) => {
warn!("Error reading from DB: {}", e);
None
}
}
}
} }
impl HeapSizeOf for HeaderChain { impl HeapSizeOf for HeaderChain {
@ -744,7 +570,7 @@ mod tests {
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
@ -757,7 +583,7 @@ mod tests {
parent_hash = header.hash(); parent_hash = header.hash();
let mut tx = db.transaction(); let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap(); let pending = chain.insert(&mut tx, header).unwrap();
db.write(tx).unwrap(); db.write(tx).unwrap();
chain.apply_pending(pending); chain.apply_pending(pending);
@ -777,7 +603,7 @@ mod tests {
let db = make_db(); let db = make_db();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
@ -790,7 +616,7 @@ mod tests {
parent_hash = header.hash(); parent_hash = header.hash();
let mut tx = db.transaction(); let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap(); let pending = chain.insert(&mut tx, header).unwrap();
db.write(tx).unwrap(); db.write(tx).unwrap();
chain.apply_pending(pending); chain.apply_pending(pending);
@ -809,7 +635,7 @@ mod tests {
parent_hash = header.hash(); parent_hash = header.hash();
let mut tx = db.transaction(); let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap(); let pending = chain.insert(&mut tx, header).unwrap();
db.write(tx).unwrap(); db.write(tx).unwrap();
chain.apply_pending(pending); chain.apply_pending(pending);
@ -833,7 +659,7 @@ mod tests {
parent_hash = header.hash(); parent_hash = header.hash();
let mut tx = db.transaction(); let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap(); let pending = chain.insert(&mut tx, header).unwrap();
db.write(tx).unwrap(); db.write(tx).unwrap();
chain.apply_pending(pending); chain.apply_pending(pending);
@ -856,10 +682,12 @@ mod tests {
#[test] #[test]
fn earliest_is_latest() { fn earliest_is_latest() {
let spec = Spec::new_test(); let spec = Spec::new_test();
let genesis_header = spec.genesis_header();
let db = make_db(); let db = make_db();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache).unwrap();
assert!(chain.block_header(BlockId::Earliest).is_some()); assert!(chain.block_header(BlockId::Earliest).is_some());
assert!(chain.block_header(BlockId::Latest).is_some()); assert!(chain.block_header(BlockId::Latest).is_some());
@ -874,7 +702,7 @@ mod tests {
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
{ {
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
for i in 1..10000 { for i in 1..10000 {
@ -886,7 +714,7 @@ mod tests {
parent_hash = header.hash(); parent_hash = header.hash();
let mut tx = db.transaction(); let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap(); let pending = chain.insert(&mut tx, header).unwrap();
db.write(tx).unwrap(); db.write(tx).unwrap();
chain.apply_pending(pending); chain.apply_pending(pending);
@ -894,7 +722,7 @@ mod tests {
} }
} }
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
assert!(chain.block_header(BlockId::Number(10)).is_none()); assert!(chain.block_header(BlockId::Number(10)).is_none());
assert!(chain.block_header(BlockId::Number(9000)).is_some()); assert!(chain.block_header(BlockId::Number(9000)).is_some());
assert!(chain.cht_root(2).is_some()); assert!(chain.cht_root(2).is_some());
@ -910,7 +738,7 @@ mod tests {
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
{ {
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
let mut parent_hash = genesis_header.hash(); let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp(); let mut rolling_timestamp = genesis_header.timestamp();
@ -924,7 +752,7 @@ mod tests {
parent_hash = header.hash(); parent_hash = header.hash();
let mut tx = db.transaction(); let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap(); let pending = chain.insert(&mut tx, header).unwrap();
db.write(tx).unwrap(); db.write(tx).unwrap();
chain.apply_pending(pending); chain.apply_pending(pending);
@ -941,7 +769,7 @@ mod tests {
parent_hash = header.hash(); parent_hash = header.hash();
let mut tx = db.transaction(); let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap(); let pending = chain.insert(&mut tx, header).unwrap();
db.write(tx).unwrap(); db.write(tx).unwrap();
chain.apply_pending(pending); chain.apply_pending(pending);
@ -952,7 +780,7 @@ mod tests {
} }
// after restoration, non-canonical eras should still be loaded. // after restoration, non-canonical eras should still be loaded.
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
assert_eq!(chain.block_header(BlockId::Latest).unwrap().number(), 10); assert_eq!(chain.block_header(BlockId::Latest).unwrap().number(), 10);
assert!(chain.candidates.read().get(&100).is_some()) assert!(chain.candidates.read().get(&100).is_some())
} }
@ -964,76 +792,10 @@ mod tests {
let db = make_db(); let db = make_db();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &spec, cache.clone()).unwrap(); let chain = HeaderChain::new(db.clone(), None, &::rlp::encode(&genesis_header), cache.clone()).unwrap();
assert!(chain.block_header(BlockId::Earliest).is_some()); assert!(chain.block_header(BlockId::Earliest).is_some());
assert!(chain.block_header(BlockId::Number(0)).is_some()); assert!(chain.block_header(BlockId::Number(0)).is_some());
assert!(chain.block_header(BlockId::Hash(genesis_header.hash())).is_some()); assert!(chain.block_header(BlockId::Hash(genesis_header.hash())).is_some());
} }
#[test]
fn epoch_transitions_available_after_cht() {
let spec = Spec::new_test();
let genesis_header = spec.genesis_header();
let db = make_db();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let chain = HeaderChain::new(db.clone(), None, &spec, cache).unwrap();
let mut parent_hash = genesis_header.hash();
let mut rolling_timestamp = genesis_header.timestamp();
for i in 1..6 {
let mut header = Header::new();
header.set_parent_hash(parent_hash);
header.set_number(i);
header.set_timestamp(rolling_timestamp);
header.set_difficulty(*genesis_header.difficulty() * i.into());
parent_hash = header.hash();
let mut tx = db.transaction();
let epoch_proof = if i == 3 {
Some(vec![1, 2, 3, 4])
} else {
None
};
let pending = chain.insert(&mut tx, header, epoch_proof).unwrap();
db.write(tx).unwrap();
chain.apply_pending(pending);
rolling_timestamp += 10;
}
// these 3 should end up falling back to the genesis epoch proof in DB
for i in 0..3 {
let hash = chain.block_hash(BlockId::Number(i)).unwrap();
assert_eq!(chain.epoch_transition_for(hash).unwrap().1, Vec::<u8>::new());
}
// these are live.
for i in 3..6 {
let hash = chain.block_hash(BlockId::Number(i)).unwrap();
assert_eq!(chain.epoch_transition_for(hash).unwrap().1, vec![1, 2, 3, 4]);
}
for i in 6..10000 {
let mut header = Header::new();
header.set_parent_hash(parent_hash);
header.set_number(i);
header.set_timestamp(rolling_timestamp);
header.set_difficulty(*genesis_header.difficulty() * i.into());
parent_hash = header.hash();
let mut tx = db.transaction();
let pending = chain.insert(&mut tx, header, None).unwrap();
db.write(tx).unwrap();
chain.apply_pending(pending);
rolling_timestamp += 10;
}
// no live blocks have associated epoch proofs -- make sure we aren't leaking memory.
assert!(chain.live_epoch_proofs.read().is_empty());
assert_eq!(chain.epoch_transition_for(parent_hash).unwrap().1, vec![1, 2, 3, 4]);
}
} }

View File

@ -19,11 +19,11 @@
use std::sync::{Weak, Arc}; use std::sync::{Weak, Arc};
use ethcore::block_status::BlockStatus; use ethcore::block_status::BlockStatus;
use ethcore::client::{TransactionImportResult, ClientReport, EnvInfo}; use ethcore::client::{ClientReport, EnvInfo};
use ethcore::engines::{epoch, Engine, EpochChange, EpochTransition, Proof, Unsure}; use ethcore::engines::Engine;
use ethcore::error::{TransactionError, BlockImportError, Error as EthcoreError}; use ethcore::error::BlockImportError;
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use ethcore::header::{BlockNumber, Header}; use ethcore::header::Header;
use ethcore::verification::queue::{self, HeaderQueue}; use ethcore::verification::queue::{self, HeaderQueue};
use ethcore::blockchain_info::BlockChainInfo; use ethcore::blockchain_info::BlockChainInfo;
use ethcore::spec::Spec; use ethcore::spec::Spec;
@ -33,12 +33,9 @@ use io::IoChannel;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use bigint::prelude::U256; use bigint::prelude::U256;
use bigint::hash::H256; use bigint::hash::H256;
use futures::{IntoFuture, Future};
use util::Address;
use util::kvdb::{KeyValueDB, CompactionProfile}; use util::kvdb::{KeyValueDB, CompactionProfile};
use self::fetch::ChainDataFetcher;
use self::header_chain::{AncestryIter, HeaderChain}; use self::header_chain::{AncestryIter, HeaderChain};
use cache::Cache; use cache::Cache;
@ -48,8 +45,6 @@ pub use self::service::Service;
mod header_chain; mod header_chain;
mod service; mod service;
pub mod fetch;
/// Configuration for the light client. /// Configuration for the light client.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
@ -85,9 +80,6 @@ impl Default for Config {
/// Trait for interacting with the header chain abstractly. /// Trait for interacting with the header chain abstractly.
pub trait LightChainClient: Send + Sync { pub trait LightChainClient: Send + Sync {
/// Adds a new `LightChainNotify` listener.
fn add_listener(&self, listener: Weak<LightChainNotify>);
/// Get chain info. /// Get chain info.
fn chain_info(&self) -> BlockChainInfo; fn chain_info(&self) -> BlockChainInfo;
@ -136,7 +128,7 @@ pub trait LightChainClient: Send + Sync {
fn cht_root(&self, i: usize) -> Option<H256>; fn cht_root(&self, i: usize) -> Option<H256>;
/// Get the EIP-86 transition block number. /// Get the EIP-86 transition block number.
fn eip86_transition(&self) -> BlockNumber; fn eip86_transition(&self) -> u64;
/// Get a report of import activity since the last call. /// Get a report of import activity since the last call.
fn report(&self) -> ClientReport; fn report(&self) -> ClientReport;
@ -164,7 +156,7 @@ impl<T: LightChainClient> AsLightClient for T {
} }
/// Light client implementation. /// Light client implementation.
pub struct Client<T> { pub struct Client {
queue: HeaderQueue, queue: HeaderQueue,
engine: Arc<Engine>, engine: Arc<Engine>,
chain: HeaderChain, chain: HeaderChain,
@ -172,30 +164,22 @@ pub struct Client<T> {
import_lock: Mutex<()>, import_lock: Mutex<()>,
db: Arc<KeyValueDB>, db: Arc<KeyValueDB>,
listeners: RwLock<Vec<Weak<LightChainNotify>>>, listeners: RwLock<Vec<Weak<LightChainNotify>>>,
fetcher: T,
verify_full: bool, verify_full: bool,
} }
impl<T: ChainDataFetcher> Client<T> { impl Client {
/// Create a new `Client`. /// Create a new `Client`.
pub fn new( pub fn new(config: Config, db: Arc<KeyValueDB>, chain_col: Option<u32>, spec: &Spec, io_channel: IoChannel<ClientIoMessage>, cache: Arc<Mutex<Cache>>) -> Result<Self, String> {
config: Config, let gh = ::rlp::encode(&spec.genesis_header());
db: Arc<KeyValueDB>,
chain_col: Option<u32>,
spec: &Spec,
fetcher: T,
io_channel: IoChannel<ClientIoMessage>,
cache: Arc<Mutex<Cache>>
) -> Result<Self, String> {
Ok(Client { Ok(Client {
queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, config.check_seal), queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, config.check_seal),
engine: spec.engine.clone(), engine: spec.engine.clone(),
chain: HeaderChain::new(db.clone(), chain_col, &spec, cache)?, chain: HeaderChain::new(db.clone(), chain_col, &gh, cache)?,
report: RwLock::new(ClientReport::default()), report: RwLock::new(ClientReport::default()),
import_lock: Mutex::new(()), import_lock: Mutex::new(()),
db: db, db: db,
listeners: RwLock::new(vec![]), listeners: RwLock::new(vec![]),
fetcher: fetcher,
verify_full: config.verify_full, verify_full: config.verify_full,
}) })
} }
@ -207,24 +191,10 @@ impl<T: ChainDataFetcher> Client<T> {
/// Create a new `Client` backed purely in-memory. /// Create a new `Client` backed purely in-memory.
/// This will ignore all database options in the configuration. /// This will ignore all database options in the configuration.
pub fn in_memory( pub fn in_memory(config: Config, spec: &Spec, io_channel: IoChannel<ClientIoMessage>, cache: Arc<Mutex<Cache>>) -> Self {
config: Config,
spec: &Spec,
fetcher: T,
io_channel: IoChannel<ClientIoMessage>,
cache: Arc<Mutex<Cache>>
) -> Self {
let db = ::util::kvdb::in_memory(0); let db = ::util::kvdb::in_memory(0);
Client::new( Client::new(config, Arc::new(db), None, spec, io_channel, cache).expect("New DB creation infallible; qed")
config,
Arc::new(db),
None,
spec,
fetcher,
io_channel,
cache
).expect("New DB creation infallible; qed")
} }
/// Import a header to the queue for additional verification. /// Import a header to the queue for additional verification.
@ -323,33 +293,19 @@ impl<T: ChainDataFetcher> Client<T> {
continue continue
} }
let write_proof_result = match self.check_epoch_signal(&verified_header) { // TODO: `epoch_end_signal`, `is_epoch_end`.
Ok(Some(proof)) => self.write_pending_proof(&verified_header, proof), // proofs we get from the network would be _complete_, whereas we need
Ok(None) => Ok(()), // _incomplete_ signals
Err(e) =>
panic!("Unable to fetch epoch transition proof: {:?}", e),
};
if let Err(e) = write_proof_result {
warn!(target: "client", "Error writing pending transition proof to DB: {:?} \
The node may not be able to synchronize further.", e);
}
let epoch_proof = self.engine.is_epoch_end(
&verified_header,
&|h| self.chain.block_header(BlockId::Hash(h)).map(|hdr| hdr.decode()),
&|h| self.chain.pending_transition(h),
);
let mut tx = self.db.transaction(); let mut tx = self.db.transaction();
let pending = match self.chain.insert(&mut tx, verified_header, epoch_proof) { let pending = match self.chain.insert(&mut tx, verified_header) {
Ok(pending) => { Ok(pending) => {
good.push(hash); good.push(hash);
self.report.write().blocks_imported += 1; self.report.write().blocks_imported += 1;
pending pending
} }
Err(e) => { Err(e) => {
debug!(target: "client", "Error importing header {:?}: {:?}", (num, hash), e); debug!(target: "client", "Error importing header {:?}: {}", (num, hash), e);
bad.push(hash); bad.push(hash);
continue; continue;
} }
@ -465,76 +421,9 @@ impl<T: ChainDataFetcher> Client<T> {
true true
} }
fn check_epoch_signal(&self, verified_header: &Header) -> Result<Option<Proof>, T::Error> {
let (mut block, mut receipts) = (None, None);
// First, check without providing auxiliary data.
match self.engine.signals_epoch_end(verified_header, None, None) {
EpochChange::No => return Ok(None),
EpochChange::Yes(proof) => return Ok(Some(proof)),
EpochChange::Unsure(unsure) => {
let (b, r) = match unsure {
Unsure::NeedsBody =>
(Some(self.fetcher.block_body(verified_header)), None),
Unsure::NeedsReceipts =>
(None, Some(self.fetcher.block_receipts(verified_header))),
Unsure::NeedsBoth => (
Some(self.fetcher.block_body(verified_header)),
Some(self.fetcher.block_receipts(verified_header)),
),
};
if let Some(b) = b {
block = Some(b.into_future().wait()?.into_inner());
}
if let Some(r) = r {
receipts = Some(r.into_future().wait()?);
}
}
}
let block = block.as_ref().map(|x| &x[..]);
let receipts = receipts.as_ref().map(|x| &x[..]);
// Check again now that required data has been fetched.
match self.engine.signals_epoch_end(verified_header, block, receipts) {
EpochChange::No => return Ok(None),
EpochChange::Yes(proof) => return Ok(Some(proof)),
EpochChange::Unsure(_) =>
panic!("Detected faulty engine implementation: requests additional \
data to check epoch end signal when everything necessary provided"),
}
}
// attempts to fetch the epoch proof from the network until successful.
fn write_pending_proof(&self, header: &Header, proof: Proof) -> Result<(), T::Error> {
let proof = match proof {
Proof::Known(known) => known,
Proof::WithState(state_dependent) => {
self.fetcher.epoch_transition(
header.hash(),
self.engine.clone(),
state_dependent
).into_future().wait()?
}
};
let mut batch = self.db.transaction();
self.chain.insert_pending_transition(&mut batch, header.hash(), epoch::PendingTransition {
proof: proof,
});
self.db.write_buffered(batch);
Ok(())
}
} }
impl<T: ChainDataFetcher> LightChainClient for Client<T> { impl LightChainClient for Client {
fn add_listener(&self, listener: Weak<LightChainNotify>) {
Client::add_listener(self, listener)
}
fn chain_info(&self) -> BlockChainInfo { Client::chain_info(self) } fn chain_info(&self) -> BlockChainInfo { Client::chain_info(self) }
fn queue_header(&self, header: Header) -> Result<H256, BlockImportError> { fn queue_header(&self, header: Header) -> Result<H256, BlockImportError> {
@ -593,7 +482,7 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
Client::cht_root(self, i) Client::cht_root(self, i)
} }
fn eip86_transition(&self) -> BlockNumber { fn eip86_transition(&self) -> u64 {
self.engine().params().eip86_transition self.engine().params().eip86_transition
} }
@ -601,38 +490,3 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
Client::report(self) Client::report(self)
} }
} }
impl<T: ChainDataFetcher> ::ethcore::client::EngineClient for Client<T> {
fn update_sealing(&self) { }
fn submit_seal(&self, _block_hash: H256, _seal: Vec<Vec<u8>>) { }
fn broadcast_consensus_message(&self, _message: Vec<u8>) { }
fn epoch_transition_for(&self, parent_hash: H256) -> Option<EpochTransition> {
self.chain.epoch_transition_for(parent_hash).map(|(hdr, proof)| EpochTransition {
block_hash: hdr.hash(),
block_number: hdr.number(),
proof: proof,
})
}
fn chain_info(&self) -> BlockChainInfo {
Client::chain_info(self)
}
fn call_contract(&self, _id: BlockId, _address: Address, _data: Vec<u8>) -> Result<Vec<u8>, String> {
Err("Contract calling not supported by light client".into())
}
fn transact_contract(&self, _address: Address, _data: Vec<u8>)
-> Result<TransactionImportResult, EthcoreError>
{
// TODO: these are only really used for misbehavior reporting.
// no relevant clients will be running light clients, but maybe
// they could be at some point?
Err(TransactionError::LimitReached.into())
}
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
self.block_header(id).map(|hdr| hdr.number())
}
}

View File

@ -30,7 +30,7 @@ use util::kvdb::{Database, DatabaseConfig};
use cache::Cache; use cache::Cache;
use parking_lot::Mutex; use parking_lot::Mutex;
use super::{ChainDataFetcher, Client, Config as ClientConfig}; use super::{Client, Config as ClientConfig};
/// Errors on service initialization. /// Errors on service initialization.
#[derive(Debug)] #[derive(Debug)]
@ -51,14 +51,14 @@ impl fmt::Display for Error {
} }
/// Light client service. /// Light client service.
pub struct Service<T> { pub struct Service {
client: Arc<Client<T>>, client: Arc<Client>,
io_service: IoService<ClientIoMessage>, io_service: IoService<ClientIoMessage>,
} }
impl<T: ChainDataFetcher> Service<T> { impl Service {
/// Start the service: initialize I/O workers and client itself. /// Start the service: initialize I/O workers and client itself.
pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, path: &Path, cache: Arc<Mutex<Cache>>) -> Result<Self, Error> { pub fn start(config: ClientConfig, spec: &Spec, path: &Path, cache: Arc<Mutex<Cache>>) -> Result<Self, Error> {
// initialize database. // initialize database.
let mut db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS); let mut db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS);
@ -81,14 +81,10 @@ impl<T: ChainDataFetcher> Service<T> {
db, db,
db::COL_LIGHT_CHAIN, db::COL_LIGHT_CHAIN,
spec, spec,
fetcher,
io_service.channel(), io_service.channel(),
cache, cache,
).map_err(Error::Database)?); ).map_err(Error::Database)?);
io_service.register_handler(Arc::new(ImportBlocks(client.clone()))).map_err(Error::Io)?; io_service.register_handler(Arc::new(ImportBlocks(client.clone()))).map_err(Error::Io)?;
spec.engine.register_client(Arc::downgrade(&client) as _);
Ok(Service { Ok(Service {
client: client, client: client,
io_service: io_service, io_service: io_service,
@ -101,14 +97,14 @@ impl<T: ChainDataFetcher> Service<T> {
} }
/// Get a handle to the client. /// Get a handle to the client.
pub fn client(&self) -> &Arc<Client<T>> { pub fn client(&self) -> &Arc<Client> {
&self.client &self.client
} }
} }
struct ImportBlocks<T>(Arc<Client<T>>); struct ImportBlocks(Arc<Client>);
impl<T: ChainDataFetcher> IoHandler<ClientIoMessage> for ImportBlocks<T> { impl IoHandler<ClientIoMessage> for ImportBlocks {
fn message(&self, _io: &IoContext<ClientIoMessage>, message: &ClientIoMessage) { fn message(&self, _io: &IoContext<ClientIoMessage>, message: &ClientIoMessage) {
if let ClientIoMessage::BlockVerified = *message { if let ClientIoMessage::BlockVerified = *message {
self.0.import_verified(); self.0.import_verified();
@ -124,7 +120,6 @@ mod tests {
use std::sync::Arc; use std::sync::Arc;
use cache::Cache; use cache::Cache;
use client::fetch;
use time::Duration; use time::Duration;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -134,6 +129,6 @@ mod tests {
let temp_path = RandomTempPath::new(); let temp_path = RandomTempPath::new();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
Service::start(Default::default(), &spec, fetch::unavailable(), temp_path.as_path(), cache).unwrap(); Service::start(Default::default(), &spec, temp_path.as_path(), cache).unwrap();
} }
} }

View File

@ -62,7 +62,6 @@ fn hardcoded_serve_time(kind: Kind) -> u64 {
Kind::Storage => 2_000_000, Kind::Storage => 2_000_000,
Kind::Code => 1_500_000, Kind::Code => 1_500_000,
Kind::Execution => 250, // per gas. Kind::Execution => 250, // per gas.
Kind::Signal => 500_000,
} }
} }

View File

@ -104,8 +104,9 @@ mod packet {
// relay transactions to peers. // relay transactions to peers.
pub const SEND_TRANSACTIONS: u8 = 0x06; pub const SEND_TRANSACTIONS: u8 = 0x06;
// two packets were previously meant to be reserved for epoch proofs. // request and respond with epoch transition proof
// these have since been moved to requests. pub const REQUEST_EPOCH_PROOF: u8 = 0x07;
pub const EPOCH_PROOF: u8 = 0x08;
} }
// timeouts for different kinds of requests. all values are in milliseconds. // timeouts for different kinds of requests. all values are in milliseconds.
@ -123,7 +124,6 @@ mod timeout {
pub const CONTRACT_CODE: i64 = 100; pub const CONTRACT_CODE: i64 = 100;
pub const HEADER_PROOF: i64 = 100; pub const HEADER_PROOF: i64 = 100;
pub const TRANSACTION_PROOF: i64 = 1000; // per gas? pub const TRANSACTION_PROOF: i64 = 1000; // per gas?
pub const EPOCH_SIGNAL: i64 = 200;
} }
/// A request id. /// A request id.
@ -584,6 +584,12 @@ impl LightProtocol {
packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp), packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
packet::REQUEST_EPOCH_PROOF | packet::EPOCH_PROOF => {
// ignore these for now, but leave them specified.
debug!(target: "pip", "Ignoring request/response for epoch proof");
Ok(())
}
other => { other => {
Err(Error::UnrecognizedPacket(other)) Err(Error::UnrecognizedPacket(other))
} }
@ -946,7 +952,6 @@ impl LightProtocol {
CompleteRequest::Storage(req) => self.provider.storage_proof(req).map(Response::Storage), CompleteRequest::Storage(req) => self.provider.storage_proof(req).map(Response::Storage),
CompleteRequest::Code(req) => self.provider.contract_code(req).map(Response::Code), CompleteRequest::Code(req) => self.provider.contract_code(req).map(Response::Code),
CompleteRequest::Execution(req) => self.provider.transaction_proof(req).map(Response::Execution), CompleteRequest::Execution(req) => self.provider.transaction_proof(req).map(Response::Execution),
CompleteRequest::Signal(req) => self.provider.epoch_signal(req).map(Response::Signal),
} }
}); });

View File

@ -91,7 +91,6 @@ pub struct CostTable {
code: U256, code: U256,
header_proof: U256, header_proof: U256,
transaction_proof: U256, // cost per gas. transaction_proof: U256, // cost per gas.
epoch_signal: U256,
} }
impl Default for CostTable { impl Default for CostTable {
@ -108,7 +107,6 @@ impl Default for CostTable {
code: 20000.into(), code: 20000.into(),
header_proof: 15000.into(), header_proof: 15000.into(),
transaction_proof: 2.into(), transaction_proof: 2.into(),
epoch_signal: 10000.into(),
} }
} }
} }
@ -123,7 +121,7 @@ impl Encodable for CostTable {
s.append(cost); s.append(cost);
} }
s.begin_list(11).append(&self.base); s.begin_list(10).append(&self.base);
append_cost(s, &self.headers, request::Kind::Headers); append_cost(s, &self.headers, request::Kind::Headers);
append_cost(s, &self.transaction_index, request::Kind::TransactionIndex); append_cost(s, &self.transaction_index, request::Kind::TransactionIndex);
append_cost(s, &self.body, request::Kind::Body); append_cost(s, &self.body, request::Kind::Body);
@ -133,7 +131,6 @@ impl Encodable for CostTable {
append_cost(s, &self.code, request::Kind::Code); append_cost(s, &self.code, request::Kind::Code);
append_cost(s, &self.header_proof, request::Kind::HeaderProof); append_cost(s, &self.header_proof, request::Kind::HeaderProof);
append_cost(s, &self.transaction_proof, request::Kind::Execution); append_cost(s, &self.transaction_proof, request::Kind::Execution);
append_cost(s, &self.epoch_signal, request::Kind::Signal);
} }
} }
@ -150,7 +147,6 @@ impl Decodable for CostTable {
let mut code = None; let mut code = None;
let mut header_proof = None; let mut header_proof = None;
let mut transaction_proof = None; let mut transaction_proof = None;
let mut epoch_signal = None;
for cost_list in rlp.iter().skip(1) { for cost_list in rlp.iter().skip(1) {
let cost = cost_list.val_at(1)?; let cost = cost_list.val_at(1)?;
@ -164,7 +160,6 @@ impl Decodable for CostTable {
request::Kind::Code => code = Some(cost), request::Kind::Code => code = Some(cost),
request::Kind::HeaderProof => header_proof = Some(cost), request::Kind::HeaderProof => header_proof = Some(cost),
request::Kind::Execution => transaction_proof = Some(cost), request::Kind::Execution => transaction_proof = Some(cost),
request::Kind::Signal => epoch_signal = Some(cost),
} }
} }
@ -181,7 +176,6 @@ impl Decodable for CostTable {
code: unwrap_cost(code)?, code: unwrap_cost(code)?,
header_proof: unwrap_cost(header_proof)?, header_proof: unwrap_cost(header_proof)?,
transaction_proof: unwrap_cost(transaction_proof)?, transaction_proof: unwrap_cost(transaction_proof)?,
epoch_signal: unwrap_cost(epoch_signal)?,
}) })
} }
} }
@ -244,7 +238,6 @@ impl FlowParams {
code: cost_for_kind(Kind::Code), code: cost_for_kind(Kind::Code),
header_proof: cost_for_kind(Kind::HeaderProof), header_proof: cost_for_kind(Kind::HeaderProof),
transaction_proof: cost_for_kind(Kind::Execution), transaction_proof: cost_for_kind(Kind::Execution),
epoch_signal: cost_for_kind(Kind::Signal),
}; };
FlowParams { FlowParams {
@ -270,8 +263,7 @@ impl FlowParams {
storage: free_cost.clone(), storage: free_cost.clone(),
code: free_cost.clone(), code: free_cost.clone(),
header_proof: free_cost.clone(), header_proof: free_cost.clone(),
transaction_proof: free_cost.clone(), transaction_proof: free_cost,
epoch_signal: free_cost,
} }
} }
} }
@ -301,7 +293,6 @@ impl FlowParams {
Request::Storage(_) => self.costs.storage, Request::Storage(_) => self.costs.storage,
Request::Code(_) => self.costs.code, Request::Code(_) => self.costs.code,
Request::Execution(ref req) => self.costs.transaction_proof * req.gas, Request::Execution(ref req) => self.costs.transaction_proof * req.gas,
Request::Signal(_) => self.costs.epoch_signal,
} }
} }

View File

@ -139,7 +139,6 @@ fn compute_timeout(reqs: &Requests) -> Duration {
Request::Storage(_) => timeout::PROOF, Request::Storage(_) => timeout::PROOF,
Request::Code(_) => timeout::CONTRACT_CODE, Request::Code(_) => timeout::CONTRACT_CODE,
Request::Execution(_) => timeout::TRANSACTION_PROOF, Request::Execution(_) => timeout::TRANSACTION_PROOF,
Request::Signal(_) => timeout::EPOCH_SIGNAL,
} }
})) }))
} }

View File

@ -158,12 +158,6 @@ impl Provider for TestProvider {
None None
} }
fn epoch_signal(&self, _req: request::CompleteSignalRequest) -> Option<request::SignalResponse> {
Some(request::SignalResponse {
signal: vec![1, 2, 3, 4],
})
}
fn ready_transactions(&self) -> Vec<PendingTransaction> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
self.0.client.ready_transactions() self.0.client.ready_transactions()
} }
@ -529,50 +523,6 @@ fn get_contract_code() {
proto.handle_packet(&expected, &1, packet::REQUEST, &request_body); proto.handle_packet(&expected, &1, packet::REQUEST, &request_body);
} }
#[test]
fn epoch_signal() {
let capabilities = capabilities();
let (provider, proto) = setup(capabilities.clone());
let flow_params = proto.flow_params.read().clone();
let cur_status = status(provider.client.chain_info());
{
let packet_body = write_handshake(&cur_status, &capabilities, &proto);
proto.on_connect(&1, &Expect::Send(1, packet::STATUS, packet_body.clone()));
proto.handle_packet(&Expect::Nothing, &1, packet::STATUS, &packet_body);
}
let req_id = 112;
let request = Request::Signal(request::IncompleteSignalRequest {
block_hash: H256([1; 32]).into(),
});
let requests = encode_single(request.clone());
let request_body = make_packet(req_id, &requests);
let response = {
let response = vec![Response::Signal(SignalResponse {
signal: vec![1, 2, 3, 4],
})];
let limit = *flow_params.limit();
let cost = flow_params.compute_cost_multi(requests.requests());
println!("limit = {}, cost = {}", limit, cost);
let new_creds = limit - cost;
let mut response_stream = RlpStream::new_list(3);
response_stream.append(&req_id).append(&new_creds).append_list(&response);
response_stream.out()
};
let expected = Expect::Respond(packet::RESPONSE, response);
proto.handle_packet(&expected, &1, packet::REQUEST, &request_body);
}
#[test] #[test]
fn proof_of_execution() { fn proof_of_execution() {
let capabilities = capabilities(); let capabilities = capabilities();

View File

@ -195,8 +195,6 @@ fn guess_capabilities(requests: &[CheckedRequest]) -> Capabilities {
caps.serve_headers = true, caps.serve_headers = true,
CheckedRequest::HeaderByHash(_, _) => CheckedRequest::HeaderByHash(_, _) =>
caps.serve_headers = true, caps.serve_headers = true,
CheckedRequest::Signal(_, _) =>
caps.serve_headers = true,
CheckedRequest::Body(ref req, _) => if let Ok(ref hdr) = req.0.as_ref() { CheckedRequest::Body(ref req, _) => if let Ok(ref hdr) = req.0.as_ref() {
update_since(&mut caps.serve_chain_since, hdr.number()); update_since(&mut caps.serve_chain_since, hdr.number());
}, },

View File

@ -20,7 +20,7 @@ use std::sync::Arc;
use ethcore::basic_account::BasicAccount; use ethcore::basic_account::BasicAccount;
use ethcore::encoded; use ethcore::encoded;
use ethcore::engines::{Engine, StateDependentProof}; use ethcore::engines::Engine;
use ethcore::receipt::Receipt; use ethcore::receipt::Receipt;
use ethcore::state::{self, ProvedExecution}; use ethcore::state::{self, ProvedExecution};
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
@ -56,8 +56,6 @@ pub enum Request {
Code(Code), Code(Code),
/// A request for proof of execution. /// A request for proof of execution.
Execution(TransactionProof), Execution(TransactionProof),
/// A request for epoch change signal.
Signal(Signal),
} }
/// A request argument. /// A request argument.
@ -138,7 +136,6 @@ impl_single!(Body, Body, encoded::Block);
impl_single!(Account, Account, Option<BasicAccount>); impl_single!(Account, Account, Option<BasicAccount>);
impl_single!(Code, Code, Bytes); impl_single!(Code, Code, Bytes);
impl_single!(Execution, TransactionProof, super::ExecutionResult); impl_single!(Execution, TransactionProof, super::ExecutionResult);
impl_single!(Signal, Signal, Vec<u8>);
macro_rules! impl_args { macro_rules! impl_args {
() => { () => {
@ -247,7 +244,6 @@ pub enum CheckedRequest {
Account(Account, net_request::IncompleteAccountRequest), Account(Account, net_request::IncompleteAccountRequest),
Code(Code, net_request::IncompleteCodeRequest), Code(Code, net_request::IncompleteCodeRequest),
Execution(TransactionProof, net_request::IncompleteExecutionRequest), Execution(TransactionProof, net_request::IncompleteExecutionRequest),
Signal(Signal, net_request::IncompleteSignalRequest)
} }
impl From<Request> for CheckedRequest { impl From<Request> for CheckedRequest {
@ -306,12 +302,6 @@ impl From<Request> for CheckedRequest {
}; };
CheckedRequest::Execution(req, net_req) CheckedRequest::Execution(req, net_req)
} }
Request::Signal(req) => {
let net_req = net_request::IncompleteSignalRequest {
block_hash: req.hash.into(),
};
CheckedRequest::Signal(req, net_req)
}
} }
} }
} }
@ -329,7 +319,6 @@ impl CheckedRequest {
CheckedRequest::Account(_, req) => NetRequest::Account(req), CheckedRequest::Account(_, req) => NetRequest::Account(req),
CheckedRequest::Code(_, req) => NetRequest::Code(req), CheckedRequest::Code(_, req) => NetRequest::Code(req),
CheckedRequest::Execution(_, req) => NetRequest::Execution(req), CheckedRequest::Execution(_, req) => NetRequest::Execution(req),
CheckedRequest::Signal(_, req) => NetRequest::Signal(req),
} }
} }
@ -457,7 +446,6 @@ macro_rules! match_me {
CheckedRequest::Account($check, $req) => $e, CheckedRequest::Account($check, $req) => $e,
CheckedRequest::Code($check, $req) => $e, CheckedRequest::Code($check, $req) => $e,
CheckedRequest::Execution($check, $req) => $e, CheckedRequest::Execution($check, $req) => $e,
CheckedRequest::Signal($check, $req) => $e,
} }
} }
} }
@ -485,7 +473,6 @@ impl IncompleteRequest for CheckedRequest {
CheckedRequest::Account(_, ref req) => req.check_outputs(f), CheckedRequest::Account(_, ref req) => req.check_outputs(f),
CheckedRequest::Code(_, ref req) => req.check_outputs(f), CheckedRequest::Code(_, ref req) => req.check_outputs(f),
CheckedRequest::Execution(_, ref req) => req.check_outputs(f), CheckedRequest::Execution(_, ref req) => req.check_outputs(f),
CheckedRequest::Signal(_, ref req) => req.check_outputs(f),
} }
} }
@ -506,7 +493,6 @@ impl IncompleteRequest for CheckedRequest {
CheckedRequest::Account(_, req) => req.complete().map(CompleteRequest::Account), CheckedRequest::Account(_, req) => req.complete().map(CompleteRequest::Account),
CheckedRequest::Code(_, req) => req.complete().map(CompleteRequest::Code), CheckedRequest::Code(_, req) => req.complete().map(CompleteRequest::Code),
CheckedRequest::Execution(_, req) => req.complete().map(CompleteRequest::Execution), CheckedRequest::Execution(_, req) => req.complete().map(CompleteRequest::Execution),
CheckedRequest::Signal(_, req) => req.complete().map(CompleteRequest::Signal),
} }
} }
@ -558,9 +544,6 @@ impl net_request::CheckedRequest for CheckedRequest {
CheckedRequest::Execution(ref prover, _) => CheckedRequest::Execution(ref prover, _) =>
expect!((&NetResponse::Execution(ref res), _) => expect!((&NetResponse::Execution(ref res), _) =>
prover.check_response(cache, &res.items).map(Response::Execution)), prover.check_response(cache, &res.items).map(Response::Execution)),
CheckedRequest::Signal(ref prover, _) =>
expect!((&NetResponse::Signal(ref res), _) =>
prover.check_response(cache, &res.signal).map(Response::Signal)),
} }
} }
} }
@ -584,8 +567,6 @@ pub enum Response {
Code(Vec<u8>), Code(Vec<u8>),
/// Response to a request for proved execution. /// Response to a request for proved execution.
Execution(super::ExecutionResult), Execution(super::ExecutionResult),
/// Response to a request for epoch change signal.
Signal(Vec<u8>),
} }
impl net_request::ResponseLike for Response { impl net_request::ResponseLike for Response {
@ -869,27 +850,6 @@ impl TransactionProof {
} }
} }
/// Request for epoch signal.
/// Provide engine and state-dependent proof checker.
#[derive(Clone)]
pub struct Signal {
/// Block hash and number to fetch proof for.
pub hash: H256,
/// Consensus engine, used to check the proof.
pub engine: Arc<Engine>,
/// Special checker for the proof.
pub proof_check: Arc<StateDependentProof>,
}
impl Signal {
/// Check the signal, returning the signal or indicate that it's bad.
pub fn check_response(&self, _: &Mutex<::cache::Cache>, signal: &[u8]) -> Result<Vec<u8>, Error> {
self.proof_check.check_proof(&*self.engine, signal)
.map(|_| signal.to_owned())
.map_err(|_| Error::BadProof)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -127,9 +127,6 @@ pub trait Provider: Send + Sync {
/// Provide a proof-of-execution for the given transaction proof request. /// Provide a proof-of-execution for the given transaction proof request.
/// Returns a vector of all state items necessary to execute the transaction. /// Returns a vector of all state items necessary to execute the transaction.
fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse>; fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse>;
/// Provide epoch signal data at given block hash. This should be just the
fn epoch_signal(&self, req: request::CompleteSignalRequest) -> Option<request::SignalResponse>;
} }
// Implementation of a light client data provider for a client. // Implementation of a light client data provider for a client.
@ -268,12 +265,6 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
fn ready_transactions(&self) -> Vec<PendingTransaction> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
BlockChainClient::ready_transactions(self) BlockChainClient::ready_transactions(self)
} }
fn epoch_signal(&self, req: request::CompleteSignalRequest) -> Option<request::SignalResponse> {
self.epoch_signal(req.block_hash).map(|signal| request::SignalResponse {
signal: signal,
})
}
} }
/// The light client "provider" implementation. This wraps a `LightClient` and /// The light client "provider" implementation. This wraps a `LightClient` and
@ -339,10 +330,6 @@ impl<L: AsLightClient + Send + Sync> Provider for LightProvider<L> {
None None
} }
fn epoch_signal(&self, _req: request::CompleteSignalRequest) -> Option<request::SignalResponse> {
None
}
fn ready_transactions(&self) -> Vec<PendingTransaction> { fn ready_transactions(&self) -> Vec<PendingTransaction> {
let chain_info = self.chain_info(); let chain_info = self.chain_info();
self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp) self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)

View File

@ -67,11 +67,6 @@ pub use self::execution::{
Incomplete as IncompleteExecutionRequest, Incomplete as IncompleteExecutionRequest,
Response as ExecutionResponse, Response as ExecutionResponse,
}; };
pub use self::epoch_signal::{
Complete as CompleteSignalRequest,
Incomplete as IncompleteSignalRequest,
Response as SignalResponse,
};
pub use self::builder::{RequestBuilder, Requests}; pub use self::builder::{RequestBuilder, Requests};
@ -266,8 +261,6 @@ pub enum Request {
Code(IncompleteCodeRequest), Code(IncompleteCodeRequest),
/// A request for proof of execution, /// A request for proof of execution,
Execution(IncompleteExecutionRequest), Execution(IncompleteExecutionRequest),
/// A request for an epoch signal.
Signal(IncompleteSignalRequest),
} }
/// All request types, in an answerable state. /// All request types, in an answerable state.
@ -291,8 +284,6 @@ pub enum CompleteRequest {
Code(CompleteCodeRequest), Code(CompleteCodeRequest),
/// A request for proof of execution, /// A request for proof of execution,
Execution(CompleteExecutionRequest), Execution(CompleteExecutionRequest),
/// A request for an epoch signal.
Signal(CompleteSignalRequest),
} }
impl CompleteRequest { impl CompleteRequest {
@ -308,7 +299,6 @@ impl CompleteRequest {
CompleteRequest::Storage(_) => Kind::Storage, CompleteRequest::Storage(_) => Kind::Storage,
CompleteRequest::Code(_) => Kind::Code, CompleteRequest::Code(_) => Kind::Code,
CompleteRequest::Execution(_) => Kind::Execution, CompleteRequest::Execution(_) => Kind::Execution,
CompleteRequest::Signal(_) => Kind::Signal,
} }
} }
} }
@ -326,7 +316,6 @@ impl Request {
Request::Storage(_) => Kind::Storage, Request::Storage(_) => Kind::Storage,
Request::Code(_) => Kind::Code, Request::Code(_) => Kind::Code,
Request::Execution(_) => Kind::Execution, Request::Execution(_) => Kind::Execution,
Request::Signal(_) => Kind::Signal,
} }
} }
} }
@ -343,7 +332,6 @@ impl Decodable for Request {
Kind::Storage => Ok(Request::Storage(rlp.val_at(1)?)), Kind::Storage => Ok(Request::Storage(rlp.val_at(1)?)),
Kind::Code => Ok(Request::Code(rlp.val_at(1)?)), Kind::Code => Ok(Request::Code(rlp.val_at(1)?)),
Kind::Execution => Ok(Request::Execution(rlp.val_at(1)?)), Kind::Execution => Ok(Request::Execution(rlp.val_at(1)?)),
Kind::Signal => Ok(Request::Signal(rlp.val_at(1)?)),
} }
} }
} }
@ -365,7 +353,6 @@ impl Encodable for Request {
Request::Storage(ref req) => s.append(req), Request::Storage(ref req) => s.append(req),
Request::Code(ref req) => s.append(req), Request::Code(ref req) => s.append(req),
Request::Execution(ref req) => s.append(req), Request::Execution(ref req) => s.append(req),
Request::Signal(ref req) => s.append(req),
}; };
} }
} }
@ -387,7 +374,6 @@ impl IncompleteRequest for Request {
Request::Storage(ref req) => req.check_outputs(f), Request::Storage(ref req) => req.check_outputs(f),
Request::Code(ref req) => req.check_outputs(f), Request::Code(ref req) => req.check_outputs(f),
Request::Execution(ref req) => req.check_outputs(f), Request::Execution(ref req) => req.check_outputs(f),
Request::Signal(ref req) => req.check_outputs(f),
} }
} }
@ -402,7 +388,6 @@ impl IncompleteRequest for Request {
Request::Storage(ref req) => req.note_outputs(f), Request::Storage(ref req) => req.note_outputs(f),
Request::Code(ref req) => req.note_outputs(f), Request::Code(ref req) => req.note_outputs(f),
Request::Execution(ref req) => req.note_outputs(f), Request::Execution(ref req) => req.note_outputs(f),
Request::Signal(ref req) => req.note_outputs(f),
} }
} }
@ -417,7 +402,6 @@ impl IncompleteRequest for Request {
Request::Storage(ref mut req) => req.fill(oracle), Request::Storage(ref mut req) => req.fill(oracle),
Request::Code(ref mut req) => req.fill(oracle), Request::Code(ref mut req) => req.fill(oracle),
Request::Execution(ref mut req) => req.fill(oracle), Request::Execution(ref mut req) => req.fill(oracle),
Request::Signal(ref mut req) => req.fill(oracle),
} }
} }
@ -432,7 +416,6 @@ impl IncompleteRequest for Request {
Request::Storage(req) => req.complete().map(CompleteRequest::Storage), Request::Storage(req) => req.complete().map(CompleteRequest::Storage),
Request::Code(req) => req.complete().map(CompleteRequest::Code), Request::Code(req) => req.complete().map(CompleteRequest::Code),
Request::Execution(req) => req.complete().map(CompleteRequest::Execution), Request::Execution(req) => req.complete().map(CompleteRequest::Execution),
Request::Signal(req) => req.complete().map(CompleteRequest::Signal),
} }
} }
@ -447,7 +430,6 @@ impl IncompleteRequest for Request {
Request::Storage(ref mut req) => req.adjust_refs(mapping), Request::Storage(ref mut req) => req.adjust_refs(mapping),
Request::Code(ref mut req) => req.adjust_refs(mapping), Request::Code(ref mut req) => req.adjust_refs(mapping),
Request::Execution(ref mut req) => req.adjust_refs(mapping), Request::Execution(ref mut req) => req.adjust_refs(mapping),
Request::Signal(ref mut req) => req.adjust_refs(mapping),
} }
} }
} }
@ -489,8 +471,6 @@ pub enum Kind {
Code = 7, Code = 7,
/// A request for transaction execution + state proof. /// A request for transaction execution + state proof.
Execution = 8, Execution = 8,
/// A request for epoch transition signal.
Signal = 9,
} }
impl Decodable for Kind { impl Decodable for Kind {
@ -505,7 +485,6 @@ impl Decodable for Kind {
6 => Ok(Kind::Storage), 6 => Ok(Kind::Storage),
7 => Ok(Kind::Code), 7 => Ok(Kind::Code),
8 => Ok(Kind::Execution), 8 => Ok(Kind::Execution),
9 => Ok(Kind::Signal),
_ => Err(DecoderError::Custom("Unknown PIP request ID.")), _ => Err(DecoderError::Custom("Unknown PIP request ID.")),
} }
} }
@ -538,8 +517,6 @@ pub enum Response {
Code(CodeResponse), Code(CodeResponse),
/// A response for proof of execution, /// A response for proof of execution,
Execution(ExecutionResponse), Execution(ExecutionResponse),
/// A response for epoch change signal.
Signal(SignalResponse),
} }
impl ResponseLike for Response { impl ResponseLike for Response {
@ -555,7 +532,6 @@ impl ResponseLike for Response {
Response::Storage(ref res) => res.fill_outputs(f), Response::Storage(ref res) => res.fill_outputs(f),
Response::Code(ref res) => res.fill_outputs(f), Response::Code(ref res) => res.fill_outputs(f),
Response::Execution(ref res) => res.fill_outputs(f), Response::Execution(ref res) => res.fill_outputs(f),
Response::Signal(ref res) => res.fill_outputs(f),
} }
} }
} }
@ -573,7 +549,6 @@ impl Response {
Response::Storage(_) => Kind::Storage, Response::Storage(_) => Kind::Storage,
Response::Code(_) => Kind::Code, Response::Code(_) => Kind::Code,
Response::Execution(_) => Kind::Execution, Response::Execution(_) => Kind::Execution,
Response::Signal(_) => Kind::Signal,
} }
} }
} }
@ -590,7 +565,6 @@ impl Decodable for Response {
Kind::Storage => Ok(Response::Storage(rlp.val_at(1)?)), Kind::Storage => Ok(Response::Storage(rlp.val_at(1)?)),
Kind::Code => Ok(Response::Code(rlp.val_at(1)?)), Kind::Code => Ok(Response::Code(rlp.val_at(1)?)),
Kind::Execution => Ok(Response::Execution(rlp.val_at(1)?)), Kind::Execution => Ok(Response::Execution(rlp.val_at(1)?)),
Kind::Signal => Ok(Response::Signal(rlp.val_at(1)?)),
} }
} }
} }
@ -612,7 +586,6 @@ impl Encodable for Response {
Response::Storage(ref res) => s.append(res), Response::Storage(ref res) => s.append(res),
Response::Code(ref res) => s.append(res), Response::Code(ref res) => s.append(res),
Response::Execution(ref res) => s.append(res), Response::Execution(ref res) => s.append(res),
Response::Signal(ref res) => s.append(res),
}; };
} }
} }
@ -787,8 +760,8 @@ pub mod header {
pub mod header_proof { pub mod header_proof {
use super::{Field, NoSuchOutput, OutputKind, Output}; use super::{Field, NoSuchOutput, OutputKind, Output};
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
use bigint::prelude::U256;
use bigint::hash::H256; use bigint::hash::H256;
use bigint::prelude::U256;
use util::Bytes; use util::Bytes;
/// Potentially incomplete header proof request. /// Potentially incomplete header proof request.
@ -1118,8 +1091,8 @@ pub mod block_body {
/// A request for an account proof. /// A request for an account proof.
pub mod account { pub mod account {
use super::{Field, NoSuchOutput, OutputKind, Output}; use super::{Field, NoSuchOutput, OutputKind, Output};
use bigint::prelude::U256;
use bigint::hash::H256; use bigint::hash::H256;
use bigint::prelude::U256;
use util::Bytes; use util::Bytes;
/// Potentially incomplete request for an account proof. /// Potentially incomplete request for an account proof.
@ -1415,8 +1388,8 @@ pub mod execution {
use super::{Field, NoSuchOutput, OutputKind, Output}; use super::{Field, NoSuchOutput, OutputKind, Output};
use ethcore::transaction::Action; use ethcore::transaction::Action;
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
use bigint::prelude::U256;
use bigint::hash::H256; use bigint::hash::H256;
use bigint::prelude::U256;
use util::{Bytes, Address, DBValue}; use util::{Bytes, Address, DBValue};
/// Potentially incomplete execution proof request. /// Potentially incomplete execution proof request.
@ -1536,105 +1509,6 @@ pub mod execution {
} }
} }
/// A request for epoch signal data.
pub mod epoch_signal {
use super::{Field, NoSuchOutput, OutputKind, Output};
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
use bigint::hash::H256;
use util::Bytes;
/// Potentially incomplete epoch signal request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Incomplete {
/// The block hash to request the signal for.
pub block_hash: Field<H256>,
}
impl Decodable for Incomplete {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(Incomplete {
block_hash: rlp.val_at(0)?,
})
}
}
impl Encodable for Incomplete {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(1).append(&self.block_hash);
}
}
impl super::IncompleteRequest for Incomplete {
type Complete = Complete;
type Response = Response;
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
{
if let Field::BackReference(req, idx) = self.block_hash {
f(req, idx, OutputKind::Hash)?;
}
Ok(())
}
fn note_outputs<F>(&self, _: F) where F: FnMut(usize, OutputKind) {}
fn fill<F>(&mut self, oracle: F) where F: Fn(usize, usize) -> Result<Output, NoSuchOutput> {
if let Field::BackReference(req, idx) = self.block_hash {
self.block_hash = match oracle(req, idx) {
Ok(Output::Hash(block_hash)) => Field::Scalar(block_hash.into()),
_ => Field::BackReference(req, idx),
}
}
}
fn complete(self) -> Result<Self::Complete, NoSuchOutput> {
Ok(Complete {
block_hash: self.block_hash.into_scalar()?,
})
}
fn adjust_refs<F>(&mut self, mut mapping: F) where F: FnMut(usize) -> usize {
self.block_hash.adjust_req(&mut mapping);
}
}
/// A complete request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Complete {
/// The block hash to request the epoch signal for.
pub block_hash: H256,
}
/// The output of a request for an epoch signal.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Response {
/// The requested epoch signal.
pub signal: Bytes,
}
impl super::ResponseLike for Response {
/// Fill reusable outputs by providing them to the function.
fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
}
impl Decodable for Response {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(Response {
signal: rlp.as_val()?,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.signal);
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -1923,22 +1797,4 @@ mod tests {
let raw = ::rlp::encode_list(&reqs); let raw = ::rlp::encode_list(&reqs);
assert_eq!(::rlp::decode_list::<Response>(&raw), reqs); assert_eq!(::rlp::decode_list::<Response>(&raw), reqs);
} }
#[test]
fn epoch_signal_roundtrip() {
let req = IncompleteSignalRequest {
block_hash: Field::Scalar(Default::default()),
};
let full_req = Request::Signal(req.clone());
let res = SignalResponse {
signal: vec![1, 2, 3, 4, 5, 6, 7, 6, 5, 4],
};
let full_res = Response::Signal(res.clone());
check_roundtrip(req);
check_roundtrip(full_req);
check_roundtrip(res);
check_roundtrip(full_res);
}
} }

View File

@ -42,7 +42,7 @@ use client::ancient_import::AncientVerifier;
use client::Error as ClientError; use client::Error as ClientError;
use client::{ use client::{
BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, MiningBlockChainClient, EngineClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
ChainNotify, PruningInfo, ProvingBlockChainClient, ChainNotify, PruningInfo, ProvingBlockChainClient,
}; };
use encoded; use encoded;
@ -770,7 +770,7 @@ impl Client {
res.map(|(output, proof)| (output, proof.into_iter().map(|x| x.into_vec()).collect())) res.map(|(output, proof)| (output, proof.into_iter().map(|x| x.into_vec()).collect()))
}; };
match with_state.generate_proof(&call) { match (with_state)(&call) {
Ok(proof) => proof, Ok(proof) => proof,
Err(e) => { Err(e) => {
warn!(target: "client", "Failed to generate transition proof for block {}: {}", hash, e); warn!(target: "client", "Failed to generate transition proof for block {}: {}", hash, e);
@ -1131,7 +1131,9 @@ impl Client {
T: trace::Tracer, T: trace::Tracer,
V: trace::VMTracer, V: trace::VMTracer,
{ {
let options = options.dont_check_nonce(); let options = options
.dont_check_nonce()
.save_output_from_contract();
let original_state = if state_diff { Some(state.clone()) } else { None }; let original_state = if state_diff { Some(state.clone()) } else { None };
let mut ret = Executive::new(state, env_info, engine).transact_virtual(transaction, options)?; let mut ret = Executive::new(state, env_info, engine).transact_virtual(transaction, options)?;
@ -1934,7 +1936,7 @@ impl MiningBlockChainClient for Client {
} }
} }
impl super::traits::EngineClient for Client { impl EngineClient for Client {
fn update_sealing(&self) { fn update_sealing(&self) {
self.miner.update_sealing(self) self.miner.update_sealing(self)
} }
@ -1952,22 +1954,6 @@ impl super::traits::EngineClient for Client {
fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition> { fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition> {
self.chain.read().epoch_transition_for(parent_hash) self.chain.read().epoch_transition_for(parent_hash)
} }
fn chain_info(&self) -> BlockChainInfo {
BlockChainClient::chain_info(self)
}
fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
BlockChainClient::call_contract(self, id, address, data)
}
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError> {
BlockChainClient::transact_contract(self, address, data)
}
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
BlockChainClient::block_number(self, id)
}
} }
impl ProvingBlockChainClient for Client { impl ProvingBlockChainClient for Client {
@ -1982,29 +1968,27 @@ impl ProvingBlockChainClient for Client {
} }
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)> { fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
let (header, mut env_info) = match (self.block_header(id), self.env_info(id)) { let (state, mut env_info) = match (self.state_at(id), self.env_info(id)) {
(Some(s), Some(e)) => (s, e), (Some(s), Some(e)) => (s, e),
_ => return None, _ => return None,
}; };
env_info.gas_limit = transaction.gas.clone(); env_info.gas_limit = transaction.gas.clone();
let mut jdb = self.state_db.lock().journal_db().boxed_clone(); let mut jdb = self.state_db.lock().journal_db().boxed_clone();
let backend = state::backend::Proving::new(jdb.as_hashdb_mut());
state::prove_transaction( let mut state = state.replace_backend(backend);
jdb.as_hashdb_mut(), let options = TransactOptions::with_no_tracing().dont_check_nonce();
header.state_root().clone(), let res = Executive::new(&mut state, &env_info, &*self.engine).transact(&transaction, options);
&transaction,
&*self.engine,
&env_info,
self.factories.clone(),
false,
)
}
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>> { match res {
// pending transitions are never deleted, and do not contain Err(ExecutionError::Internal(_)) => None,
// finality proofs by definition. Err(e) => {
self.chain.read().get_pending_transition(hash).map(|pending| pending.proof) trace!(target: "client", "Proved call failed: {}", e);
Some((Vec::new(), state.drop().1.extract_proof()))
}
Ok(res) => Some((res.output, state.drop().1.extract_proof())),
}
} }
} }

View File

@ -33,7 +33,7 @@ use devtools::*;
use transaction::{Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action}; use transaction::{Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action};
use blockchain::TreeRoute; use blockchain::TreeRoute;
use client::{ use client::{
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId, BlockChainClient, MiningBlockChainClient, EngineClient, BlockChainInfo, BlockStatus, BlockId,
TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError,
ProvingBlockChainClient, ProvingBlockChainClient,
}; };
@ -801,13 +801,9 @@ impl ProvingBlockChainClient for TestBlockChainClient {
fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<(Bytes, Vec<DBValue>)> { fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
None None
} }
fn epoch_signal(&self, _: H256) -> Option<Vec<u8>> {
None
}
} }
impl super::traits::EngineClient for TestBlockChainClient { impl EngineClient for TestBlockChainClient {
fn update_sealing(&self) { fn update_sealing(&self) {
self.miner.update_sealing(self) self.miner.update_sealing(self)
} }
@ -823,20 +819,4 @@ impl super::traits::EngineClient for TestBlockChainClient {
fn epoch_transition_for(&self, _block_hash: H256) -> Option<::engines::EpochTransition> { fn epoch_transition_for(&self, _block_hash: H256) -> Option<::engines::EpochTransition> {
None None
} }
fn chain_info(&self) -> BlockChainInfo {
BlockChainClient::chain_info(self)
}
fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
BlockChainClient::call_contract(self, id, address, data)
}
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError> {
BlockChainClient::transact_contract(self, address, data)
}
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
BlockChainClient::block_number(self, id)
}
} }

View File

@ -317,7 +317,7 @@ pub trait MiningBlockChainClient: BlockChainClient {
} }
/// Client facilities used by internally sealing Engines. /// Client facilities used by internally sealing Engines.
pub trait EngineClient: Sync + Send { pub trait EngineClient: MiningBlockChainClient {
/// Make a new block and seal it. /// Make a new block and seal it.
fn update_sealing(&self); fn update_sealing(&self);
@ -333,17 +333,6 @@ pub trait EngineClient: Sync + Send {
/// ///
/// The block corresponding the the parent hash must be stored already. /// The block corresponding the the parent hash must be stored already.
fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition>; fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition>;
/// Get block chain info.
fn chain_info(&self) -> BlockChainInfo;
/// Like `call`, but with various defaults. Designed to be used for calling contracts.
fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String>;
/// Import a transaction: used for misbehaviour reporting.
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError>;
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
} }
/// Extended client interface for providing proofs of the state. /// Extended client interface for providing proofs of the state.
@ -363,7 +352,4 @@ pub trait ProvingBlockChainClient: BlockChainClient {
/// Returns the output of the call and a vector of database items necessary /// Returns the output of the call and a vector of database items necessary
/// to reproduce it. /// to reproduce it.
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)>; fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)>;
/// Get an epoch change signal by block hash.
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>>;
} }

View File

@ -25,7 +25,7 @@ use std::cmp;
use account_provider::AccountProvider; use account_provider::AccountProvider;
use block::*; use block::*;
use builtin::Builtin; use builtin::Builtin;
use client::EngineClient; use client::{Client, EngineClient};
use engines::{Call, Engine, Seal, EngineError, ConstructedVerifier}; use engines::{Call, Engine, Seal, EngineError, ConstructedVerifier};
use error::{Error, TransactionError, BlockError}; use error::{Error, TransactionError, BlockError};
use ethjson; use ethjson;
@ -646,8 +646,6 @@ impl Engine for AuthorityRound {
(&active_set as &_, epoch_manager.epoch_transition_number) (&active_set as &_, epoch_manager.epoch_transition_number)
}; };
// always report with "self.validators" so that the report actually gets
// to the contract.
let report = |report| match report { let report = |report| match report {
Report::Benign(address, block_number) => Report::Benign(address, block_number) =>
self.validators.report_benign(&address, set_number, block_number), self.validators.report_benign(&address, set_number, block_number),
@ -740,18 +738,13 @@ impl Engine for AuthorityRound {
{ {
if let Ok(finalized) = epoch_manager.finality_checker.push_hash(chain_head.hash(), *chain_head.author()) { if let Ok(finalized) = epoch_manager.finality_checker.push_hash(chain_head.hash(), *chain_head.author()) {
let mut finalized = finalized.into_iter(); let mut finalized = finalized.into_iter();
while let Some(finalized_hash) = finalized.next() { while let Some(hash) = finalized.next() {
if let Some(pending) = transition_store(finalized_hash) { if let Some(pending) = transition_store(hash) {
let finality_proof = ::std::iter::once(finalized_hash) let finality_proof = ::std::iter::once(hash)
.chain(finalized) .chain(finalized)
.chain(epoch_manager.finality_checker.unfinalized_hashes()) .chain(epoch_manager.finality_checker.unfinalized_hashes())
.map(|h| if h == chain_head.hash() { .map(|hash| chain(hash)
// chain closure only stores ancestry, but the chain head is also .expect("these headers fetched before when constructing finality checker; qed"))
// unfinalized.
chain_head.clone()
} else {
chain(h).expect("these headers fetched before when constructing finality checker; qed")
})
.collect::<Vec<Header>>(); .collect::<Vec<Header>>();
// this gives us the block number for `hash`, assuming it's ancestry. // this gives us the block number for `hash`, assuming it's ancestry.
@ -815,9 +808,9 @@ impl Engine for AuthorityRound {
Ok(()) Ok(())
} }
fn register_client(&self, client: Weak<EngineClient>) { fn register_client(&self, client: Weak<Client>) {
*self.client.write() = Some(client.clone()); *self.client.write() = Some(client.clone());
self.validators.register_client(client); self.validators.register_contract(client);
} }
fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) { fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) {

View File

@ -33,7 +33,7 @@ use error::{BlockError, Error};
use evm::Schedule; use evm::Schedule;
use ethjson; use ethjson;
use header::{Header, BlockNumber}; use header::{Header, BlockNumber};
use client::EngineClient; use client::Client;
use semantic_version::SemanticVersion; use semantic_version::SemanticVersion;
use super::signer::EngineSigner; use super::signer::EngineSigner;
use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; use super::validator_set::{ValidatorSet, SimpleList, new_validator_set};
@ -236,8 +236,8 @@ impl Engine for BasicAuthority {
} }
} }
fn register_client(&self, client: Weak<EngineClient>) { fn register_client(&self, client: Weak<Client>) {
self.validators.register_client(client); self.validators.register_contract(client);
} }
fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) { fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) {

View File

@ -44,7 +44,7 @@ use self::epoch::PendingTransition;
use account_provider::AccountProvider; use account_provider::AccountProvider;
use block::ExecutedBlock; use block::ExecutedBlock;
use builtin::Builtin; use builtin::Builtin;
use client::EngineClient; use client::Client;
use vm::{EnvInfo, LastHashes, Schedule, CreateContractAddress}; use vm::{EnvInfo, LastHashes, Schedule, CreateContractAddress};
use error::Error; use error::Error;
use header::{Header, BlockNumber}; use header::{Header, BlockNumber};
@ -123,22 +123,12 @@ pub type Headers<'a> = Fn(H256) -> Option<Header> + 'a;
/// Type alias for a function we can query pending transitions by block hash through. /// Type alias for a function we can query pending transitions by block hash through.
pub type PendingTransitionStore<'a> = Fn(H256) -> Option<PendingTransition> + 'a; pub type PendingTransitionStore<'a> = Fn(H256) -> Option<PendingTransition> + 'a;
/// Proof dependent on state.
pub trait StateDependentProof: Send + Sync {
/// Generate a proof, given the state.
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String>;
/// Check a proof generated elsewhere (potentially by a peer).
// `engine` needed to check state proofs, while really this should
// just be state machine params.
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String>;
}
/// Proof generated on epoch change. /// Proof generated on epoch change.
pub enum Proof { pub enum Proof {
/// Known proof (extracted from signal) /// Known proof (exctracted from signal)
Known(Vec<u8>), Known(Vec<u8>),
/// State dependent proof. /// Extract proof from caller.
WithState(Arc<StateDependentProof>), WithState(Box<Fn(&Call) -> Result<Vec<u8>, String>>),
} }
/// Generated epoch verifier. /// Generated epoch verifier.
@ -370,7 +360,7 @@ pub trait Engine : Sync + Send {
fn sign(&self, _hash: H256) -> Result<Signature, Error> { unimplemented!() } fn sign(&self, _hash: H256) -> Result<Signature, Error> { unimplemented!() }
/// Add Client which can be used for sealing, querying the state and sending messages. /// Add Client which can be used for sealing, querying the state and sending messages.
fn register_client(&self, _client: Weak<EngineClient>) {} fn register_client(&self, _client: Weak<Client>) {}
/// Trigger next step of the consensus engine. /// Trigger next step of the consensus engine.
fn step(&self) {} fn step(&self) {}

View File

@ -34,7 +34,7 @@ use bigint::prelude::{U128, U256};
use bigint::hash::{H256, H520}; use bigint::hash::{H256, H520};
use parking_lot::RwLock; use parking_lot::RwLock;
use util::*; use util::*;
use client::EngineClient; use client::{Client, EngineClient};
use error::{Error, BlockError}; use error::{Error, BlockError};
use header::{Header, BlockNumber}; use header::{Header, BlockNumber};
use builtin::Builtin; use builtin::Builtin;
@ -570,35 +570,18 @@ impl Engine for Tendermint {
Ok(()) Ok(())
} }
/// Verify gas limit. /// Verify validators and gas limit.
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
if header.number() == 0 { if header.number() == 0 {
return Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }).into()); return Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }).into());
} }
let gas_limit_divisor = self.params().gas_limit_bound_divisor;
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
self.validators.report_malicious(header.author(), header.number(), header.number(), Default::default());
return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
}
Ok(())
}
fn verify_block_external(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
if let Ok(proposal) = ConsensusMessage::new_proposal(header) { if let Ok(proposal) = ConsensusMessage::new_proposal(header) {
let proposer = proposal.verify()?; let proposer = proposal.verify()?;
if !self.is_authority(&proposer) { if !self.is_authority(&proposer) {
return Err(EngineError::NotAuthorized(proposer).into()); return Err(EngineError::NotAuthorized(proposer).into());
} }
self.check_view_proposer( self.check_view_proposer(header.parent_hash(), proposal.vote_step.height, proposal.vote_step.view, &proposer)?;
header.parent_hash(),
proposal.vote_step.height,
proposal.vote_step.view,
&proposer
).map_err(Into::into)
} else { } else {
let vote_step = VoteStep::new(header.number() as usize, consensus_view(header)?, Step::Precommit); let vote_step = VoteStep::new(header.number() as usize, consensus_view(header)?, Step::Precommit);
let precommit_hash = message_hash(vote_step.clone(), header.bare_hash()); let precommit_hash = message_hash(vote_step.clone(), header.bare_hash());
@ -624,8 +607,18 @@ impl Engine for Tendermint {
} }
} }
self.check_above_threshold(origins.len()).map_err(Into::into) self.check_above_threshold(origins.len())?
} }
let gas_limit_divisor = self.params().gas_limit_bound_divisor;
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
self.validators.report_malicious(header.author(), header.number(), header.number(), Default::default());
return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
}
Ok(())
} }
fn signals_epoch_end(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>) fn signals_epoch_end(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
@ -760,12 +753,13 @@ impl Engine for Tendermint {
self.to_step(next_step); self.to_step(next_step);
} }
fn register_client(&self, client: Weak<EngineClient>) { fn register_client(&self, client: Weak<Client>) {
use client::BlockChainClient;
if let Some(c) = client.upgrade() { if let Some(c) = client.upgrade() {
self.height.store(c.chain_info().best_block_number as usize + 1, AtomicOrdering::SeqCst); self.height.store(c.chain_info().best_block_number as usize + 1, AtomicOrdering::SeqCst);
} }
*self.client.write() = Some(client.clone()); *self.client.write() = Some(client.clone());
self.validators.register_client(client); self.validators.register_contract(client);
} }
} }
@ -893,14 +887,14 @@ mod tests {
let seal = proposal_seal(&tap, &header, 0); let seal = proposal_seal(&tap, &header, 0);
header.set_seal(seal); header.set_seal(seal);
// Good proposer. // Good proposer.
assert!(engine.verify_block_external(&header, None).is_ok()); assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
let validator = insert_and_unlock(&tap, "0"); let validator = insert_and_unlock(&tap, "0");
header.set_author(validator); header.set_author(validator);
let seal = proposal_seal(&tap, &header, 0); let seal = proposal_seal(&tap, &header, 0);
header.set_seal(seal); header.set_seal(seal);
// Bad proposer. // Bad proposer.
match engine.verify_block_external(&header, None) { match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::NotProposer(_))) => {}, Err(Error::Engine(EngineError::NotProposer(_))) => {},
_ => panic!(), _ => panic!(),
} }
@ -910,7 +904,7 @@ mod tests {
let seal = proposal_seal(&tap, &header, 0); let seal = proposal_seal(&tap, &header, 0);
header.set_seal(seal); header.set_seal(seal);
// Not authority. // Not authority.
match engine.verify_block_external(&header, None) { match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::NotAuthorized(_))) => {}, Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
_ => panic!(), _ => panic!(),
}; };
@ -940,7 +934,7 @@ mod tests {
header.set_seal(seal.clone()); header.set_seal(seal.clone());
// One good signature is not enough. // One good signature is not enough.
match engine.verify_block_external(&header, None) { match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {}, Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {},
_ => panic!(), _ => panic!(),
} }
@ -951,7 +945,7 @@ mod tests {
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]).into_vec(); seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]).into_vec();
header.set_seal(seal.clone()); header.set_seal(seal.clone());
assert!(engine.verify_block_external(&header, None).is_ok()); assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
let bad_voter = insert_and_unlock(&tap, "101"); let bad_voter = insert_and_unlock(&tap, "101");
let bad_signature = tap.sign(bad_voter, None, keccak(vote_info)).unwrap(); let bad_signature = tap.sign(bad_voter, None, keccak(vote_info)).unwrap();
@ -960,7 +954,7 @@ mod tests {
header.set_seal(seal); header.set_seal(seal);
// One good and one bad signature. // One good and one bad signature.
match engine.verify_block_external(&header, None) { match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::NotAuthorized(_))) => {}, Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
_ => panic!(), _ => panic!(),
}; };
@ -1006,7 +1000,7 @@ mod tests {
let client = generate_dummy_client(0); let client = generate_dummy_client(0);
let notify = Arc::new(TestNotify::default()); let notify = Arc::new(TestNotify::default());
client.add_notify(notify.clone()); client.add_notify(notify.clone());
engine.register_client(Arc::downgrade(&client) as _); engine.register_client(Arc::downgrade(&client));
let prevote_current = vote(engine.as_ref(), |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Prevote, proposal); let prevote_current = vote(engine.as_ref(), |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Prevote, proposal);
@ -1024,6 +1018,7 @@ mod tests {
fn seal_submission() { fn seal_submission() {
use ethkey::{Generator, Random}; use ethkey::{Generator, Random};
use transaction::{Transaction, Action}; use transaction::{Transaction, Action};
use client::BlockChainClient;
let tap = Arc::new(AccountProvider::transient_provider()); let tap = Arc::new(AccountProvider::transient_provider());
// Accounts for signing votes. // Accounts for signing votes.
@ -1036,7 +1031,7 @@ mod tests {
let notify = Arc::new(TestNotify::default()); let notify = Arc::new(TestNotify::default());
client.add_notify(notify.clone()); client.add_notify(notify.clone());
engine.register_client(Arc::downgrade(&client) as _); engine.register_client(Arc::downgrade(&client));
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
let transaction = Transaction { let transaction = Transaction {

View File

@ -25,7 +25,7 @@ use util::*;
use futures::Future; use futures::Future;
use native_contracts::ValidatorReport as Provider; use native_contracts::ValidatorReport as Provider;
use client::EngineClient; use client::{Client, BlockChainClient};
use engines::{Call, Engine}; use engines::{Call, Engine};
use header::{Header, BlockNumber}; use header::{Header, BlockNumber};
@ -36,7 +36,7 @@ use super::safe_contract::ValidatorSafeContract;
pub struct ValidatorContract { pub struct ValidatorContract {
validators: ValidatorSafeContract, validators: ValidatorSafeContract,
provider: Provider, provider: Provider,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove client: RwLock<Option<Weak<Client>>>, // TODO [keorn]: remove
} }
impl ValidatorContract { impl ValidatorContract {
@ -120,8 +120,8 @@ impl ValidatorSet for ValidatorContract {
} }
} }
fn register_client(&self, client: Weak<EngineClient>) { fn register_contract(&self, client: Weak<Client>) {
self.validators.register_client(client.clone()); self.validators.register_contract(client.clone());
*self.client.write() = Some(client); *self.client.write() = Some(client);
} }
} }
@ -148,7 +148,7 @@ mod tests {
fn fetches_validators() { fn fetches_validators() {
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None);
let vc = Arc::new(ValidatorContract::new("0000000000000000000000000000000000000005".parse::<Address>().unwrap())); let vc = Arc::new(ValidatorContract::new("0000000000000000000000000000000000000005".parse::<Address>().unwrap()));
vc.register_client(Arc::downgrade(&client) as _); vc.register_contract(Arc::downgrade(&client));
let last_hash = client.best_block_header().hash(); let last_hash = client.best_block_header().hash();
assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap())); assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap()));
assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap())); assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap()));
@ -159,7 +159,7 @@ mod tests {
let tap = Arc::new(AccountProvider::transient_provider()); let tap = Arc::new(AccountProvider::transient_provider());
let v1 = tap.insert_account(keccak("1").into(), "").unwrap(); let v1 = tap.insert_account(keccak("1").into(), "").unwrap();
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone())); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone()));
client.engine().register_client(Arc::downgrade(&client) as _); client.engine().register_client(Arc::downgrade(&client));
let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap(); let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap();
// Make sure reporting can be done. // Make sure reporting can be done.

View File

@ -28,7 +28,7 @@ use ids::BlockId;
use bigint::hash::H256; use bigint::hash::H256;
use util::{Bytes, Address}; use util::{Bytes, Address};
use ethjson::spec::ValidatorSet as ValidatorSpec; use ethjson::spec::ValidatorSet as ValidatorSpec;
use client::EngineClient; use client::Client;
use header::{Header, BlockNumber}; use header::{Header, BlockNumber};
#[cfg(test)] #[cfg(test)]
@ -142,5 +142,5 @@ pub trait ValidatorSet: Send + Sync {
/// Notifies about benign misbehaviour. /// Notifies about benign misbehaviour.
fn report_benign(&self, _validator: &Address, _set_block: BlockNumber, _block: BlockNumber) {} fn report_benign(&self, _validator: &Address, _set_block: BlockNumber, _block: BlockNumber) {}
/// Allows blockchain state access. /// Allows blockchain state access.
fn register_client(&self, _client: Weak<EngineClient>) {} fn register_contract(&self, _client: Weak<Client>) {}
} }

View File

@ -24,7 +24,7 @@ use parking_lot::RwLock;
use util::{Bytes, Address}; use util::{Bytes, Address};
use ids::BlockId; use ids::BlockId;
use header::{BlockNumber, Header}; use header::{BlockNumber, Header};
use client::EngineClient; use client::{Client, BlockChainClient};
use super::{SystemCall, ValidatorSet}; use super::{SystemCall, ValidatorSet};
type BlockNumberLookup = Box<Fn(BlockId) -> Result<BlockNumber, String> + Send + Sync + 'static>; type BlockNumberLookup = Box<Fn(BlockId) -> Result<BlockNumber, String> + Send + Sync + 'static>;
@ -131,9 +131,9 @@ impl ValidatorSet for Multi {
self.correct_set_by_number(set_block).1.report_benign(validator, set_block, block); self.correct_set_by_number(set_block).1.report_benign(validator, set_block, block);
} }
fn register_client(&self, client: Weak<EngineClient>) { fn register_contract(&self, client: Weak<Client>) {
for set in self.sets.values() { for set in self.sets.values() {
set.register_client(client.clone()); set.register_contract(client.clone());
} }
*self.block_number.write() = Box::new(move |id| client *self.block_number.write() = Box::new(move |id| client
.upgrade() .upgrade()
@ -148,7 +148,7 @@ mod tests {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use hash::keccak; use hash::keccak;
use account_provider::AccountProvider; use account_provider::AccountProvider;
use client::BlockChainClient; use client::{BlockChainClient, EngineClient};
use engines::EpochChange; use engines::EpochChange;
use engines::validator_set::ValidatorSet; use engines::validator_set::ValidatorSet;
use ethkey::Secret; use ethkey::Secret;
@ -170,7 +170,7 @@ mod tests {
let v0 = tap.insert_account(s0.clone(), "").unwrap(); let v0 = tap.insert_account(s0.clone(), "").unwrap();
let v1 = tap.insert_account(keccak("1").into(), "").unwrap(); let v1 = tap.insert_account(keccak("1").into(), "").unwrap();
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_multi, Some(tap)); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_multi, Some(tap));
client.engine().register_client(Arc::downgrade(&client) as _); client.engine().register_client(Arc::downgrade(&client));
// Make sure txs go through. // Make sure txs go through.
client.miner().set_gas_floor_target(1_000_000.into()); client.miner().set_gas_floor_target(1_000_000.into());
@ -178,27 +178,27 @@ mod tests {
// Wrong signer for the first block. // Wrong signer for the first block.
client.miner().set_engine_signer(v1, "".into()).unwrap(); client.miner().set_engine_signer(v1, "".into()).unwrap();
client.transact_contract(Default::default(), Default::default()).unwrap(); client.transact_contract(Default::default(), Default::default()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 0); assert_eq!(client.chain_info().best_block_number, 0);
// Right signer for the first block. // Right signer for the first block.
client.miner().set_engine_signer(v0, "".into()).unwrap(); client.miner().set_engine_signer(v0, "".into()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 1); assert_eq!(client.chain_info().best_block_number, 1);
// This time v0 is wrong. // This time v0 is wrong.
client.transact_contract(Default::default(), Default::default()).unwrap(); client.transact_contract(Default::default(), Default::default()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 1); assert_eq!(client.chain_info().best_block_number, 1);
client.miner().set_engine_signer(v1, "".into()).unwrap(); client.miner().set_engine_signer(v1, "".into()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 2); assert_eq!(client.chain_info().best_block_number, 2);
// v1 is still good. // v1 is still good.
client.transact_contract(Default::default(), Default::default()).unwrap(); client.transact_contract(Default::default(), Default::default()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 3); assert_eq!(client.chain_info().best_block_number, 3);
// Check syncing. // Check syncing.
let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_multi, 0, 0, &[]); let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_multi, 0, 0, &[]);
sync_client.engine().register_client(Arc::downgrade(&sync_client) as _); sync_client.engine().register_client(Arc::downgrade(&sync_client));
for i in 1..4 { for i in 1..4 {
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap(); sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
} }

View File

@ -23,14 +23,13 @@ use hash::keccak;
use bigint::prelude::U256; use bigint::prelude::U256;
use bigint::hash::{H160, H256}; use bigint::hash::{H160, H256};
use parking_lot::{Mutex, RwLock}; use parking_lot::RwLock;
use util::*; use util::*;
use util::cache::MemoryLruCache; use util::cache::MemoryLruCache;
use rlp::{UntrustedRlp, RlpStream}; use rlp::{UntrustedRlp, RlpStream};
use basic_types::LogBloom; use basic_types::LogBloom;
use client::EngineClient; use client::{Client, BlockChainClient};
use engines::{Call, Engine}; use engines::{Call, Engine};
use header::Header; use header::Header;
use ids::BlockId; use ids::BlockId;
@ -49,35 +48,12 @@ lazy_static! {
static ref EVENT_NAME_HASH: H256 = keccak(EVENT_NAME); static ref EVENT_NAME_HASH: H256 = keccak(EVENT_NAME);
} }
// state-dependent proofs for the safe contract:
// only "first" proofs are such.
struct StateProof {
header: Mutex<Header>,
provider: Provider,
}
impl ::engines::StateDependentProof for StateProof {
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
prove_initial(&self.provider, &*self.header.lock(), caller)
}
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String> {
let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof))
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
if &header != &*self.header.lock(){
return Err("wrong header in proof".into());
}
check_first_proof(engine, &self.provider, header, &state_items).map(|_| ())
}
}
/// The validator contract should have the following interface: /// The validator contract should have the following interface:
pub struct ValidatorSafeContract { pub struct ValidatorSafeContract {
pub address: Address, pub address: Address,
validators: RwLock<MemoryLruCache<H256, SimpleList>>, validators: RwLock<MemoryLruCache<H256, SimpleList>>,
provider: Provider, provider: Provider,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove client: RwLock<Option<Weak<Client>>>, // TODO [keorn]: remove
} }
// first proof is just a state proof call of `getValidators` at header's state. // first proof is just a state proof call of `getValidators` at header's state.
@ -91,59 +67,6 @@ fn encode_first_proof(header: &Header, state_items: &[Vec<u8>]) -> Bytes {
stream.out() stream.out()
} }
// check a first proof: fetch the validator set at the given block.
fn check_first_proof(engine: &Engine, provider: &Provider, old_header: Header, state_items: &[DBValue])
-> Result<Vec<Address>, String>
{
use transaction::{Action, Transaction};
// TODO: match client contract_call_tx more cleanly without duplication.
const PROVIDED_GAS: u64 = 50_000_000;
let env_info = ::vm::EnvInfo {
number: old_header.number(),
author: *old_header.author(),
difficulty: *old_header.difficulty(),
gas_limit: PROVIDED_GAS.into(),
timestamp: old_header.timestamp(),
last_hashes: {
// this will break if we don't inclue all 256 last hashes.
let mut last_hashes: Vec<_> = (0..256).map(|_| H256::default()).collect();
last_hashes[255] = *old_header.parent_hash();
Arc::new(last_hashes)
},
gas_used: 0.into(),
};
// check state proof using given engine.
let number = old_header.number();
provider.get_validators(move |a, d| {
let from = Address::default();
let tx = Transaction {
nonce: engine.account_start_nonce(number),
action: Action::Call(a),
gas: PROVIDED_GAS.into(),
gas_price: U256::default(),
value: U256::default(),
data: d,
}.fake_sign(from);
let res = ::state::check_proof(
state_items,
*old_header.state_root(),
&tx,
engine,
&env_info,
);
match res {
::state::ProvedExecution::BadProof => Err("Bad proof".into()),
::state::ProvedExecution::Failed(e) => Err(format!("Failed call: {}", e)),
::state::ProvedExecution::Complete(e) => Ok(e.output),
}
}).wait()
}
fn decode_first_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec<DBValue>), ::error::Error> { fn decode_first_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec<DBValue>), ::error::Error> {
let header = rlp.val_at(0)?; let header = rlp.val_at(0)?;
let state_items = rlp.at(1)?.iter().map(|x| { let state_items = rlp.at(1)?.iter().map(|x| {
@ -181,7 +104,8 @@ fn prove_initial(provider: &Provider, header: &Header, caller: &Call) -> Result<
Ok(result) Ok(result)
}; };
provider.get_validators(caller).wait() provider.get_validators(caller)
.wait()
}; };
res.map(|validators| { res.map(|validators| {
@ -335,11 +259,9 @@ impl ValidatorSet for ValidatorSafeContract {
// transition to the first block of a contract requires finality but has no log event. // transition to the first block of a contract requires finality but has no log event.
if first { if first {
debug!(target: "engine", "signalling transition to fresh contract."); debug!(target: "engine", "signalling transition to fresh contract.");
let state_proof = Arc::new(StateProof { let (provider, header) = (self.provider.clone(), header.clone());
header: Mutex::new(header.clone()), let with_caller: Box<Fn(&Call) -> _> = Box::new(move |caller| prove_initial(&provider, &header, caller));
provider: self.provider.clone(), return ::engines::EpochChange::Yes(::engines::Proof::WithState(with_caller))
});
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>));
} }
// otherwise, we're checking for logs. // otherwise, we're checking for logs.
@ -368,16 +290,61 @@ impl ValidatorSet for ValidatorSafeContract {
fn epoch_set(&self, first: bool, engine: &Engine, _number: ::header::BlockNumber, proof: &[u8]) fn epoch_set(&self, first: bool, engine: &Engine, _number: ::header::BlockNumber, proof: &[u8])
-> Result<(SimpleList, Option<H256>), ::error::Error> -> Result<(SimpleList, Option<H256>), ::error::Error>
{ {
use transaction::{Action, Transaction};
let rlp = UntrustedRlp::new(proof); let rlp = UntrustedRlp::new(proof);
if first { if first {
trace!(target: "engine", "Recovering initial epoch set"); trace!(target: "engine", "Recovering initial epoch set");
// TODO: match client contract_call_tx more cleanly without duplication.
const PROVIDED_GAS: u64 = 50_000_000;
let (old_header, state_items) = decode_first_proof(&rlp)?; let (old_header, state_items) = decode_first_proof(&rlp)?;
let number = old_header.number();
let old_hash = old_header.hash(); let old_hash = old_header.hash();
let addresses = check_first_proof(engine, &self.provider, old_header, &state_items)
.map_err(::engines::EngineError::InsufficientProof)?; let env_info = ::vm::EnvInfo {
number: old_header.number(),
author: *old_header.author(),
difficulty: *old_header.difficulty(),
gas_limit: PROVIDED_GAS.into(),
timestamp: old_header.timestamp(),
last_hashes: {
// this will break if we don't inclue all 256 last hashes.
let mut last_hashes: Vec<_> = (0..256).map(|_| H256::default()).collect();
last_hashes[255] = *old_header.parent_hash();
Arc::new(last_hashes)
},
gas_used: 0.into(),
};
// check state proof using given engine.
let number = old_header.number();
let addresses = self.provider.get_validators(move |a, d| {
let from = Address::default();
let tx = Transaction {
nonce: engine.account_start_nonce(number),
action: Action::Call(a),
gas: PROVIDED_GAS.into(),
gas_price: U256::default(),
value: U256::default(),
data: d,
}.fake_sign(from);
let res = ::state::check_proof(
&state_items,
*old_header.state_root(),
&tx,
engine,
&env_info,
);
match res {
::state::ProvedExecution::BadProof => Err("Bad proof".into()),
::state::ProvedExecution::Failed(e) => Err(format!("Failed call: {}", e)),
::state::ProvedExecution::Complete(e) => Ok(e.output),
}
}).wait().map_err(::engines::EngineError::InsufficientProof)?;
trace!(target: "engine", "extracted epoch set at #{}: {} addresses", trace!(target: "engine", "extracted epoch set at #{}: {} addresses",
number, addresses.len()); number, addresses.len());
@ -451,7 +418,7 @@ impl ValidatorSet for ValidatorSafeContract {
})) }))
} }
fn register_client(&self, client: Weak<EngineClient>) { fn register_contract(&self, client: Weak<Client>) {
trace!(target: "engine", "Setting up contract caller."); trace!(target: "engine", "Setting up contract caller.");
*self.client.write() = Some(client); *self.client.write() = Some(client);
} }
@ -467,7 +434,7 @@ mod tests {
use spec::Spec; use spec::Spec;
use account_provider::AccountProvider; use account_provider::AccountProvider;
use transaction::{Transaction, Action}; use transaction::{Transaction, Action};
use client::BlockChainClient; use client::{BlockChainClient, EngineClient};
use ethkey::Secret; use ethkey::Secret;
use miner::MinerService; use miner::MinerService;
use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data};
@ -478,7 +445,7 @@ mod tests {
fn fetches_validators() { fn fetches_validators() {
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
let vc = Arc::new(ValidatorSafeContract::new("0000000000000000000000000000000000000005".parse::<Address>().unwrap())); let vc = Arc::new(ValidatorSafeContract::new("0000000000000000000000000000000000000005".parse::<Address>().unwrap()));
vc.register_client(Arc::downgrade(&client) as _); vc.register_contract(Arc::downgrade(&client));
let last_hash = client.best_block_header().hash(); let last_hash = client.best_block_header().hash();
assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap())); assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap()));
assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap())); assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap()));
@ -492,7 +459,7 @@ mod tests {
let v1 = tap.insert_account(keccak("0").into(), "").unwrap(); let v1 = tap.insert_account(keccak("0").into(), "").unwrap();
let chain_id = Spec::new_validator_safe_contract().chain_id(); let chain_id = Spec::new_validator_safe_contract().chain_id();
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap)); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap));
client.engine().register_client(Arc::downgrade(&client) as _); client.engine().register_client(Arc::downgrade(&client));
let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap(); let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap();
client.miner().set_engine_signer(v1, "".into()).unwrap(); client.miner().set_engine_signer(v1, "".into()).unwrap();
@ -506,7 +473,7 @@ mod tests {
data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
}.sign(&s0, Some(chain_id)); }.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 1); assert_eq!(client.chain_info().best_block_number, 1);
// Add "1" validator back in. // Add "1" validator back in.
let tx = Transaction { let tx = Transaction {
@ -518,13 +485,13 @@ mod tests {
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
}.sign(&s0, Some(chain_id)); }.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
// The transaction is not yet included so still unable to seal. // The transaction is not yet included so still unable to seal.
assert_eq!(client.chain_info().best_block_number, 1); assert_eq!(client.chain_info().best_block_number, 1);
// Switch to the validator that is still there. // Switch to the validator that is still there.
client.miner().set_engine_signer(v0, "".into()).unwrap(); client.miner().set_engine_signer(v0, "".into()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 2); assert_eq!(client.chain_info().best_block_number, 2);
// Switch back to the added validator, since the state is updated. // Switch back to the added validator, since the state is updated.
client.miner().set_engine_signer(v1, "".into()).unwrap(); client.miner().set_engine_signer(v1, "".into()).unwrap();
@ -537,13 +504,13 @@ mod tests {
data: Vec::new(), data: Vec::new(),
}.sign(&s0, Some(chain_id)); }.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
::client::EngineClient::update_sealing(&*client); client.update_sealing();
// Able to seal again. // Able to seal again.
assert_eq!(client.chain_info().best_block_number, 3); assert_eq!(client.chain_info().best_block_number, 3);
// Check syncing. // Check syncing.
let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_safe_contract, 0, 0, &[]); let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_safe_contract, 0, 0, &[]);
sync_client.engine().register_client(Arc::downgrade(&sync_client) as _); sync_client.engine().register_client(Arc::downgrade(&sync_client));
for i in 1..4 { for i in 1..4 {
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap(); sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
} }

View File

@ -77,6 +77,8 @@ pub struct TransactOptions<T, V> {
pub vm_tracer: V, pub vm_tracer: V,
/// Check transaction nonce before execution. /// Check transaction nonce before execution.
pub check_nonce: bool, pub check_nonce: bool,
/// Records the output from init contract calls.
pub output_from_init_contract: bool,
} }
impl<T, V> TransactOptions<T, V> { impl<T, V> TransactOptions<T, V> {
@ -86,6 +88,7 @@ impl<T, V> TransactOptions<T, V> {
tracer, tracer,
vm_tracer, vm_tracer,
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
@ -94,6 +97,12 @@ impl<T, V> TransactOptions<T, V> {
self.check_nonce = false; self.check_nonce = false;
self self
} }
/// Saves the output from contract creation.
pub fn save_output_from_contract(mut self) -> Self {
self.output_from_init_contract = true;
self
}
} }
impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> { impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> {
@ -103,6 +112,7 @@ impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> {
tracer: trace::ExecutiveTracer::default(), tracer: trace::ExecutiveTracer::default(),
vm_tracer: trace::ExecutiveVMTracer::toplevel(), vm_tracer: trace::ExecutiveVMTracer::toplevel(),
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
} }
@ -114,6 +124,7 @@ impl TransactOptions<trace::ExecutiveTracer, trace::NoopVMTracer> {
tracer: trace::ExecutiveTracer::default(), tracer: trace::ExecutiveTracer::default(),
vm_tracer: trace::NoopVMTracer, vm_tracer: trace::NoopVMTracer,
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
} }
@ -125,6 +136,7 @@ impl TransactOptions<trace::NoopTracer, trace::ExecutiveVMTracer> {
tracer: trace::NoopTracer, tracer: trace::NoopTracer,
vm_tracer: trace::ExecutiveVMTracer::toplevel(), vm_tracer: trace::ExecutiveVMTracer::toplevel(),
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
} }
@ -136,6 +148,7 @@ impl TransactOptions<trace::NoopTracer, trace::NoopVMTracer> {
tracer: trace::NoopTracer, tracer: trace::NoopTracer,
vm_tracer: trace::NoopVMTracer, vm_tracer: trace::NoopVMTracer,
check_nonce: true, check_nonce: true,
output_from_init_contract: false,
} }
} }
} }
@ -204,7 +217,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
pub fn transact<T, V>(&'a mut self, t: &SignedTransaction, options: TransactOptions<T, V>) pub fn transact<T, V>(&'a mut self, t: &SignedTransaction, options: TransactOptions<T, V>)
-> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer, -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer,
{ {
self.transact_with_tracer(t, options.check_nonce, options.tracer, options.vm_tracer) self.transact_with_tracer(t, options.check_nonce, options.output_from_init_contract, options.tracer, options.vm_tracer)
} }
/// Execute a transaction in a "virtual" context. /// Execute a transaction in a "virtual" context.
@ -229,6 +242,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
&'a mut self, &'a mut self,
t: &SignedTransaction, t: &SignedTransaction,
check_nonce: bool, check_nonce: bool,
output_from_create: bool,
mut tracer: T, mut tracer: T,
mut vm_tracer: V mut vm_tracer: V
) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer { ) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer {
@ -297,7 +311,8 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
data: None, data: None,
call_type: CallType::None, call_type: CallType::None,
}; };
(self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![]) let mut out = if output_from_create { Some(vec![]) } else { None };
(self.create(params, &mut substate, &mut out, &mut tracer, &mut vm_tracer), out.unwrap_or_else(Vec::new))
}, },
Action::Call(ref address) => { Action::Call(ref address) => {
let params = ActionParams { let params = ActionParams {
@ -490,6 +505,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
&mut self, &mut self,
params: ActionParams, params: ActionParams,
substate: &mut Substate, substate: &mut Substate,
output: &mut Option<Bytes>,
tracer: &mut T, tracer: &mut T,
vm_tracer: &mut V, vm_tracer: &mut V,
) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { ) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
@ -531,7 +547,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed")); let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed"));
let res = { let res = {
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer) self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), &mut subtracer, &mut subvmtracer)
}; };
vm_tracer.done_subtrace(subvmtracer); vm_tracer.done_subtrace(subvmtracer);
@ -540,7 +556,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
Ok(ref res) => tracer.trace_create( Ok(ref res) => tracer.trace_create(
trace_info, trace_info,
gas - res.gas_left, gas - res.gas_left,
trace_output, trace_output.map(|data| output.as_ref().map(|out| out.to_vec()).unwrap_or(data)),
created, created,
subtracer.drain() subtracer.drain()
), ),
@ -701,7 +717,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(79_975)); assert_eq!(gas_left, U256::from(79_975));
@ -759,7 +775,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(62_976)); assert_eq!(gas_left, U256::from(62_976));
@ -926,7 +942,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap() ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(96_776)); assert_eq!(gas_left, U256::from(96_776));
@ -1011,7 +1027,7 @@ mod tests {
let (gas_left, _) = { let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
assert_eq!(gas_left, U256::from(62_976)); assert_eq!(gas_left, U256::from(62_976));
@ -1062,7 +1078,7 @@ mod tests {
{ {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap(); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap();
} }
assert_eq!(substate.contracts_created.len(), 1); assert_eq!(substate.contracts_created.len(), 1);
@ -1335,7 +1351,7 @@ mod tests {
let result = { let result = {
let mut ex = Executive::new(&mut state, &info, &engine); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer)
}; };
match result { match result {

View File

@ -224,7 +224,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag); let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);
// TODO: handle internal error separately // TODO: handle internal error separately
match ex.create(params, self.substate, self.tracer, self.vm_tracer) { match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) {
Ok((gas_left, _)) => { Ok((gas_left, _)) => {
self.substate.contracts_created.push(address.clone()); self.substate.contracts_created.push(address.clone());
ContractCreateResult::Created(address, gas_left) ContractCreateResult::Created(address, gas_left)

View File

@ -261,13 +261,8 @@ impl Header {
s.out() s.out()
} }
/// Get the SHA3 (Keccak) of this header, optionally `with_seal`. /// Get the KECCAK (Keccak) of this header, optionally `with_seal`.
pub fn rlp_keccak(&self, with_seal: Seal) -> H256 { keccak(self.rlp(with_seal)) } pub fn rlp_keccak(&self, with_seal: Seal) -> H256 { keccak(self.rlp(with_seal)) }
/// Encode the header, getting a type-safe wrapper around the RLP.
pub fn encoded(&self) -> ::encoded::Header {
::encoded::Header::new(self.rlp(Seal::With))
}
} }
impl Decodable for Header { impl Decodable for Header {

View File

@ -116,7 +116,7 @@ impl ClientService {
}); });
io_service.register_handler(client_io)?; io_service.register_handler(client_io)?;
spec.engine.register_client(Arc::downgrade(&client) as _); spec.engine.register_client(Arc::downgrade(&client));
let stop_guard = ::devtools::StopGuard::new(); let stop_guard = ::devtools::StopGuard::new();
run_ipc(ipc_path, client.clone(), snapshot.clone(), stop_guard.share()); run_ipc(ipc_path, client.clone(), snapshot.clone(), stop_guard.share());

View File

@ -93,7 +93,7 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
let mut cur_signers = vec![*RICH_ADDR]; let mut cur_signers = vec![*RICH_ADDR];
{ {
let engine = client.engine(); let engine = client.engine();
engine.register_client(Arc::downgrade(&client) as _); engine.register_client(Arc::downgrade(&client));
} }
{ {

View File

@ -36,6 +36,7 @@ use factory::Factories;
use header::{BlockNumber, Header}; use header::{BlockNumber, Header};
use pod_state::*; use pod_state::*;
use rlp::{Rlp, RlpStream}; use rlp::{Rlp, RlpStream};
use state_db::StateDB;
use state::{Backend, State, Substate}; use state::{Backend, State, Substate};
use state::backend::Basic as BasicBackend; use state::backend::Basic as BasicBackend;
use trace::{NoopTracer, NoopVMTracer}; use trace::{NoopTracer, NoopVMTracer};
@ -355,7 +356,7 @@ impl Spec {
{ {
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref()); let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref());
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) { if let Err(e) = exec.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) {
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e); warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
} }
} }
@ -464,7 +465,7 @@ impl Spec {
} }
/// Ensure that the given state DB has the trie nodes in for the genesis state. /// Ensure that the given state DB has the trie nodes in for the genesis state.
pub fn ensure_db_good<T: Backend>(&self, db: T, factories: &Factories) -> Result<T, Error> { pub fn ensure_db_good(&self, db: StateDB, factories: &Factories) -> Result<StateDB, Error> {
if db.as_hashdb().contains(&self.state_root()) { if db.as_hashdb().contains(&self.state_root()) {
return Ok(db) return Ok(db)
} }
@ -486,63 +487,6 @@ impl Spec {
.and_then(|x| load_from(cache_dir, x).map_err(fmt)) .and_then(|x| load_from(cache_dir, x).map_err(fmt))
} }
/// initialize genesis epoch data, using in-memory database for
/// constructor.
pub fn genesis_epoch_data(&self) -> Result<Vec<u8>, String> {
use transaction::{Action, Transaction};
use util::{journaldb, kvdb};
let genesis = self.genesis_header();
let factories = Default::default();
let mut db = journaldb::new(
Arc::new(kvdb::in_memory(0)),
journaldb::Algorithm::Archive,
None,
);
self.ensure_db_good(BasicBackend(db.as_hashdb_mut()), &factories)
.map_err(|e| format!("Unable to initialize genesis state: {}", e))?;
let call = |a, d| {
let mut db = db.boxed_clone();
let env_info = ::evm::EnvInfo {
number: 0,
author: *genesis.author(),
timestamp: genesis.timestamp(),
difficulty: *genesis.difficulty(),
gas_limit: *genesis.gas_limit(),
last_hashes: Arc::new(Vec::new()),
gas_used: 0.into()
};
let from = Address::default();
let tx = Transaction {
nonce: self.engine.account_start_nonce(0),
action: Action::Call(a),
gas: U256::from(50_000_000), // TODO: share with client.
gas_price: U256::default(),
value: U256::default(),
data: d,
}.fake_sign(from);
let res = ::state::prove_transaction(
db.as_hashdb_mut(),
*genesis.state_root(),
&tx,
&*self.engine,
&env_info,
factories.clone(),
true,
);
res.map(|(out, proof)| (out, proof.into_iter().map(|x| x.into_vec()).collect()))
.ok_or_else(|| "Failed to prove call: insufficient state".into())
};
self.engine.genesis_epoch_data(&genesis, &call)
}
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus. /// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus.
pub fn new_test() -> Spec { load_bundled!("null_morden") } pub fn new_test() -> Spec { load_bundled!("null_morden") }

View File

@ -212,7 +212,8 @@ pub fn check_proof(
Err(_) => return ProvedExecution::BadProof, Err(_) => return ProvedExecution::BadProof,
}; };
match state.execute(env_info, engine, transaction, TransactOptions::with_no_tracing(), true) { let options = TransactOptions::with_no_tracing().save_output_from_contract();
match state.execute(env_info, engine, transaction, options, true) {
Ok(executed) => ProvedExecution::Complete(executed), Ok(executed) => ProvedExecution::Complete(executed),
Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof, Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof,
Err(e) => ProvedExecution::Failed(e), Err(e) => ProvedExecution::Failed(e),
@ -246,7 +247,7 @@ pub fn prove_transaction<H: AsHashDB + Send + Sync>(
Err(_) => return None, Err(_) => return None,
}; };
let options = TransactOptions::with_no_tracing().dont_check_nonce(); let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract();
match state.execute(env_info, engine, transaction, options, virt) { match state.execute(env_info, engine, transaction, options, virt) {
Err(ExecutionError::Internal(_)) => None, Err(ExecutionError::Internal(_)) => None,
Err(e) => { Err(e) => {

View File

@ -21,7 +21,8 @@ use std::collections::HashMap;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use native_contracts::TransactAcl as Contract; use native_contracts::TransactAcl as Contract;
use client::{BlockChainClient, BlockId, ChainNotify}; use client::{BlockChainClient, BlockId, ChainNotify};
use util::{Address, H256, Bytes}; use util::{Address, Bytes};
use bigint::hash::H256;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use futures::{self, Future}; use futures::{self, Future};
use spec::CommonParams; use spec::CommonParams;

2
js/package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "parity.js", "name": "parity.js",
"version": "1.8.18", "version": "1.8.19",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "parity.js", "name": "parity.js",
"version": "1.8.18", "version": "1.8.19",
"main": "release/index.js", "main": "release/index.js",
"jsnext:main": "src/index.js", "jsnext:main": "src/index.js",
"author": "Parity Team <admin@parity.io>", "author": "Parity Team <admin@parity.io>",

View File

@ -20,34 +20,57 @@ import * as defaults from '../src/i18n/_default';
import { LANGUAGES, MESSAGES } from '../src/i18n/store'; import { LANGUAGES, MESSAGES } from '../src/i18n/store';
const SKIP_LANG = ['en']; const SKIP_LANG = ['en'];
const defaultKeys = Object.keys(flatten(Object.assign({}, defaults, LANGUAGES))); const defaultValues = flatten(Object.assign({}, defaults, LANGUAGES));
const defaultKeys = Object.keys(defaultValues);
const results = {};
Object Object
.keys(MESSAGES) .keys(MESSAGES)
.filter((lang) => !SKIP_LANG.includes(lang)) .filter((lang) => !SKIP_LANG.includes(lang))
.forEach((lang) => { .forEach((lang) => {
const messageKeys = Object.keys(MESSAGES[lang]); const messageKeys = Object.keys(MESSAGES[lang]);
let extra = 0; const langResults = { found: [], missing: [], extras: [] };
let found = 0;
let missing = 0;
console.log(`*** Checking translations for ${lang}`); console.warn(`*** Checking translations for ${lang}`);
defaultKeys.forEach((key) => { defaultKeys.forEach((key) => {
if (messageKeys.includes(key)) { if (messageKeys.includes(key)) {
found++; langResults.found.push(key);
} else { } else {
missing++; langResults.missing.push(key);
console.log(` Missing ${key}`);
} }
}); });
messageKeys.forEach((key) => { messageKeys.forEach((key) => {
if (!defaultKeys.includes(key)) { if (!defaultKeys.includes(key)) {
extra++; langResults.extras.push(key);
console.log(` Extra ${key}`);
} }
}); });
console.log(`Found ${found} keys, missing ${missing} keys, ${extra} extraneous keys\n`); // Sort keys
langResults.extras.sort((kA, kB) => kA.localeCompare(kB));
langResults.found.sort((kA, kB) => kA.localeCompare(kB));
langResults.missing.sort((kA, kB) => kA.localeCompare(kB));
// Print to stderr the missing and extra keys
langResults.missing.forEach((key) => console.warn(` Missing ${key}`));
langResults.extras.forEach((key) => console.warn(` Extra ${key}`));
results[lang] = langResults;
console.warn(`Found ${langResults.found.length} keys, missing ${langResults.missing.length} keys, ${langResults.extras.length} extraneous keys\n`);
}); });
const formattedResults = Object.keys(results)
.reduce((res, lang) => {
const { missing } = results[lang];
res[lang] = missing.map((key) => ({
key,
default: defaultValues[key]
}));
return res;
}, {});
process.stdout.write(JSON.stringify(formattedResults, null, 2) + '\n');

View File

@ -18,12 +18,29 @@ export default {
button: { button: {
delete: `delete`, delete: `delete`,
edit: `edit`, edit: `edit`,
export: `export`,
faucet: `Kovan ETH`, faucet: `Kovan ETH`,
forget: `forget`,
password: `password`, password: `password`,
shapeshift: `shapeshift`, shapeshift: `shapeshift`,
transfer: `transfer`, transfer: `transfer`,
verify: `verify` verify: `verify`
}, },
export: {
info: `Export your account as a JSON file. Please enter the password linked with this account.`,
password: {
hint: `The password specified when creating this account`,
label: `Account password`
},
setPassword: {
hint: `Enter password Here`,
label: `Password`
},
title: `Export Account`
},
external: {
confirmDelete: `Are you sure you want to remove the following external address from your account list?`
},
hardware: { hardware: {
confirmDelete: `Are you sure you want to remove the following hardware address from your account list?` confirmDelete: `Are you sure you want to remove the following hardware address from your account list?`
}, },

View File

@ -16,10 +16,19 @@
export default { export default {
button: { button: {
export: `export`,
newAccount: `account`, newAccount: `account`,
newWallet: `wallet`, newWallet: `wallet`,
restoreAccount: `restore`,
vaults: `vaults` vaults: `vaults`
}, },
export: {
button: {
cancel: `Cancel`,
export: `Export`
},
title: `Export an Account`
},
summary: { summary: {
minedBlock: `Mined at block #{blockNumber}` minedBlock: `Mined at block #{blockNumber}`
}, },

View File

@ -22,8 +22,7 @@ export default {
consensus: { consensus: {
capable: `Upgrade not required.`, capable: `Upgrade not required.`,
capableUntil: `Upgrade required before #{blockNumber}`, capableUntil: `Upgrade required before #{blockNumber}`,
incapableSince: `Upgrade required since #{blockNumber}`, incapableSince: `Upgrade required since #{blockNumber}`
unknown: `Upgrade status is unknown.`
}, },
upgrade: `Upgrade` upgrade: `Upgrade`
} }

View File

@ -19,6 +19,7 @@ export default {
connectingNode: `Connecting to the Parity Node. If this informational message persists, please ensure that your Parity node is running and reachable on the network.`, connectingNode: `Connecting to the Parity Node. If this informational message persists, please ensure that your Parity node is running and reachable on the network.`,
invalidToken: `invalid signer token`, invalidToken: `invalid signer token`,
noConnection: `Unable to make a connection to the Parity Secure API. To update your secure token or to generate a new one, run {newToken} and paste the generated token into the space below.`, noConnection: `Unable to make a connection to the Parity Secure API. To update your secure token or to generate a new one, run {newToken} and paste the generated token into the space below.`,
timestamp: `Ensure that both the Parity node and this machine connecting have computer clocks in-sync with each other and with a timestamp server, ensuring both successful token validation and block operations.`,
token: { token: {
hint: `a generated token from Parity`, hint: `a generated token from Parity`,
label: `secure token` label: `secure token`

View File

@ -21,8 +21,11 @@ export default {
label: `address` label: `address`
}, },
phrase: { phrase: {
backedUp: `Type "I have written down the phrase" below to confirm it is backed up.`,
backup: `Please back up the recovery phrase now. Make sure to keep it private and secure, it allows full and unlimited access to the account.`,
backupConfirm: `Type your recovery phrase now.`,
hint: `the account recovery phrase`, hint: `the account recovery phrase`,
label: `owner recovery phrase (keep private and secure, it allows full and unlimited access to the account)` label: `owner recovery phrase`
} }
}, },
accountDetailsGeth: { accountDetailsGeth: {
@ -50,14 +53,14 @@ export default {
description: `Selecting your identity icon and specifying the password`, description: `Selecting your identity icon and specifying the password`,
label: `New Account` label: `New Account`
}, },
fromPhrase: {
description: `Recover using a previously stored recovery phrase and new password`,
label: `Recovery phrase`
},
fromPresale: { fromPresale: {
description: `Import an Ethereum presale wallet file with the original password`, description: `Import an Ethereum presale wallet file with the original password`,
label: `Presale wallet` label: `Presale wallet`
}, },
fromQr: {
description: `Attach an externally managed account via QR code`,
label: `External Account`
},
fromRaw: { fromRaw: {
description: `Enter a previously created raw private key with a new password`, description: `Enter a previously created raw private key with a new password`,
label: `Private key` label: `Private key`
@ -104,6 +107,21 @@ export default {
label: `password` label: `password`
} }
}, },
newQr: {
address: {
hint: `the network address for the account`,
label: `address`
},
description: {
hint: `a description for the account`,
label: `account description`
},
name: {
hint: `a descriptive name for the account`,
label: `account name`
},
summary: `Use the built-in machine camera to scan to QR code of the account you wish to attach as an external account. External accounts are signed on the external device.`
},
rawKey: { rawKey: {
hint: { hint: {
hint: `(optional) a hint to help with remembering the password`, hint: `(optional) a hint to help with remembering the password`,
@ -135,6 +153,9 @@ export default {
hint: `a descriptive name for the account`, hint: `a descriptive name for the account`,
label: `account name` label: `account name`
}, },
passPhrase: {
error: `enter a recovery phrase`
},
password: { password: {
hint: `a strong, unique password`, hint: `a strong, unique password`,
label: `password` label: `password`
@ -147,14 +168,27 @@ export default {
hint: `the account recovery phrase`, hint: `the account recovery phrase`,
label: `account recovery phrase` label: `account recovery phrase`
}, },
warning: {
emptyPhrase: `The recovery phrase is empty.
This account can be recovered by anyone.`,
shortPhrase: `The recovery phrase is less than 11 words.
This account has not been generated by Parity and might be insecure.
Proceed with caution.`,
testnetEmptyPhrase: `The recovery phrase is empty.
This account can be recovered by anyone.
Proceed with caution.`
},
windowsKey: { windowsKey: {
label: `Key was created with Parity <1.4.5 on Windows` label: `Key was created with Parity <1.4.5 on Windows`
} }
}, },
title: { title: {
accountInfo: `account information`, accountInfo: `account information`,
backupPhrase: `confirm recovery phrase`,
createAccount: `create account`, createAccount: `create account`,
createType: `creation type`, createType: `creation type`,
importWallet: `import wallet` importAccount: `import account`,
qr: `external account`,
restoreAccount: `restore account`
} }
}; };

View File

@ -18,14 +18,9 @@ export default {
button: { button: {
add: `Add`, add: `Add`,
cancel: `Cancel`, cancel: `Cancel`,
close: `Close`,
create: `Create`, create: `Create`,
done: `Done`, done: `Done`,
next: `Next`, next: `Next`
sending: `Sending...`
},
deployment: {
message: `The deployment is currently in progress`
}, },
details: { details: {
address: { address: {
@ -73,21 +68,7 @@ export default {
numOwners: `{numOwners} owners are required to confirm a transaction.`, numOwners: `{numOwners} owners are required to confirm a transaction.`,
owners: `The following are wallet owners` owners: `The following are wallet owners`
}, },
rejected: {
message: `The deployment has been rejected`,
state: `The wallet will not be created. You can safely close this window.`,
title: `rejected`
},
states: {
completed: `The contract deployment has been completed`,
confirmationNeeded: `The contract deployment needs confirmations from other owners of the Wallet`,
preparing: `Preparing transaction for network transmission`,
validatingCode: `Validating the deployed contract code`,
waitingConfirm: `Waiting for confirmation of the transaction in the Parity Secure Signer`,
waitingReceipt: `Waiting for the contract deployment transaction receipt`
},
steps: { steps: {
deployment: `wallet deployment`,
details: `wallet details`, details: `wallet details`,
info: `wallet informaton`, info: `wallet informaton`,
type: `wallet type` type: `wallet type`

View File

@ -31,6 +31,9 @@ export default {
} }
}, },
button: { button: {
dapp: {
refresh: `refresh`
},
edit: `edit`, edit: `edit`,
permissions: `permissions` permissions: `permissions`
}, },

View File

@ -15,19 +15,12 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default { export default {
busy: {
title: `The deployment is currently in progress`
},
button: { button: {
cancel: `Cancel`, cancel: `Cancel`,
close: `Close`, close: `Close`,
create: `Create`, create: `Create`,
done: `Done`,
next: `Next` next: `Next`
}, },
completed: {
description: `Your contract has been deployed at`
},
details: { details: {
abi: { abi: {
hint: `the abi of the contract to deploy or solc combined-output`, hint: `the abi of the contract to deploy or solc combined-output`,
@ -66,25 +59,9 @@ export default {
parameters: { parameters: {
choose: `Choose the contract parameters` choose: `Choose the contract parameters`
}, },
rejected: {
description: `You can safely close this window, the contract deployment will not occur.`,
title: `The deployment has been rejected`
},
state: {
completed: `The contract deployment has been completed`,
confirmationNeeded: `The operation needs confirmations from the other owners of the contract`,
preparing: `Preparing transaction for network transmission`,
validatingCode: `Validating the deployed contract code`,
waitReceipt: `Waiting for the contract deployment transaction receipt`,
waitSigner: `Waiting for confirmation of the transaction in the Parity Secure Signer`
},
title: { title: {
completed: `completed`,
deployment: `deployment`,
details: `contract details`, details: `contract details`,
extras: `extra information`, extras: `extra information`,
failed: `deployment failed`, parameters: `contract parameters`
parameters: `contract parameters`,
rejected: `rejected`
} }
}; };

View File

@ -19,6 +19,8 @@ export default {
invalidKey: `the raw key needs to be hex, 64 characters in length and contain the prefix "0x"`, invalidKey: `the raw key needs to be hex, 64 characters in length and contain the prefix "0x"`,
noFile: `select a valid wallet file to import`, noFile: `select a valid wallet file to import`,
noKey: `you need to provide the raw private key`, noKey: `you need to provide the raw private key`,
noMatchBackupPhrase: `the supplied recovery phrase does not match`,
noMatchPassword: `the supplied passwords does not match`, noMatchPassword: `the supplied passwords does not match`,
noMatchPhraseBackedUp: `type "I have written down the phrase"`,
noName: `you need to specify a valid name` noName: `you need to specify a valid name`
}; };

View File

@ -15,14 +15,8 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default { export default {
busy: {
posted: `Your transaction has been posted to the network`,
title: `The function execution is in progress`,
waitAuth: `Waiting for authorization in the Parity Signer`
},
button: { button: {
cancel: `cancel`, cancel: `cancel`,
done: `done`,
next: `next`, next: `next`,
post: `post transaction`, post: `post transaction`,
prev: `prev` prev: `prev`
@ -44,15 +38,8 @@ export default {
label: `function to execute` label: `function to execute`
} }
}, },
rejected: {
state: `You can safely close this window, the function execution will not occur.`,
title: `The execution has been rejected`
},
steps: { steps: {
advanced: `advanced options`, advanced: `advanced options`,
complete: `complete`,
rejected: `rejected`,
sending: `sending`,
transfer: `function details` transfer: `function details`
} }
}; };

View File

@ -20,6 +20,7 @@ export default {
create: `Create`, create: `Create`,
next: `Next`, next: `Next`,
print: `Print Phrase`, print: `Print Phrase`,
restart: `Start Over`,
skip: `Skip` skip: `Skip`
}, },
completed: { completed: {
@ -28,6 +29,7 @@ export default {
}, },
title: { title: {
completed: `completed`, completed: `completed`,
confirmation: `confirmation`,
newAccount: `new account`, newAccount: `new account`,
recovery: `recovery`, recovery: `recovery`,
terms: `terms`, terms: `terms`,

View File

@ -41,11 +41,14 @@ export home from './home';
export loadContract from './loadContract'; export loadContract from './loadContract';
export parityBar from './parityBar'; export parityBar from './parityBar';
export passwordChange from './passwordChange'; export passwordChange from './passwordChange';
export peers from './peers';
export requests from './requests';
export saveContract from './saveContract'; export saveContract from './saveContract';
export settings from './settings'; export settings from './settings';
export shapeshift from './shapeshift'; export shapeshift from './shapeshift';
export signer from './signer'; export signer from './signer';
export status from './status'; export status from './status';
export syncWarning from './syncWarning';
export tabBar from './tabBar'; export tabBar from './tabBar';
export transfer from './transfer'; export transfer from './transfer';
export txEditor from './txEditor'; export txEditor from './txEditor';

View File

@ -0,0 +1,46 @@
// 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 <http://www.gnu.org/licenses/>.
export default {
acceptNonReserved: {
label: `Accept non-reserved`
},
acceptNonReservedPeers: {
success: `Accepting non-reserved peers`
},
addReserved: {
label: `Add reserved`
},
dropNonReserved: {
label: `Drop non-reserved`
},
dropNonReservedPeers: {
success: `Dropping non-reserved peers`
},
form: {
action: {
label: `{add, select, true {Add} false {}}{remove, select, true {Remove} false {}}`,
success: `Successfully {add, select, true {added} false {}}{remove, select, true {removed} false {}} a reserved peer`
},
cancel: {
label: `Cancel`
},
label: `Peer enode URL`
},
removeReserved: {
label: `Remove reserved`
}
};

View File

@ -0,0 +1,24 @@
// 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 <http://www.gnu.org/licenses/>.
export default {
status: {
error: `An error occured:`,
transactionMined: `Transaction mined at block #{blockNumber} ({blockHeight} blocks ago)`,
transactionSent: `Transaction sent to network with hash`,
waitingForSigner: `Waiting for authorization in the Parity Signer`
}
};

View File

@ -36,7 +36,7 @@ export default {
}, },
languages: { languages: {
hint: `the language this interface is displayed with`, hint: `the language this interface is displayed with`,
label: `UI language` label: `language`
}, },
loglevels: `Choose the different logs level.`, loglevels: `Choose the different logs level.`,
modes: { modes: {
@ -51,7 +51,7 @@ export default {
label: `parity` label: `parity`
}, },
proxy: { proxy: {
details_0: `Instead of accessing Parity via the IP address and port, you will be able to access it via the .parity subdomain, by visiting {homeProxy}. To setup subdomain-based routing, you need to add the relevant proxy entries to your browser,`, details_0: `Instead of accessing Parity via the IP address and port, you will be able to access it via the .web3.site subdomain, by visiting {homeProxy}. To setup subdomain-based routing, you need to add the relevant proxy entries to your browser,`,
details_1: `To learn how to configure the proxy, instructions are provided for {windowsLink}, {macOSLink} or {ubuntuLink}.`, details_1: `To learn how to configure the proxy, instructions are provided for {windowsLink}, {macOSLink} or {ubuntuLink}.`,
details_macos: `macOS`, details_macos: `macOS`,
details_ubuntu: `Ubuntu`, details_ubuntu: `Ubuntu`,
@ -88,13 +88,12 @@ export default {
description: `The secure transaction management area of the application where you can approve any outgoing transactions made from the application as well as those placed into the queue by decentralized applications.`, description: `The secure transaction management area of the application where you can approve any outgoing transactions made from the application as well as those placed into the queue by decentralized applications.`,
label: `Signer` label: `Signer`
}, },
status: {
description: `See how the Parity node is performing in terms of connections to the network, logs from the actual running instance and details of mining (if enabled and configured).`,
label: `Status`
},
label: `views`, label: `views`,
home: { home: {
label: `Home` label: `Home`
},
status: {
label: `Status`
} }
}, },
label: `settings` label: `settings`

View File

@ -15,6 +15,13 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default { export default {
decryptRequest: {
request: `A request to decrypt data using your account:`,
state: {
confirmed: `Confirmed`,
rejected: `Rejected`
}
},
embedded: { embedded: {
noPending: `There are currently no pending requests awaiting your confirmation` noPending: `There are currently no pending requests awaiting your confirmation`
}, },
@ -29,7 +36,7 @@ export default {
requestOrigin: { requestOrigin: {
dapp: `by a dapp at {url}`, dapp: `by a dapp at {url}`,
ipc: `via IPC session`, ipc: `via IPC session`,
rpc: `via RPC {rpc}`, rpc: `via RPC {url}`,
signerCurrent: `via current tab`, signerCurrent: `via current tab`,
signerUI: `via UI session`, signerUI: `via UI session`,
unknownInterface: `via unknown interface`, unknownInterface: `via unknown interface`,
@ -38,10 +45,14 @@ export default {
}, },
requestsPage: { requestsPage: {
noPending: `There are no requests requiring your confirmation.`, noPending: `There are no requests requiring your confirmation.`,
pendingTitle: `Pending Requests`, pendingTitle: `Pending Signature Authorization`,
queueTitle: `Local Transactions` queueTitle: `Local Transactions`
}, },
sending: { sending: {
external: {
scanSigned: `Scan the QR code of the signed transaction from your external device`,
scanTx: `Please scan the transaction QR on your external device`
},
hardware: { hardware: {
confirm: `Please confirm the transaction on your attached hardware device`, confirm: `Please confirm the transaction on your attached hardware device`,
connect: `Please attach your hardware device before confirming the transaction` connect: `Please attach your hardware device before confirming the transaction`
@ -53,6 +64,10 @@ export default {
confirmed: `Confirmed`, confirmed: `Confirmed`,
rejected: `Rejected` rejected: `Rejected`
}, },
tooltip: {
data: `Data: {data}`,
hash: `Hash to be signed: {hashToSign}`
},
unknownBinary: `(Unknown binary data)`, unknownBinary: `(Unknown binary data)`,
warning: `WARNING: This consequences of doing this may be grave. Confirm the request only if you are sure.` warning: `WARNING: This consequences of doing this may be grave. Confirm the request only if you are sure.`
}, },
@ -65,7 +80,8 @@ export default {
txPendingConfirm: { txPendingConfirm: {
buttons: { buttons: {
confirmBusy: `Confirming...`, confirmBusy: `Confirming...`,
confirmRequest: `Confirm Request` confirmRequest: `Confirm Request`,
scanSigned: `Scan Signed QR`
}, },
errors: { errors: {
invalidWallet: `Given wallet file is invalid.` invalidWallet: `Given wallet file is invalid.`

View File

@ -20,6 +20,14 @@ export default {
stopped: `Refresh and display of logs from Parity is currently stopped via the UI, start it to see the latest updates.`, stopped: `Refresh and display of logs from Parity is currently stopped via the UI, start it to see the latest updates.`,
title: `Node Logs` title: `Node Logs`
}, },
health: {
no: `no`,
peers: `Connected Peers`,
sync: `Chain Synchronized`,
time: `Time Synchronized`,
title: `Node Health`,
yes: `yes`
},
miningSettings: { miningSettings: {
input: { input: {
author: { author: {
@ -41,13 +49,25 @@ export default {
}, },
title: `mining settings` title: `mining settings`
}, },
peers: {
table: {
header: {
caps: `Capabilities`,
ethDiff: `Difficulty (ETH)`,
ethHeader: `Header (ETH)`,
id: `ID`,
name: `Name`,
remoteAddress: `Remote Address`
}
},
title: `network peers`
},
status: { status: {
hashrate: `{hashrate} H/s`, hashrate: `{hashrate} H/s`,
input: { input: {
chain: `chain`, chain: `chain`,
enode: `enode`, enode: `enode`,
no: `no`, no: `no`,
peers: `peers`,
port: `network port`, port: `network port`,
rpcEnabled: `rpc enabled`, rpcEnabled: `rpc enabled`,
rpcInterface: `rpc interface`, rpcInterface: `rpc interface`,

View File

@ -14,4 +14,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default `Windows`; export default {
dontShowAgain: {
label: `Do not show this warning again`
},
understandBtn: {
label: `I understand`
}
};

View File

@ -24,7 +24,6 @@ export default {
buttons: { buttons: {
back: `Back`, back: `Back`,
cancel: `Cancel`, cancel: `Cancel`,
close: `Close`,
next: `Next`, next: `Next`,
send: `Send` send: `Send`
}, },
@ -51,10 +50,6 @@ export default {
label: `total transaction amount` label: `total transaction amount`
} }
}, },
wallet: {
confirmation: `This transaction needs confirmation from other owners.`,
operationHash: `operation hash`
},
warning: { warning: {
wallet_spent_limit: `This transaction value is above the remaining daily limit. It will need to be confirmed by other owners.` wallet_spent_limit: `This transaction value is above the remaining daily limit. It will need to be confirmed by other owners.`
} }

View File

@ -66,6 +66,18 @@ export default {
errors: { errors: {
close: `close` close: `close`
}, },
features: {
defaults: {
i18n: {
desc: `Allows changing the default interface language`,
name: `Language Selection`
},
logging: {
desc: `Allows changing of the log levels for various components`,
name: `Logging Level Selection`
}
}
},
fileSelect: { fileSelect: {
defaultLabel: `Drop a file here, or click to select a file to upload` defaultLabel: `Drop a file here, or click to select a file to upload`
}, },
@ -80,8 +92,8 @@ export default {
}, },
methodDecoding: { methodDecoding: {
condition: { condition: {
block: `, {historic, select, true {Submitted} false {Submission}} at block {blockNumber}`, block: `{historic, select, true {Will be submitted} false {To be submitted}} at block {blockNumber}`,
time: `, {historic, select, true {Submitted} false {Submission}} at {timestamp}` time: `{historic, select, true {Will be submitted} false {To be submitted}} {timestamp}`
}, },
deploy: { deploy: {
address: `Deployed a contract at address`, address: `Deployed a contract at address`,
@ -101,7 +113,7 @@ export default {
info: `{historic, select, true {Received} false {Will receive}} {valueEth} from {aContract}{address}` info: `{historic, select, true {Received} false {Will receive}} {valueEth} from {aContract}{address}`
}, },
signature: { signature: {
info: `{historic, select, true {Executed} false {Will execute}} the {method} function on the contract {address} trsansferring {ethValue}{inputLength, plural, zero {,} other {passing the following {inputLength, plural, one {parameter} other {parameters}}}}` info: `{historic, select, true {Executed} false {Will execute}} the {method} function on the contract {address} {showEth, select, true {transferring {ethValue}} false {}} {showInputs, select, false {} true {passing the following {inputLength, plural, one {parameter} other {parameters}}}}`
}, },
token: { token: {
transfer: `{historic, select, true {Transferred} false {Will transfer}} {value} to {address}` transfer: `{historic, select, true {Transferred} false {Will transfer}} {value} to {address}`
@ -131,6 +143,27 @@ export default {
posted: `The transaction has been posted to the network with a hash of {hashLink}`, posted: `The transaction has been posted to the network with a hash of {hashLink}`,
waiting: `waiting for confirmations` waiting: `waiting for confirmations`
}, },
txList: {
txRow: {
cancel: `Cancel`,
cancelWarning: `Warning: Editing or Canceling the transaction may not succeed!`,
canceled: `Canceled`,
edit: `Edit`,
editing: `Editing`,
pendingStatus: {
blocksLeft: `{blockNumber} blocks left`,
time: `{time} left`
},
scheduled: `Scheduled`,
submitting: `Pending`,
verify: {
cancelEditCancel: `Cancel`,
cancelEditEdit: `Edit`,
confirm: `Are you sure?`,
nevermind: `Nevermind`
}
}
},
vaultSelect: { vaultSelect: {
hint: `the vault this account is attached to`, hint: `the vault this account is attached to`,
label: `associated vault` label: `associated vault`

View File

@ -22,8 +22,12 @@ export default {
cancel: `Cancel`, cancel: `Cancel`,
close: `Close`, close: `Close`,
next: `Next`, next: `Next`,
send: `Send`, send: `Send`
sending: `Sending...` },
changeOwner: {
labelFrom: `From`,
labelTo: `To`,
title: `Change Owner`
}, },
changes: { changes: {
modificationString: `For your modifications to be taken into account, modificationString: `For your modifications to be taken into account,
@ -62,7 +66,6 @@ export default {
details: `from {from} to {to}`, details: `from {from} to {to}`,
title: `Change Required Owners` title: `Change Required Owners`
}, },
rejected: `The transaction #{txid} has been rejected`,
removeOwner: { removeOwner: {
title: `Remove Owner` title: `Remove Owner`
} }

View File

@ -37,7 +37,7 @@ export default {
params: `An error occurred with the following description` params: `An error occurred with the following description`
}, },
input: { input: {
abi: `ABI Interface`, abi: `ABI Definition`,
code: `Bytecode`, code: `Bytecode`,
metadata: `Metadata`, metadata: `Metadata`,
swarm: `Swarm Metadata Hash` swarm: `Swarm Metadata Hash`

View File

@ -33,8 +33,8 @@ import zhHantTWMessages from './zh-Hant-TW';
let instance = null; let instance = null;
const LANGUAGES = flatten({ languages }); export const LANGUAGES = flatten({ languages });
const MESSAGES = { export const MESSAGES = {
de: Object.assign(flatten(deMessages), LANGUAGES), de: Object.assign(flatten(deMessages), LANGUAGES),
en: Object.assign(flatten(enMessages), LANGUAGES), en: Object.assign(flatten(enMessages), LANGUAGES),
nl: Object.assign(flatten(nlMessages), LANGUAGES), nl: Object.assign(flatten(nlMessages), LANGUAGES),
@ -75,8 +75,3 @@ export default class Store {
return instance; return instance;
} }
} }
export {
LANGUAGES,
MESSAGES
};

View File

@ -58,7 +58,7 @@ class ExportAccount extends Component {
key='cancel' key='cancel'
label={ label={
<FormattedMessage <FormattedMessage
id='export.accounts.button.cancel' id='accounts.export.button.cancel'
defaultMessage='Cancel' defaultMessage='Cancel'
/> />
} }
@ -70,7 +70,7 @@ class ExportAccount extends Component {
key='execute' key='execute'
label={ label={
<FormattedMessage <FormattedMessage
id='export.accounts.button.export' id='accounts.export.button.export'
defaultMessage='Export' defaultMessage='Export'
/> />
} }
@ -81,7 +81,7 @@ class ExportAccount extends Component {
open open
title={ title={
<FormattedMessage <FormattedMessage
id='export.accounts.title' id='accounts.export.title'
defaultMessage='Export an Account' defaultMessage='Export an Account'
/> />
} }

View File

@ -34,13 +34,13 @@ export default class ExportInput extends Component {
type='password' type='password'
label={ label={
<FormattedMessage <FormattedMessage
id='export.setPassword.label' id='account.export.setPassword.label'
defaultMessage='Password' defaultMessage='Password'
/> />
} }
hint={ hint={
<FormattedMessage <FormattedMessage
id='export.setPassword.hint' id='account.export.setPassword.hint'
defaultMessage='Enter password Here' defaultMessage='Enter password Here'
/> />
} }

View File

@ -30,17 +30,17 @@ const FEATURES = {
const DEFAULTS = { const DEFAULTS = {
[FEATURES.LANGUAGE]: { [FEATURES.LANGUAGE]: {
mode: MODES.TESTING, mode: MODES.PRODUCTION,
name: ( name: (
<FormattedMessage <FormattedMessage
id='ui.features.defaults.i18n.name' id='ui.features.defaults.i18n.name'
defaultMssage='Language Selection' defaultMessage='Language Selection'
/> />
), ),
description: ( description: (
<FormattedMessage <FormattedMessage
id='ui.features.defaults.i18n.desc' id='ui.features.defaults.i18n.desc'
defaultMssage='Allows changing the default interface language' defaultMessage='Allows changing the default interface language'
/> />
) )
}, },
@ -49,13 +49,13 @@ const DEFAULTS = {
name: ( name: (
<FormattedMessage <FormattedMessage
id='ui.features.defaults.logging.name' id='ui.features.defaults.logging.name'
defaultMssage='Logging Level Selection' defaultMessage='Logging Level Selection'
/> />
), ),
description: ( description: (
<FormattedMessage <FormattedMessage
id='ui.features.defaults.logging.desc' id='ui.features.defaults.logging.desc'
defaultMssage='Allows changing of the log levels for various components' defaultMessage='Allows changing of the log levels for various components'
/> />
) )
} }

View File

@ -45,7 +45,7 @@ export default class LanguageSelector extends Component {
label={ label={
<FormattedMessage <FormattedMessage
id='settings.parity.languages.label' id='settings.parity.languages.label'
defaultMessage='UI language' defaultMessage='language'
/> />
} }
value={ this.store.locale } value={ this.store.locale }

View File

@ -291,7 +291,7 @@ class TxRow extends Component {
<div /> <div />
<div className={ styles.uppercase }> <div className={ styles.uppercase }>
<FormattedMessage <FormattedMessage
id='ui.txList.txRow.verify' id='ui.txList.txRow.verify.confirm'
defaultMessage='Are you sure?' defaultMessage='Are you sure?'
/> />
</div> </div>

View File

@ -370,14 +370,14 @@ class Account extends Component {
onDeny={ this.exportClose } onDeny={ this.exportClose }
title={ title={
<FormattedMessage <FormattedMessage
id='export.account.title' id='account.export.title'
defaultMessage='Export Account' defaultMessage='Export Account'
/> />
} }
> >
<div className={ styles.textbox }> <div className={ styles.textbox }>
<FormattedMessage <FormattedMessage
id='export.account.info' id='account.export.info'
defaultMessage='Export your account as a JSON file. Please enter the password linked with this account.' defaultMessage='Export your account as a JSON file. Please enter the password linked with this account.'
/> />
</div> </div>
@ -388,13 +388,13 @@ class Account extends Component {
type='password' type='password'
hint={ hint={
<FormattedMessage <FormattedMessage
id='export.account.password.hint' id='account.export.password.hint'
defaultMessage='The password specified when creating this account' defaultMessage='The password specified when creating this account'
/> />
} }
label={ label={
<FormattedMessage <FormattedMessage
id='export.account.password.label' id='account.export.password.label'
defaultMessage='Account password' defaultMessage='Account password'
/> />
} }

View File

@ -46,6 +46,8 @@ export default class Parity extends Component {
<FormattedMessage id='settings.parity.label' /> <FormattedMessage id='settings.parity.label' />
} }
> >
<Features />
<div className={ layout.layout }> <div className={ layout.layout }>
<div className={ layout.overview }> <div className={ layout.overview }>
<div> <div>
@ -58,10 +60,10 @@ export default class Parity extends Component {
<div className={ layout.details }> <div className={ layout.details }>
{ this.renderChains() } { this.renderChains() }
{ this.renderModes() } { this.renderModes() }
<Features />
<LanguageSelector /> <LanguageSelector />
</div> </div>
</div> </div>
{ this.renderLogsConfig() } { this.renderLogsConfig() }
</Container> </Container>
); );

View File

@ -208,9 +208,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> {
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024; config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
config.queue.verifier_settings = cmd.verifier_settings; config.queue.verifier_settings = cmd.verifier_settings;
// TODO: could epoch signals be avilable at the end of the file? let service = LightClientService::start(config, &spec, &client_path, cache)
let fetch = ::light::client::fetch::unavailable();
let service = LightClientService::start(config, &spec, fetch, &client_path, cache)
.map_err(|e| format!("Failed to start client: {}", e))?; .map_err(|e| format!("Failed to start client: {}", e))?;
// free up the spec in memory. // free up the spec in memory.

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ macro_rules! println_stderr(
); );
macro_rules! otry { macro_rules! otry {
($e: expr) => ( ($e:expr) => (
match $e { match $e {
Some(ref v) => v, Some(ref v) => v,
None => { None => {
@ -31,21 +31,107 @@ macro_rules! otry {
} }
) )
} }
macro_rules! if_option {
(Option<$type:ty>, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
$($then)*
);
($type:ty, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
$($otherwise)*
);
}
macro_rules! if_vec {
(Vec<$type:ty>, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
$($then)*
);
($type:ty, THEN {$($then:tt)*} ELSE {$($otherwise:tt)*}) => (
$($otherwise)*
);
}
macro_rules! if_option_vec {
(Option<Vec<String>>, THEN {$then:expr} ELSE {$otherwise:expr}) => (
$then
);
(Option<$type:ty>, THEN {$then:expr} ELSE {$otherwise:expr}) => (
$otherwise
);
}
macro_rules! inner_option_type {
(Option<$type:ty>) => (
$type
)
}
macro_rules! inner_vec_type {
(Vec<$type:ty>) => (
$type
)
}
macro_rules! inner_option_vec_type {
(Option<Vec<String>>) => (
String
)
}
macro_rules! usage_with_ident {
($name:expr, $usage:expr, $help:expr) => (
if $usage.contains("<") {
format!("<{}> {} '{}'",$name, $usage, $help)
} else {
format!("[{}] {} '{}'",$name, $usage, $help)
}
);
}
macro_rules! underscore_to_hyphen {
($e:expr) => (
str::replace($e, "_", "-")
)
}
macro_rules! usage { macro_rules! usage {
( (
{ {
$( $(
$field_a:ident : $typ_a:ty, CMD $subc:ident
{
$subc_help:expr,
$(
CMD $subc_subc:ident
{
$subc_subc_help:expr,
$(
FLAG $subc_subc_flag:ident : (bool) = false, $subc_subc_flag_usage:expr, $subc_subc_flag_help:expr,
)*
$(
ARG $subc_subc_arg:ident : ($($subc_subc_arg_type_tt:tt)+) = $subc_subc_arg_default:expr, $subc_subc_arg_usage:expr, $subc_subc_arg_help:expr,
)*
}
)*
$(
FLAG $subc_flag:ident : (bool) = false, $subc_flag_usage:expr, $subc_flag_help:expr,
)*
$(
ARG $subc_arg:ident : ($($subc_arg_type_tt:tt)+) = $subc_arg_default:expr, $subc_arg_usage:expr, $subc_arg_help:expr,
)*
}
)* )*
} }
{ {
$( $(
$field:ident : $typ:ty = $default:expr, or $from_config:expr, [$group_name:expr]
)* $(
} FLAG $flag:ident : (bool) = false, or $flag_from_config:expr, $flag_usage:expr, $flag_help:expr,
{ )*
$( $(
$field_s:ident : $typ_s:ty, display $default_s:expr, or $from_config_s:expr, ARG $arg:ident : ($($arg_type_tt:tt)+) = $arg_default:expr, or $arg_from_config:expr, $arg_usage:expr, $arg_help:expr,
)*
)* )*
} }
) => { ) => {
@ -53,12 +139,17 @@ macro_rules! usage {
use std::{fs, io, process}; use std::{fs, io, process};
use std::io::{Read, Write}; use std::io::{Read, Write};
use util::version; use util::version;
use docopt::{Docopt, Error as DocoptError}; use clap::{Arg, App, SubCommand, AppSettings, Error as ClapError};
use helpers::replace_home; use helpers::replace_home;
use std::ffi::OsStr;
use std::collections::HashMap;
#[cfg(test)]
use regex::Regex;
#[derive(Debug)] #[derive(Debug)]
pub enum ArgsError { pub enum ArgsError {
Docopt(DocoptError), Clap(ClapError),
Decode(toml::de::Error), Decode(toml::de::Error),
Config(String, io::Error), Config(String, io::Error),
} }
@ -66,7 +157,7 @@ macro_rules! usage {
impl ArgsError { impl ArgsError {
pub fn exit(self) -> ! { pub fn exit(self) -> ! {
match self { match self {
ArgsError::Docopt(e) => e.exit(), ArgsError::Clap(e) => e.exit(),
ArgsError::Decode(e) => { ArgsError::Decode(e) => {
println_stderr!("You might have supplied invalid parameters in config file."); println_stderr!("You might have supplied invalid parameters in config file.");
println_stderr!("{}", e); println_stderr!("{}", e);
@ -81,9 +172,9 @@ macro_rules! usage {
} }
} }
impl From<DocoptError> for ArgsError { impl From<ClapError> for ArgsError {
fn from(e: DocoptError) -> Self { fn from(e: ClapError) -> Self {
ArgsError::Docopt(e) ArgsError::Clap(e)
} }
} }
@ -96,15 +187,33 @@ macro_rules! usage {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Args { pub struct Args {
$( $(
pub $field_a: $typ_a, pub $subc: bool,
$(
pub $subc_subc: bool,
$(
pub $subc_subc_flag: bool,
)*
$(
pub $subc_subc_arg: $($subc_subc_arg_type_tt)+,
)*
)*
$(
pub $subc_flag: bool,
)*
$(
pub $subc_arg: $($subc_arg_type_tt)+,
)*
)* )*
$( $(
pub $field: $typ, $(
)* pub $flag: bool,
)*
$( $(
pub $field_s: $typ_s, pub $arg: $($arg_type_tt)+,
)*
)* )*
} }
@ -112,15 +221,32 @@ macro_rules! usage {
fn default() -> Self { fn default() -> Self {
Args { Args {
$( $(
$field_a: Default::default(), $subc: Default::default(),
$(
$subc_subc: Default::default(),
$(
$subc_subc_flag: Default::default(),
)*
$(
$subc_subc_arg: Default::default(),
)*
)*
$(
$subc_flag: Default::default(),
)*
$(
$subc_arg: Default::default(),
)*
)* )*
$( $(
$field: $default.into(), $(
)* $flag: Default::default(),
)*
$( $(
$field_s: Default::default(), $arg: Default::default(),
)*
)* )*
} }
} }
@ -129,13 +255,46 @@ macro_rules! usage {
#[derive(Default, Debug, PartialEq, Clone, Deserialize)] #[derive(Default, Debug, PartialEq, Clone, Deserialize)]
struct RawArgs { struct RawArgs {
$( $(
$field_a: $typ_a, $subc: bool,
$(
$subc_subc: bool,
$(
$subc_subc_flag: bool,
)*
$(
$subc_subc_arg: if_option!(
$($subc_subc_arg_type_tt)+,
THEN { $($subc_subc_arg_type_tt)+ }
ELSE { Option<$($subc_subc_arg_type_tt)+> }
),
)*
)*
$(
$subc_flag: bool,
)*
$(
$subc_arg: if_option!(
$($subc_arg_type_tt)+,
THEN { $($subc_arg_type_tt)+ }
ELSE { Option<$($subc_arg_type_tt)+> }
),
)*
)* )*
$( $(
$field: Option<$typ>, $(
)* $flag: bool,
$( )*
$field_s: Option<$typ_s>,
$(
$arg: if_option!(
$($arg_type_tt)+,
THEN { $($arg_type_tt)+ }
ELSE { Option<$($arg_type_tt)+> }
),
)*
)* )*
} }
@ -149,9 +308,9 @@ macro_rules! usage {
return Ok(raw_args.into_args(Config::default())); return Ok(raw_args.into_args(Config::default()));
} }
let config_file = raw_args.flag_config.clone().unwrap_or_else(|| raw_args.clone().into_args(Config::default()).flag_config); let config_file = raw_args.arg_config.clone().unwrap_or_else(|| raw_args.clone().into_args(Config::default()).arg_config);
let config_file = replace_home(&::dir::default_data_path(), &config_file); let config_file = replace_home(&::dir::default_data_path(), &config_file);
match (fs::File::open(&config_file), raw_args.flag_config.clone()) { match (fs::File::open(&config_file), raw_args.arg_config.clone()) {
// Load config file // Load config file
(Ok(mut file), _) => { (Ok(mut file), _) => {
println_stderr!("Loading config file from {}", &config_file); println_stderr!("Loading config file from {}", &config_file);
@ -178,7 +337,7 @@ macro_rules! usage {
#[cfg(test)] #[cfg(test)]
fn parse_with_config<S: AsRef<str>>(command: &[S], config: Config) -> Result<Self, ArgsError> { fn parse_with_config<S: AsRef<str>>(command: &[S], config: Config) -> Result<Self, ArgsError> {
RawArgs::parse(command).map(|raw| raw.into_args(config)).map_err(ArgsError::Docopt) RawArgs::parse(command).map(|raw| raw.into_args(config)).map_err(ArgsError::Clap)
} }
fn parse_config(config: &str) -> Result<Config, ArgsError> { fn parse_config(config: &str) -> Result<Config, ArgsError> {
@ -188,41 +347,346 @@ macro_rules! usage {
pub fn print_version() -> String { pub fn print_version() -> String {
format!(include_str!("./version.txt"), version()) format!(include_str!("./version.txt"), version())
} }
#[allow(unused_mut)] // subc_subc_exist may be assigned true by the macro
#[allow(unused_assignments)] // Rust issue #22630
pub fn print_help() -> String {
let mut help : String = include_str!("./usage_header.txt").to_owned();
help.push_str("\n\n");
// Subcommands
help.push_str("parity [options]\n");
$(
{
let mut subc_subc_exist = false;
$(
subc_subc_exist = true;
let subc_subc_usages : Vec<&str> = vec![
$(
concat!("[",$subc_subc_flag_usage,"]"),
)*
$(
$subc_subc_arg_usage,
)*
];
if subc_subc_usages.is_empty() {
help.push_str(&format!("parity [options] {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])));
} else {
help.push_str(&format!("parity [options] {} {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]), subc_subc_usages.join(" ")));
}
)*
// Print the subcommand on its own only if it has no subsubcommands
if !subc_subc_exist {
let subc_usages : Vec<&str> = vec![
$(
concat!("[",$subc_flag_usage,"]"),
)*
$(
$subc_arg_usage,
)*
];
if subc_usages.is_empty() {
help.push_str(&format!("parity [options] {}\n", underscore_to_hyphen!(&stringify!($subc)[4..])));
} else {
help.push_str(&format!("parity [options] {} {}\n", underscore_to_hyphen!(&stringify!($subc)[4..]), subc_usages.join(" ")));
}
}
}
)*
// Arguments and flags
$(
help.push_str("\n");
help.push_str($group_name); help.push_str(":\n");
$(
help.push_str(&format!("\t{}\n\t\t{}\n", $flag_usage, $flag_help));
)*
$(
if_option!(
$($arg_type_tt)+,
THEN {
if_option_vec!(
$($arg_type_tt)+,
THEN {
help.push_str(&format!("\t{}\n\t\t{} (default: {:?})\n", $arg_usage, $arg_help, {let x : inner_option_type!($($arg_type_tt)+)> = $arg_default; x}))
}
ELSE {
help.push_str(&format!("\t{}\n\t\t{}{}\n", $arg_usage, $arg_help, $arg_default.map(|x: inner_option_type!($($arg_type_tt)+)| format!(" (default: {})",x)).unwrap_or("".to_owned())))
}
)
}
ELSE {
if_vec!(
$($arg_type_tt)+,
THEN {
help.push_str(&format!("\t{}\n\t\t{} (default: {:?})\n", $arg_usage, $arg_help, {let x : $($arg_type_tt)+ = $arg_default; x}))
}
ELSE {
help.push_str(&format!("\t{}\n\t\t{} (default: {})\n", $arg_usage, $arg_help, $arg_default))
}
)
}
);
)*
)*
help
}
} }
impl RawArgs { impl RawArgs {
fn into_args(self, config: Config) -> Args { fn into_args(self, config: Config) -> Args {
let mut args = Args::default(); let mut args = Args::default();
$( $(
args.$field_a = self.$field_a; args.$subc = self.$subc;
$(
args.$subc_subc = self.$subc_subc;
$(
args.$subc_subc_flag = self.$subc_subc_flag;
)*
$(
args.$subc_subc_arg = if_option!(
$($subc_subc_arg_type_tt)+,
THEN { self.$subc_subc_arg.or($subc_subc_arg_default) }
ELSE { self.$subc_subc_arg.unwrap_or($subc_subc_arg_default.into()) }
);
)*
)*
$(
args.$subc_flag = self.$subc_flag;
)*
$(
args.$subc_arg = if_option!(
$($subc_arg_type_tt)+,
THEN { self.$subc_arg.or($subc_arg_default) }
ELSE { self.$subc_arg.unwrap_or($subc_arg_default.into()) }
);
)*
)* )*
$( $(
args.$field = self.$field.or_else(|| $from_config(&config)).unwrap_or_else(|| $default.into()); $(
)* args.$flag = self.$flag || $flag_from_config(&config).unwrap_or(false);
$( )*
args.$field_s = self.$field_s.or_else(|| $from_config_s(&config)).unwrap_or(None); $(
args.$arg = if_option!(
$($arg_type_tt)+,
THEN { self.$arg.or_else(|| $arg_from_config(&config)).or_else(|| $arg_default.into()) }
ELSE { self.$arg.or_else(|| $arg_from_config(&config)).unwrap_or_else(|| $arg_default.into()) }
);
)*
)* )*
args args
} }
pub fn parse<S: AsRef<str>>(command: &[S]) -> Result<Self, DocoptError> { #[allow(unused_variables)] // the submatches of arg-less subcommands aren't used
Docopt::new(Self::usage()).and_then(|d| d.argv(command).deserialize()) pub fn parse<S: AsRef<str>>(command: &[S]) -> Result<Self, ClapError> {
let usages = vec![
$(
$(
usage_with_ident!(stringify!($arg), $arg_usage, $arg_help),
)*
$(
usage_with_ident!(stringify!($flag), $flag_usage, $flag_help),
)*
)*
];
// Hash of subc|subc_subc => Vec<String>
let mut subc_usages = HashMap::new();
$(
{
let this_subc_usages = vec![
$(
usage_with_ident!(stringify!($subc_flag), $subc_flag_usage, $subc_flag_help),
)*
$(
usage_with_ident!(stringify!($subc_arg), $subc_arg_usage, $subc_arg_help),
)*
];
subc_usages.insert(stringify!($subc),this_subc_usages);
$(
{
let this_subc_subc_usages = vec![
$(
usage_with_ident!(stringify!($subc_subc_flag), $subc_subc_flag_usage, $subc_subc_flag_help),
)*
$(
usage_with_ident!(stringify!($subc_subc_arg), $subc_subc_arg_usage, $subc_subc_arg_help),
)*
];
subc_usages.insert(stringify!($subc_subc), this_subc_subc_usages);
}
)*
}
)*
let matches = App::new("Parity")
.global_setting(AppSettings::VersionlessSubcommands)
.global_setting(AppSettings::AllowLeadingHyphen) // allow for example --allow-ips -10.0.0.0/8
.global_setting(AppSettings::DisableHelpSubcommand)
.help(Args::print_help().as_ref())
.args(&usages.iter().map(|u| Arg::from_usage(u).use_delimiter(false)).collect::<Vec<Arg>>())
$(
.subcommand(
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc)[4..]))
.about($subc_help)
.args(&subc_usages.get(stringify!($subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false)).collect::<Vec<Arg>>())
$(
.setting(AppSettings::SubcommandRequired) // prevent from running `parity account`
.subcommand(
SubCommand::with_name(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..]))
.about($subc_subc_help)
.args(&subc_usages.get(stringify!($subc_subc)).unwrap().iter().map(|u| Arg::from_usage(u).use_delimiter(false)).collect::<Vec<Arg>>())
)
)*
)
)*
.get_matches_from_safe(command.iter().map(|x| OsStr::new(x.as_ref())))?;
let mut raw_args : RawArgs = Default::default();
$(
$(
raw_args.$flag = matches.is_present(stringify!($flag));
)*
$(
raw_args.$arg = if_option!(
$($arg_type_tt)+,
THEN {
if_option_vec!(
$($arg_type_tt)+,
THEN { values_t!(matches, stringify!($arg), inner_option_vec_type!($($arg_type_tt)+)).ok() }
ELSE { value_t!(matches, stringify!($arg), inner_option_type!($($arg_type_tt)+)).ok() }
)
}
ELSE {
if_vec!(
$($arg_type_tt)+,
THEN { values_t!(matches, stringify!($arg), inner_vec_type!($($arg_type_tt)+)).ok() }
ELSE { value_t!(matches, stringify!($arg), $($arg_type_tt)+).ok() }
)
}
);
)*
)*
// Subcommands
$(
if let Some(submatches) = matches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc)[4..])) {
raw_args.$subc = true;
// Subcommand flags
$(
raw_args.$subc_flag = submatches.is_present(&stringify!($subc_flag));
)*
// Subcommand arguments
$(
raw_args.$subc_arg = if_option!(
$($subc_arg_type_tt)+,
THEN {
if_option_vec!(
$($subc_arg_type_tt)+,
THEN { values_t!(submatches, stringify!($subc_arg), inner_option_vec_type!($($subc_arg_type_tt)+)).ok() }
ELSE { value_t!(submatches, stringify!($subc_arg), inner_option_type!($($subc_arg_type_tt)+)).ok() }
)
}
ELSE {
if_vec!(
$($subc_arg_type_tt)+,
THEN { values_t!(submatches, stringify!($subc_arg), inner_vec_type!($($subc_arg_type_tt)+)).ok() }
ELSE { value_t!(submatches, stringify!($subc_arg), $($subc_arg_type_tt)+).ok() }
)
}
);
)*
// Sub-subcommands
$(
if let Some(subsubmatches) = submatches.subcommand_matches(&underscore_to_hyphen!(&stringify!($subc_subc)[stringify!($subc).len()+1..])) {
raw_args.$subc_subc = true;
// Sub-subcommand flags
$(
raw_args.$subc_subc_flag = subsubmatches.is_present(&stringify!($subc_subc_flag));
)*
// Sub-subcommand arguments
$(
raw_args.$subc_subc_arg = if_option!(
$($subc_subc_arg_type_tt)+,
THEN {
if_option_vec!(
$($subc_subc_arg_type_tt)+,
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_vec_type!($($subc_subc_arg_type_tt)+)).ok() }
ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), inner_option_type!($($subc_subc_arg_type_tt)+)).ok() }
)
}
ELSE {
if_vec!(
$($subc_subc_arg_type_tt)+,
THEN { values_t!(subsubmatches, stringify!($subc_subc_arg), inner_vec_type!($($subc_subc_arg_type_tt)+)).ok() }
ELSE { value_t!(subsubmatches, stringify!($subc_subc_arg), $($subc_subc_arg_type_tt)+).ok() }
)
}
);
)*
}
else {
raw_args.$subc_subc = false;
}
)*
}
else {
raw_args.$subc = false;
}
)*
Ok(raw_args)
} }
fn usage() -> String { }
format!(
include_str!("./usage.txt"), #[test]
fn usages_valid() {
let re = Regex::new(r"^(?:(-[a-zA-Z-]+, )?--[a-z-]+(=\[[a-zA-Z]+\](\.\.\.)?|=<[a-zA-Z]+>(\.\.\.)?)?)|(?:\[[a-zA-Z-]+\])(\.\.\.)?|(?:<[a-zA-Z-]+>)(\.\.\.)?$").unwrap();
let usages = vec![
$(
$( $(
$field={ let v: $typ = $default.into(); v }, $(
// Uncomment this to debug $subc_subc_arg_usage,
// "named argument never used" error )*
// $field = $default,
)* )*
$( $(
$field_s = $default_s, $subc_arg_usage,
)* )*
) )*
$(
$(
$flag_usage,
)*
$(
$arg_usage,
)*
)*
];
for usage in &usages {
assert!(re.is_match(usage));
} }
} }
}; }
} }

View File

@ -1,499 +0,0 @@
Parity. Ethereum Client.
By Wood/Paronyan/Kotewicz/Drwięga/Volf et al.
Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd
Usage:
parity [options]
parity ui [options]
parity dapp <path> [options]
parity daemon <pid-file> [options]
parity account (new | list ) [options]
parity account import <path>... [options]
parity wallet import <path> --password FILE [options]
parity import [ <file> ] [options]
parity export (blocks | state) [ <file> ] [options]
parity signer new-token [options]
parity signer list [options]
parity signer sign [ <id> ] [ --password FILE ] [options]
parity signer reject <id> [options]
parity snapshot <file> [options]
parity restore [ <file> ] [options]
parity tools hash <file>
parity db kill [options]
Operating Options:
--mode MODE Set the operating mode. MODE can be one of:
last - Uses the last-used mode, active if none.
active - Parity continuously syncs the chain.
passive - Parity syncs initially, then sleeps and
wakes regularly to resync.
dark - Parity syncs only when the RPC is active.
offline - Parity doesn't sync. (default: {flag_mode}).
--mode-timeout SECS Specify the number of seconds before inactivity
timeout occurs when mode is dark or passive
(default: {flag_mode_timeout}).
--mode-alarm SECS Specify the number of seconds before auto sleep
reawake timeout occurs when mode is passive
(default: {flag_mode_alarm}).
--auto-update SET Set a releases set to automatically update and
install.
all - All updates in the our release track.
critical - Only consensus/security updates.
none - No updates will be auto-installed.
(default: {flag_auto_update}).
--release-track TRACK Set which release track we should use for updates.
stable - Stable releases.
beta - Beta releases.
nightly - Nightly releases (unstable).
testing - Testing releases (do not use).
current - Whatever track this executable was
released on (default: {flag_release_track}).
--public-node Start Parity as a public web server. Account storage
and transaction signing will be delegated to the UI.
(default: {flag_public_node}).
--no-download Normally new releases will be downloaded ready for
updating. This disables it. Not recommended.
(default: {flag_no_download}).
--no-consensus Force the binary to run even if there are known
issues regarding consensus. Not recommended.
(default: {flag_no_consensus}).
--force-direct Run the originally installed version of Parity,
ignoring any updates that have since been installed.
--chain CHAIN Specify the blockchain type. CHAIN may be either a
JSON chain specification file or olympic, frontier,
homestead, mainnet, morden, ropsten, classic, expanse,
testnet, kovan or dev (default: {flag_chain}).
-d --base-path PATH Specify the base data storage path.
(default: {flag_base_path}).
--db-path PATH Specify the database directory path
(default: {flag_db_path}).
--keys-path PATH Specify the path for JSON key files to be found
(default: {flag_keys_path}).
--identity NAME Specify your node's name. (default: {flag_identity})
--light Experimental: run in light client mode. Light clients
synchronize a bare minimum of data and fetch necessary
data on-demand from the network. Much lower in storage,
potentially higher in bandwidth. Has no effect with
subcommands (default: {flag_light}).
Convenience Options:
-c --config CONFIG Specify a configuration. CONFIG may be either a
configuration file or a preset: dev, insecure, dev-insecure,
mining, or non-standard-ports.
(default: {flag_config}).
--ports-shift SHIFT Add SHIFT to all port numbers Parity is listening on.
Includes network port and all servers (RPC, WebSockets, UI, IPFS, SecretStore).
(default: {flag_ports_shift})
--unsafe-expose All servers will listen on external interfaces and will
be remotely accessible. It's equivalent with setting
the following: --{{ws,jsonrpc,ui,ipfs,secret_store,stratum}}-interface=all --*-hosts=all
This option is UNSAFE and should be used with great care!
(default: {flag_unsafe_expose})
Account Options:
--unlock ACCOUNTS Unlock ACCOUNTS for the duration of the execution.
ACCOUNTS is a comma-delimited list of addresses.
Implies --no-ui. (default: {flag_unlock:?})
--password FILE Provide a file containing a password for unlocking
an account. Leading and trailing whitespace is trimmed.
(default: {flag_password:?})
--keys-iterations NUM Specify the number of iterations to use when
deriving key from the password (bigger is more
secure) (default: {flag_keys_iterations}).
--no-hardware-wallets Disables hardware wallet support. (default: {flag_no_hardware_wallets})
--fast-unlock Use drasticly faster unlocking mode. This setting causes
raw secrets to be stored unprotected in memory,
so use with care. (default: {flag_fast_unlock})
UI Options:
--force-ui Enable Trusted UI WebSocket endpoint,
even when --unlock is in use. (default: {flag_force_ui})
--no-ui Disable Trusted UI WebSocket endpoint.
(default: {flag_no_ui})
--ui-port PORT Specify the port of Trusted UI server
(default: {flag_ui_port}).
--ui-interface IP Specify the hostname portion of the Trusted UI
server, IP should be an interface's IP address,
or local (default: {flag_ui_interface}).
--ui-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
is additional security against some attack
vectors. Special options: "all", "none",
(default: {flag_ui_hosts}).
--ui-path PATH Specify directory where Trusted UIs tokens should
be stored. (default: {flag_ui_path})
--ui-no-validation Disable Origin and Host headers validation for
Trusted UI. WARNING: INSECURE. Used only for
development. (default: {flag_ui_no_validation})
Networking Options:
--no-warp Disable syncing from the snapshot over the network. (default: {flag_no_warp})
--port PORT Override the port on which the node should listen
(default: {flag_port}).
--min-peers NUM Try to maintain at least NUM peers (default: {flag_min_peers}).
--max-peers NUM Allow up to NUM peers (default: {flag_max_peers}).
--snapshot-peers NUM Allow additional NUM peers for a snapshot sync
(default: {flag_snapshot_peers}).
--nat METHOD Specify method to use for determining public
address. Must be one of: any, none, upnp,
extip:<IP> (default: {flag_nat}).
--network-id INDEX Override the network identifier from the chain we
are on. (default: {flag_network_id:?})
--bootnodes NODES Override the bootnodes from our chain. NODES should
be comma-delimited enodes. (default: {flag_bootnodes:?})
--no-discovery Disable new peer discovery. (default: {flag_no_discovery})
--node-key KEY Specify node secret key, either as 64-character hex
string or input to SHA3 operation. (default: {flag_node_key:?})
--reserved-peers FILE Provide a file containing enodes, one per line.
These nodes will always have a reserved slot on top
of the normal maximum peers. (default: {flag_reserved_peers:?})
--reserved-only Connect only to reserved nodes. (default: {flag_reserved_only})
--allow-ips FILTER Filter outbound connections. FILTER can be one of:
private - connect to private network IP addresses only;
public - connect to public network IP addresses only;
all - connect to any IP address;
none - block all (for use with a custom filter as below);
a custom filter list in the format: "private ip_range1 -ip_range2 ...".
Where ip_range1 would be allowed and ip_range2 blocked;
Custom blocks ("-ip_range") override custom allows ("ip_range");
(default: {flag_allow_ips}).
--max-pending-peers NUM Allow up to NUM pending connections. (default: {flag_max_pending_peers})
--no-ancient-blocks Disable downloading old blocks after snapshot restoration
or warp sync. (default: {flag_no_ancient_blocks})
--no-serve-light Disable serving of light peers. (default: {flag_no_serve_light})
API and Console Options:
--no-jsonrpc Disable the JSON-RPC API server. (default: {flag_no_jsonrpc})
--jsonrpc-port PORT Specify the port portion of the JSONRPC API server
(default: {flag_jsonrpc_port}).
--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: {flag_jsonrpc_interface}).
--jsonrpc-cors URL Specify CORS header for JSON-RPC API responses.
(default: {flag_jsonrpc_cors:?})
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC
interface. APIS is a comma-delimited list of API
name. Possible name are all, safe, web3, eth, net, personal,
parity, parity_set, traces, rpc, parity_accounts.
You can also disable a specific API by putting '-' in the front: all,-personal
(default: {flag_jsonrpc_apis}).
--jsonrpc-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
is additional security against some attack
vectors. Special options: "all", "none",
(default: {flag_jsonrpc_hosts}).
--jsonrpc-server-threads NUM Enables experimental faster implementation of JSON-RPC server.
Requires Dapps server to be disabled
using --no-dapps. (default: {flag_jsonrpc_server_threads:?})
--jsonrpc-threads THREADS Turn on additional processing threads in all RPC servers.
Setting this to non-zero value allows parallel cpu-heavy queries
execution. (default: {flag_jsonrpc_threads})
--no-ws Disable the WebSockets server. (default: {flag_no_ws})
--ws-port PORT Specify the port portion of the WebSockets server
(default: {flag_ws_port}).
--ws-interface IP Specify the hostname portion of the WebSockets
server, IP should be an interface's IP address, or
all (all interfaces) or local (default: {flag_ws_interface}).
--ws-apis APIS Specify the APIs available through the WebSockets
interface. APIS is a comma-delimited list of API
name. Possible name are web3, eth, pubsub, net, personal,
parity, parity_set, traces, rpc, parity_accounts.
(default: {flag_ws_apis}).
--ws-origins URL Specify Origin header values allowed to connect.
Special options: "all", "none".
(default: {flag_ws_origins})
--ws-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
is additional security against some attack
vectors. Special options: "all", "none",
(default: {flag_ws_hosts}).
--no-ipc Disable JSON-RPC over IPC service. (default: {flag_no_ipc})
--ipc-path PATH Specify custom path for JSON-RPC over IPC service
(default: {flag_ipc_path}).
--ipc-apis APIS Specify custom API set available via JSON-RPC over
IPC (default: {flag_ipc_apis}).
--no-dapps Disable the Dapps server (e.g. status page). (default: {flag_no_dapps})
--dapps-path PATH Specify directory where dapps should be installed.
(default: {flag_dapps_path})
--ipfs-api Enable IPFS-compatible HTTP API. (default: {flag_ipfs_api})
--ipfs-api-port PORT Configure on which port the IPFS HTTP API should listen.
(default: {flag_ipfs_api_port})
--ipfs-api-interface IP Specify the hostname portion of the IPFS API server,
IP should be an interface's IP address or local.
(default: {flag_ipfs_api_interface})
--ipfs-api-cors URL Specify CORS header for IPFS API responses.
(default: {flag_ipfs_api_cors:?})
--ipfs-api-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it
is additional security against some attack
vectors. Special options: "all", "none"
(default: {flag_ipfs_api_hosts}).
Secret Store Options:
--no-secretstore Disable Secret Store functionality. (default: {flag_no_secretstore})
--no-secretstore-http Disable Secret Store HTTP API. (default: {flag_no_secretstore_http})
--no-acl-check Disable ACL check (useful for test environments). (default: {flag_no_secretstore_acl_check})
--secretstore-secret SECRET Hex-encoded secret key of this node.
(required, default: {flag_secretstore_secret:?}).
--secretstore-nodes NODES Comma-separated list of other secret store cluster nodes in form
NODE_PUBLIC_KEY_IN_HEX@NODE_IP_ADDR:NODE_PORT.
(required, default: {flag_secretstore_nodes}).
--secretstore-interface IP Specify the hostname portion for listening to Secret Store Key Server
internal requests, IP should be an interface's IP address, or local
(default: {flag_secretstore_interface}).
--secretstore-port PORT Specify the port portion for listening to Secret Store Key Server
internal requests (default: {flag_secretstore_port}).
--secretstore-http-interface IP Specify the hostname portion for listening to Secret Store Key Server
HTTP requests, IP should be an interface's IP address, or local
(default: {flag_secretstore_http_interface}).
--secretstore-http-port PORT Specify the port portion for listening to Secret Store Key Server
HTTP requests (default: {flag_secretstore_http_port}).
--secretstore-path PATH Specify directory where Secret Store should save its data.
(default: {flag_secretstore_path}).
Sealing/Mining Options:
--author ADDRESS Specify the block author (aka "coinbase") address
for sending block rewards from sealed blocks.
NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION.
(default: {flag_author:?})
--engine-signer ADDRESS Specify the address which should be used to
sign consensus messages and issue blocks.
Relevant only to non-PoW chains.
(default: {flag_engine_signer:?})
--force-sealing Force the node to author new blocks as if it were
always sealing/mining.
(default: {flag_force_sealing})
--reseal-on-txs SET Specify which transactions should force the node
to reseal a block. SET is one of:
none - never reseal on new transactions;
own - reseal only on a new local transaction;
ext - reseal only on a new external transaction;
all - reseal on all new transactions
(default: {flag_reseal_on_txs}).
--reseal-on-uncle Force the node to author new blocks when a new uncle
block is imported.
(default: {flag_reseal_on_uncle})
--reseal-min-period MS Specify the minimum time between reseals from
incoming transactions. MS is time measured in
milliseconds (default: {flag_reseal_min_period}).
--reseal-max-period MS Specify the maximum time since last block to enable
force-sealing. MS is time measured in
milliseconds (default: {flag_reseal_max_period}).
--work-queue-size ITEMS Specify the number of historical work packages
which are kept cached lest a solution is found for
them later. High values take more memory but result
in fewer unusable solutions (default: {flag_work_queue_size}).
--tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas
a single transaction may have for it to be mined.
(default: {flag_tx_gas_limit:?})
--tx-time-limit MS Maximal time for processing single transaction.
If enabled senders/recipients/code of transactions
offending the limit will be banned from being included
in transaction queue for 180 seconds.
(default: {flag_tx_time_limit:?})
--relay-set SET Set of transactions to relay. SET may be:
cheap - Relay any transaction in the queue (this
may include invalid transactions);
strict - Relay only executed transactions (this
guarantees we don't relay invalid transactions, but
means we relay nothing if not mining);
lenient - Same as strict when mining, and cheap
when not (default: {flag_relay_set}).
--min-gas-price WEI Minimum amount of Wei per GAS to be paid for a
transaction to be accepted for mining. Overrides
--basic-tx-usd.
(default: {flag_min_gas_price:?})
--usd-per-tx USD Amount of USD to be paid for a basic transaction
(default: {flag_usd_per_tx}). 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, a web service or 'auto' to use each
web service in turn and fallback on the last known
good value (default: {flag_usd_per_eth}).
--price-update-period T T will be allowed to pass between each gas price
update. T may be daily, hourly, a number of seconds,
or a time string of the form "2 days", "30 minutes"
etc. (default: {flag_price_update_period}).
--gas-floor-target GAS Amount of gas per block to target when sealing a new
block (default: {flag_gas_floor_target}).
--gas-cap GAS A cap on how large we will raise the gas limit per
block due to transaction volume (default: {flag_gas_cap}).
--extra-data STRING Specify a custom extra-data for authored blocks, no
more than 32 characters. (default: {flag_extra_data:?})
--tx-queue-mem-limit MB Maximum amount of memory that can be used by the
transaction queue. Setting this parameter to 0
disables limiting (default: {flag_tx_queue_mem_limit}).
--tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting
to be included in next block) (default: {flag_tx_queue_size}).
--tx-queue-gas LIMIT Maximum amount of total gas for external transactions in
the queue. LIMIT can be either an amount of gas or
'auto' or 'off'. 'auto' sets the limit to be 20x
the current block gas limit. (default: {flag_tx_queue_gas}).
--tx-queue-strategy S Prioritization strategy used to order transactions
in the queue. S may be:
gas - Prioritize txs with low gas limit;
gas_price - Prioritize txs with high gas price;
gas_factor - Prioritize txs using gas price
and gas limit ratio (default: {flag_tx_queue_strategy}).
--tx-queue-ban-count C Number of times maximal time for execution (--tx-time-limit)
can be exceeded before banning sender/recipient/code.
(default: {flag_tx_queue_ban_count})
--tx-queue-ban-time SEC Banning time (in seconds) for offenders of specified
execution time limit. Also number of offending actions
have to reach the threshold within that time.
(default: {flag_tx_queue_ban_time} seconds)
--no-persistent-txqueue Don't save pending local transactions to disk to be
restored whenever the node restarts.
(default: {flag_no_persistent_txqueue}).
--remove-solved Move solved blocks from the work package queue
instead of cloning them. This gives a slightly
faster import speed, but means that extra solutions
submitted for the same work package will go unused.
(default: {flag_remove_solved})
--notify-work URLS URLs to which work package notifications are pushed.
URLS should be a comma-delimited list of HTTP URLs.
(default: {flag_notify_work:?})
--refuse-service-transactions Always refuse service transactions.
(default: {flag_refuse_service_transactions}).
--stratum Run Stratum server for miner push notification. (default: {flag_stratum})
--stratum-interface IP Interface address for Stratum server. (default: {flag_stratum_interface})
--stratum-port PORT Port for Stratum server to listen on. (default: {flag_stratum_port})
--stratum-secret STRING Secret for authorizing Stratum server for peers.
(default: {flag_stratum_secret:?})
Footprint Options:
--tracing BOOL Indicates if full transaction tracing should be
enabled. Works only if client had been fully synced
with tracing enabled. BOOL may be one of auto, on,
off. auto uses last used value of this option (off
if it does not exist) (default: {flag_tracing}).
--pruning METHOD Configure pruning of the state/storage trie. METHOD
may be one of auto, archive, fast:
archive - keep all state trie data. No pruning.
fast - maintain journal overlay. Fast but 50MB used.
auto - use the method most recently synced or
default to fast if none synced (default: {flag_pruning}).
--pruning-history NUM Set a minimum number of recent states to keep when pruning
is active. (default: {flag_pruning_history}).
--pruning-memory MB The ideal amount of memory in megabytes to use to store
recent states. As many states as possible will be kept
within this limit, and at least --pruning-history states
will always be kept. (default: {flag_pruning_memory})
--cache-size-db MB Override database cache size (default: {flag_cache_size_db}).
--cache-size-blocks MB Specify the prefered size of the blockchain cache in
megabytes (default: {flag_cache_size_blocks}).
--cache-size-queue MB Specify the maximum size of memory to use for block
queue (default: {flag_cache_size_queue}).
--cache-size-state MB Specify the maximum size of memory to use for
the state cache (default: {flag_cache_size_state}).
--cache-size MB Set total amount of discretionary memory to use for
the entire system, overrides other cache and queue
options. (default: {flag_cache_size:?})
--fast-and-loose Disables DB WAL, which gives a significant speed up
but means an unclean exit is unrecoverable. (default: {flag_fast_and_loose})
--db-compaction TYPE Database compaction type. TYPE may be one of:
ssd - suitable for SSDs and fast HDDs;
hdd - suitable for slow HDDs;
auto - determine automatically (default: {flag_db_compaction}).
--fat-db BOOL Build appropriate information to allow enumeration
of all accounts and storage keys. Doubles the size
of the state database. BOOL may be one of on, off
or auto. (default: {flag_fat_db})
--scale-verifiers Automatically scale amount of verifier threads based on
workload. Not guaranteed to be faster.
(default: {flag_scale_verifiers})
--num-verifiers INT Amount of verifier threads to use or to begin with, if verifier
auto-scaling is enabled. (default: {flag_num_verifiers:?})
Import/Export Options:
--from BLOCK Export from block BLOCK, which may be an index or
hash (default: {flag_from}).
--to BLOCK Export to (including) block BLOCK, which may be an
index, hash or 'latest' (default: {flag_to}).
--format FORMAT For import/export in given format. FORMAT must be
one of 'hex' and 'binary'.
(default: {flag_format:?} = Import: auto, Export: binary)
--no-seal-check Skip block seal check. (default: {flag_no_seal_check})
--at BLOCK Export state at the given block, which may be an
index, hash, or 'latest'. (default: {flag_at})
--no-storage Don't export account storage. (default: {flag_no_storage})
--no-code Don't export account code. (default: {flag_no_code})
--min-balance WEI Don't export accounts with balance less than specified.
(default: {flag_min_balance:?})
--max-balance WEI Don't export accounts with balance greater than specified.
(default: {flag_max_balance:?})
Snapshot Options:
--at BLOCK Take a snapshot at the given block, which may be an
index, hash, or 'latest'. Note that taking snapshots at
non-recent blocks will only work with --pruning archive
(default: {flag_at})
--no-periodic-snapshot Disable automated snapshots which usually occur once
every 10000 blocks. (default: {flag_no_periodic_snapshot})
Virtual Machine Options:
--jitvm Enable the JIT VM. (default: {flag_jitvm})
Whisper Options:
--whisper Enable the Whisper network. (default: {flag_whisper})
--whisper-pool-size MB Target size of the whisper message pool in megabytes.
(default: {flag_whisper_pool_size})
Legacy Options:
--geth Run in Geth-compatibility mode. Sets the IPC path
to be the same as Geth's. Overrides the --ipc-path
and --ipcpath options. Alters RPCs to reflect Geth
bugs. Includes the personal_ RPC by default.
--testnet Testnet mode. Equivalent to --chain testnet.
Overrides the --keys-path option.
--import-geth-keys Attempt to import keys from Geth client.
--datadir PATH Equivalent to --base-path PATH.
--networkid INDEX Equivalent to --network-id INDEX.
--peers NUM Equivalent to --min-peers NUM.
--nodekey KEY Equivalent to --node-key KEY.
--nodiscover Equivalent to --no-discovery.
-j --jsonrpc Does nothing; JSON-RPC is on by default now.
--jsonrpc-off Equivalent to --no-jsonrpc.
-w --webapp Does nothing; dapps server is on by default now.
--dapps-off Equivalent to --no-dapps.
--dapps-user USERNAME Dapps server authentication has been removed. (default: {flag_dapps_user:?})
--dapps-pass PASSWORD Dapps server authentication has been removed. (default: {flag_dapps_pass:?})
--dapps-apis-all Dapps server is merged with RPC server. Use --jsonrpc-apis. (default: {flag_dapps_apis_all:?})
--dapps-cors URL Dapps server is merged with RPC server. Use --jsonrpc-cors. (default: {flag_dapps_cors:?})
--dapps-hosts HOSTS Dapps server is merged with RPC server. Use --jsonrpc-hosts. (default: {flag_dapps_hosts:?})
--dapps-interface IP Dapps server is merged with RPC server. Use --jsonrpc-interface. (default: {flag_dapps_interface:?})
--dapps-port PORT Dapps server is merged with RPC server. Use --jsonrpc-port. (default: {flag_dapps_port:?})
--rpc Does nothing; JSON-RPC is on by default now.
--warp Does nothing; Warp sync is on by default. (default: {flag_warp})
--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.
--ipcdisable Equivalent to --no-ipc.
--ipc-off Equivalent to --no-ipc.
--ipcapi APIS Equivalent to --ipc-apis APIS.
--ipcpath PATH Equivalent to --ipc-path PATH.
--gasprice WEI Equivalent to --min-gas-price WEI.
--etherbase ADDRESS Equivalent to --author ADDRESS.
--extradata STRING Equivalent to --extra-data STRING.
--cache MB Equivalent to --cache-size MB.
Internal Options:
--can-restart Executable will auto-restart if exiting with 69.
Miscellaneous Options:
--ntp-servers HOSTS Comma separated list of NTP servers to provide current time (host:port).
Used to verify node health. Parity uses pool.ntp.org NTP servers,
consider joining the pool: http://www.pool.ntp.org/join.html
(default: {flag_ntp_servers})
-l --logging LOGGING Specify the logging level. Must conform to the same
format as RUST_LOG. (default: {flag_logging:?})
--log-file FILENAME Specify a filename into which logging should be
appended. (default: {flag_log_file:?})
--no-config Don't load a configuration file.
--no-color Don't use terminal color codes in output. (default: {flag_no_color})
-v --version Show information about version.
-h --help Show this screen.

View File

@ -0,0 +1,3 @@
Parity. Ethereum Client.
By Wood/Paronyan/Kotewicz/Drwięga/Volf et al.
Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd

View File

@ -7,4 +7,3 @@ There is NO WARRANTY, to the extent permitted by law.
By Wood/Paronyan/Kotewicz/Drwięga/Volf By Wood/Paronyan/Kotewicz/Drwięga/Volf
Habermeier/Czaban/Greeff/Gotchac/Redmann Habermeier/Czaban/Greeff/Gotchac/Redmann

View File

@ -106,13 +106,13 @@ impl Configuration {
pub fn into_command(self) -> Result<Execute, String> { pub fn into_command(self) -> Result<Execute, String> {
let dirs = self.directories(); let dirs = self.directories();
let pruning = self.args.flag_pruning.parse()?; let pruning = self.args.arg_pruning.parse()?;
let pruning_history = self.args.flag_pruning_history; let pruning_history = self.args.arg_pruning_history;
let vm_type = self.vm_type()?; let vm_type = self.vm_type()?;
let spec = self.chain().parse()?; let spec = self.chain().parse()?;
let mode = match self.args.flag_mode.as_ref() { let mode = match self.args.arg_mode.as_ref() {
"last" => None, "last" => None,
mode => Some(to_mode(&mode, self.args.flag_mode_timeout, self.args.flag_mode_alarm)?), mode => Some(to_mode(&mode, self.args.arg_mode_timeout, self.args.arg_mode_alarm)?),
}; };
let update_policy = self.update_policy()?; let update_policy = self.update_policy()?;
let logger_config = self.logger_config(); let logger_config = self.logger_config();
@ -123,18 +123,21 @@ impl Configuration {
let ui_conf = self.ui_config(); let ui_conf = self.ui_config();
let network_id = self.network_id(); let network_id = self.network_id();
let cache_config = self.cache_config(); let cache_config = self.cache_config();
let tracing = self.args.flag_tracing.parse()?; let tracing = self.args.arg_tracing.parse()?;
let fat_db = self.args.flag_fat_db.parse()?; let fat_db = self.args.arg_fat_db.parse()?;
let compaction = self.args.flag_db_compaction.parse()?; let compaction = self.args.arg_db_compaction.parse()?;
let wal = !self.args.flag_fast_and_loose; let wal = !self.args.flag_fast_and_loose;
match self.args.flag_warp {
// Logging is not initialized yet, so we print directly to stderr
Some(true) if fat_db == Switch::On => writeln!(&mut stderr(), "Warning: Warp Sync is disabled because Fat DB is turned on").expect("Error writing to stderr"),
Some(true) if tracing == Switch::On => writeln!(&mut stderr(), "Warning: Warp Sync is disabled because tracing is turned on").expect("Error writing to stderr"),
Some(true) if pruning == Pruning::Specific(Algorithm::Archive) => writeln!(&mut stderr(), "Warning: Warp Sync is disabled because pruning mode is set to archive").expect("Error writing to stderr"),
_ => {},
};
let public_node = self.args.flag_public_node; let public_node = self.args.flag_public_node;
if !self.args.flag_no_warp {
// Logging is not initialized yet, so we print directly to stderr
if fat_db == Switch::On {
writeln!(&mut stderr(), "Warning: Warp Sync is disabled because Fat DB is turned on").expect("Error writing to stderr");
} else if tracing == Switch::On {
writeln!(&mut stderr(), "Warning: Warp Sync is disabled because tracing is turned on").expect("Error writing to stderr");
} else if pruning == Pruning::Specific(Algorithm::Archive) {
writeln!(&mut stderr(), "Warning: Warp Sync is disabled because pruning mode is set to archive").expect("Error writing to stderr");
}
}
let warp_sync = !self.args.flag_no_warp && fat_db != Switch::On && tracing != Switch::On && pruning != Pruning::Specific(Algorithm::Archive); let warp_sync = !self.args.flag_no_warp && fat_db != Switch::On && tracing != Switch::On && pruning != Pruning::Specific(Algorithm::Archive);
let geth_compatibility = self.args.flag_geth; let geth_compatibility = self.args.flag_geth;
let mut dapps_conf = self.dapps_config(); let mut dapps_conf = self.dapps_config();
@ -142,9 +145,9 @@ impl Configuration {
let secretstore_conf = self.secretstore_config()?; let secretstore_conf = self.secretstore_config()?;
let format = self.format()?; let format = self.format()?;
if self.args.flag_jsonrpc_server_threads.is_some() && dapps_conf.enabled { if self.args.arg_jsonrpc_server_threads.is_some() && dapps_conf.enabled {
dapps_conf.enabled = false; dapps_conf.enabled = false;
writeln!(&mut stderr(), "Warning: Disabling Dapps server because fast RPC server was enabled.").expect("Error writing to stderr.") writeln!(&mut stderr(), "Warning: Disabling Dapps server because fast RPC server was enabled.").expect("Error writing to stderr.");
} }
let cmd = if self.args.flag_version { let cmd = if self.args.flag_version {
@ -152,25 +155,25 @@ impl Configuration {
} else if self.args.cmd_signer { } else if self.args.cmd_signer {
let authfile = ::signer::codes_path(&ws_conf.signer_path); let authfile = ::signer::codes_path(&ws_conf.signer_path);
if self.args.cmd_new_token { if self.args.cmd_signer_new_token {
Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone()) Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone())
} else if self.args.cmd_sign { } else if self.args.cmd_signer_sign {
let pwfile = self.args.flag_password.get(0).map(|pwfile| { let pwfile = self.args.arg_signer_sign_password.map(|pwfile| {
PathBuf::from(pwfile) PathBuf::from(pwfile)
}); });
Cmd::SignerSign { Cmd::SignerSign {
id: self.args.arg_id, id: self.args.arg_signer_sign_id,
pwfile: pwfile, pwfile: pwfile,
port: ws_conf.port, port: ws_conf.port,
authfile: authfile, authfile: authfile,
} }
} else if self.args.cmd_reject { } else if self.args.cmd_signer_reject {
Cmd::SignerReject { Cmd::SignerReject {
id: self.args.arg_id, id: self.args.arg_signer_reject_id,
port: ws_conf.port, port: ws_conf.port,
authfile: authfile, authfile: authfile,
} }
} else if self.args.cmd_list { } else if self.args.cmd_signer_list {
Cmd::SignerList { Cmd::SignerList {
port: ws_conf.port, port: ws_conf.port,
authfile: authfile, authfile: authfile,
@ -178,32 +181,32 @@ impl Configuration {
} else { } else {
unreachable!(); unreachable!();
} }
} else if self.args.cmd_tools && self.args.cmd_hash { } else if self.args.cmd_tools && self.args.cmd_tools_hash {
Cmd::Hash(self.args.arg_file) Cmd::Hash(self.args.arg_tools_hash_file)
} else if self.args.cmd_db && self.args.cmd_kill { } else if self.args.cmd_db && self.args.cmd_db_kill {
Cmd::Blockchain(BlockchainCmd::Kill(KillBlockchain { Cmd::Blockchain(BlockchainCmd::Kill(KillBlockchain {
spec: spec, spec: spec,
dirs: dirs, dirs: dirs,
pruning: pruning, pruning: pruning,
})) }))
} else if self.args.cmd_account { } else if self.args.cmd_account {
let account_cmd = if self.args.cmd_new { let account_cmd = if self.args.cmd_account_new {
let new_acc = NewAccount { let new_acc = NewAccount {
iterations: self.args.flag_keys_iterations, iterations: self.args.arg_keys_iterations,
path: dirs.keys, path: dirs.keys,
spec: spec, spec: spec,
password_file: self.args.flag_password.first().cloned(), password_file: self.args.arg_account_new_password.clone(),
}; };
AccountCmd::New(new_acc) AccountCmd::New(new_acc)
} else if self.args.cmd_list { } else if self.args.cmd_account_list {
let list_acc = ListAccounts { let list_acc = ListAccounts {
path: dirs.keys, path: dirs.keys,
spec: spec, spec: spec,
}; };
AccountCmd::List(list_acc) AccountCmd::List(list_acc)
} else if self.args.cmd_import { } else if self.args.cmd_account_import {
let import_acc = ImportAccounts { let import_acc = ImportAccounts {
from: self.args.arg_path.clone(), from: self.args.arg_account_import_path.expect("CLI argument is required; qed").clone(),
to: dirs.keys, to: dirs.keys,
spec: spec, spec: spec,
}; };
@ -223,11 +226,11 @@ impl Configuration {
Cmd::Account(account_cmd) Cmd::Account(account_cmd)
} else if self.args.cmd_wallet { } else if self.args.cmd_wallet {
let presale_cmd = ImportWallet { let presale_cmd = ImportWallet {
iterations: self.args.flag_keys_iterations, iterations: self.args.arg_keys_iterations,
path: dirs.keys, path: dirs.keys,
spec: spec, spec: spec,
wallet_path: self.args.arg_path.first().unwrap().clone(), wallet_path: self.args.arg_wallet_import_path.unwrap().clone(),
password_file: self.args.flag_password.first().cloned(), password_file: self.args.arg_wallet_import_password,
}; };
Cmd::ImportPresaleWallet(presale_cmd) Cmd::ImportPresaleWallet(presale_cmd)
} else if self.args.cmd_import { } else if self.args.cmd_import {
@ -235,11 +238,11 @@ impl Configuration {
spec: spec, spec: spec,
cache_config: cache_config, cache_config: cache_config,
dirs: dirs, dirs: dirs,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_import_file.clone(),
format: format, format: format,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
pruning_memory: self.args.flag_pruning_memory, pruning_memory: self.args.arg_pruning_memory,
compaction: compaction, compaction: compaction,
wal: wal, wal: wal,
tracing: tracing, tracing: tracing,
@ -252,44 +255,44 @@ impl Configuration {
}; };
Cmd::Blockchain(BlockchainCmd::Import(import_cmd)) Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
} else if self.args.cmd_export { } else if self.args.cmd_export {
if self.args.cmd_blocks { if self.args.cmd_export_blocks {
let export_cmd = ExportBlockchain { let export_cmd = ExportBlockchain {
spec: spec, spec: spec,
cache_config: cache_config, cache_config: cache_config,
dirs: dirs, dirs: dirs,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_export_blocks_file.clone(),
format: format, format: format,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
pruning_memory: self.args.flag_pruning_memory, pruning_memory: self.args.arg_pruning_memory,
compaction: compaction, compaction: compaction,
wal: wal, wal: wal,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
from_block: to_block_id(&self.args.flag_from)?, from_block: to_block_id(&self.args.arg_export_blocks_from)?,
to_block: to_block_id(&self.args.flag_to)?, to_block: to_block_id(&self.args.arg_export_blocks_to)?,
check_seal: !self.args.flag_no_seal_check, check_seal: !self.args.flag_no_seal_check,
}; };
Cmd::Blockchain(BlockchainCmd::Export(export_cmd)) Cmd::Blockchain(BlockchainCmd::Export(export_cmd))
} else if self.args.cmd_state { } else if self.args.cmd_export_state {
let export_cmd = ExportState { let export_cmd = ExportState {
spec: spec, spec: spec,
cache_config: cache_config, cache_config: cache_config,
dirs: dirs, dirs: dirs,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_export_state_file.clone(),
format: format, format: format,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
pruning_memory: self.args.flag_pruning_memory, pruning_memory: self.args.arg_pruning_memory,
compaction: compaction, compaction: compaction,
wal: wal, wal: wal,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
at: to_block_id(&self.args.flag_at)?, at: to_block_id(&self.args.arg_export_state_at)?,
storage: !self.args.flag_no_storage, storage: !self.args.flag_export_state_no_storage,
code: !self.args.flag_no_code, code: !self.args.flag_export_state_no_code,
min_balance: self.args.flag_min_balance.and_then(|s| to_u256(&s).ok()), min_balance: self.args.arg_export_state_min_balance.and_then(|s| to_u256(&s).ok()),
max_balance: self.args.flag_max_balance.and_then(|s| to_u256(&s).ok()), max_balance: self.args.arg_export_state_max_balance.and_then(|s| to_u256(&s).ok()),
}; };
Cmd::Blockchain(BlockchainCmd::ExportState(export_cmd)) Cmd::Blockchain(BlockchainCmd::ExportState(export_cmd))
} else { } else {
@ -302,14 +305,14 @@ impl Configuration {
spec: spec, spec: spec,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
pruning_memory: self.args.flag_pruning_memory, pruning_memory: self.args.arg_pruning_memory,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
compaction: compaction, compaction: compaction,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_snapshot_file.clone(),
wal: wal, wal: wal,
kind: snapshot::Kind::Take, kind: snapshot::Kind::Take,
block_at: to_block_id(&self.args.flag_at)?, block_at: to_block_id(&self.args.arg_snapshot_at)?,
}; };
Cmd::Snapshot(snapshot_cmd) Cmd::Snapshot(snapshot_cmd)
} else if self.args.cmd_restore { } else if self.args.cmd_restore {
@ -319,11 +322,11 @@ impl Configuration {
spec: spec, spec: spec,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
pruning_memory: self.args.flag_pruning_memory, pruning_memory: self.args.arg_pruning_memory,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
compaction: compaction, compaction: compaction,
file_path: self.args.arg_file.clone(), file_path: self.args.arg_restore_file.clone(),
wal: wal, wal: wal,
kind: snapshot::Kind::Restore, kind: snapshot::Kind::Restore,
block_at: to_block_id("latest")?, // unimportant. block_at: to_block_id("latest")?, // unimportant.
@ -331,7 +334,7 @@ impl Configuration {
Cmd::Snapshot(restore_cmd) Cmd::Snapshot(restore_cmd)
} else { } else {
let daemon = if self.args.cmd_daemon { let daemon = if self.args.cmd_daemon {
Some(self.args.arg_pid_file.clone()) Some(self.args.arg_daemon_pid_file.clone().expect("CLI argument is required; qed"))
} else { } else {
None None
}; };
@ -345,10 +348,10 @@ impl Configuration {
spec: spec, spec: spec,
pruning: pruning, pruning: pruning,
pruning_history: pruning_history, pruning_history: pruning_history,
pruning_memory: self.args.flag_pruning_memory, pruning_memory: self.args.arg_pruning_memory,
daemon: daemon, daemon: daemon,
logger_config: logger_config.clone(), logger_config: logger_config.clone(),
miner_options: self.miner_options(self.args.flag_reseal_min_period)?, miner_options: self.miner_options(self.args.arg_reseal_min_period)?,
ntp_servers: self.ntp_servers(), ntp_servers: self.ntp_servers(),
ws_conf: ws_conf, ws_conf: ws_conf,
http_conf: http_conf, http_conf: http_conf,
@ -376,8 +379,8 @@ impl Configuration {
secretstore_conf: secretstore_conf, secretstore_conf: secretstore_conf,
dapp: self.dapp_to_open()?, dapp: self.dapp_to_open()?,
ui: self.args.cmd_ui, ui: self.args.cmd_ui,
name: self.args.flag_identity, name: self.args.arg_identity,
custom_bootnodes: self.args.flag_bootnodes.is_some(), custom_bootnodes: self.args.arg_bootnodes.is_some(),
no_periodic_snapshot: self.args.flag_no_periodic_snapshot, no_periodic_snapshot: self.args.flag_no_periodic_snapshot,
check_seal: !self.args.flag_no_seal_check, check_seal: !self.args.flag_no_seal_check,
download_old_blocks: !self.args.flag_no_ancient_blocks, download_old_blocks: !self.args.flag_no_ancient_blocks,
@ -408,8 +411,8 @@ impl Configuration {
let extras = MinerExtras { let extras = MinerExtras {
author: self.author()?, author: self.author()?,
extra_data: self.extra_data()?, extra_data: self.extra_data()?,
gas_floor_target: to_u256(&self.args.flag_gas_floor_target)?, gas_floor_target: to_u256(&self.args.arg_gas_floor_target)?,
gas_ceil_target: to_u256(&self.args.flag_gas_cap)?, gas_ceil_target: to_u256(&self.args.arg_gas_cap)?,
engine_signer: self.engine_signer()?, engine_signer: self.engine_signer()?,
}; };
@ -417,37 +420,39 @@ impl Configuration {
} }
fn author(&self) -> Result<Address, String> { fn author(&self) -> Result<Address, String> {
to_address(self.args.flag_etherbase.clone().or(self.args.flag_author.clone())) to_address(self.args.arg_etherbase.clone().or(self.args.arg_author.clone()))
} }
fn engine_signer(&self) -> Result<Address, String> { fn engine_signer(&self) -> Result<Address, String> {
to_address(self.args.flag_engine_signer.clone()) to_address(self.args.arg_engine_signer.clone())
} }
fn format(&self) -> Result<Option<DataFormat>, String> { fn format(&self) -> Result<Option<DataFormat>, String> {
match self.args.flag_format { match self.args.arg_import_format.clone()
.or(self.args.arg_export_blocks_format.clone())
.or(self.args.arg_export_state_format.clone()) {
Some(ref f) => Ok(Some(f.parse()?)), Some(ref f) => Ok(Some(f.parse()?)),
None => Ok(None), None => Ok(None),
} }
} }
fn cache_config(&self) -> CacheConfig { fn cache_config(&self) -> CacheConfig {
match self.args.flag_cache_size.or(self.args.flag_cache) { match self.args.arg_cache_size.or(self.args.arg_cache) {
Some(size) => CacheConfig::new_with_total_cache_size(size), Some(size) => CacheConfig::new_with_total_cache_size(size),
None => CacheConfig::new( None => CacheConfig::new(
self.args.flag_cache_size_db, self.args.arg_cache_size_db,
self.args.flag_cache_size_blocks, self.args.arg_cache_size_blocks,
self.args.flag_cache_size_queue, self.args.arg_cache_size_queue,
self.args.flag_cache_size_state, self.args.arg_cache_size_state,
), ),
} }
} }
fn logger_config(&self) -> LogConfig { fn logger_config(&self) -> LogConfig {
LogConfig { LogConfig {
mode: self.args.flag_logging.clone(), mode: self.args.arg_logging.clone(),
color: !self.args.flag_no_color && !cfg!(windows), color: !self.args.flag_no_color && !cfg!(windows),
file: self.args.flag_log_file.clone(), file: self.args.arg_log_file.clone(),
} }
} }
@ -458,44 +463,44 @@ impl Configuration {
else if self.args.flag_testnet { else if self.args.flag_testnet {
"testnet".to_owned() "testnet".to_owned()
} else { } else {
self.args.flag_chain.clone() self.args.arg_chain.clone()
} }
} }
fn max_peers(&self) -> u32 { fn max_peers(&self) -> u32 {
let peers = self.args.flag_max_peers as u32; let peers = self.args.arg_max_peers as u32;
max(self.min_peers(), peers) max(self.min_peers(), peers)
} }
fn ip_filter(&self) -> Result<IpFilter, String> { fn ip_filter(&self) -> Result<IpFilter, String> {
match IpFilter::parse(self.args.flag_allow_ips.as_str()) { match IpFilter::parse(self.args.arg_allow_ips.as_str()) {
Ok(allow_ip) => Ok(allow_ip), Ok(allow_ip) => Ok(allow_ip),
Err(_) => Err("Invalid IP filter value".to_owned()), Err(_) => Err("Invalid IP filter value".to_owned()),
} }
} }
fn min_peers(&self) -> u32 { fn min_peers(&self) -> u32 {
self.args.flag_peers.unwrap_or(self.args.flag_min_peers) as u32 self.args.arg_peers.unwrap_or(self.args.arg_min_peers) as u32
} }
fn max_pending_peers(&self) -> u32 { fn max_pending_peers(&self) -> u32 {
self.args.flag_max_pending_peers as u32 self.args.arg_max_pending_peers as u32
} }
fn snapshot_peers(&self) -> u32 { fn snapshot_peers(&self) -> u32 {
self.args.flag_snapshot_peers as u32 self.args.arg_snapshot_peers as u32
} }
fn work_notify(&self) -> Vec<String> { fn work_notify(&self) -> Vec<String> {
self.args.flag_notify_work.as_ref().map_or_else(Vec::new, |s| s.split(',').map(|s| s.to_owned()).collect()) self.args.arg_notify_work.as_ref().map_or_else(Vec::new, |s| s.split(',').map(|s| s.to_owned()).collect())
} }
fn accounts_config(&self) -> Result<AccountsConfig, String> { fn accounts_config(&self) -> Result<AccountsConfig, String> {
let cfg = AccountsConfig { let cfg = AccountsConfig {
iterations: self.args.flag_keys_iterations, iterations: self.args.arg_keys_iterations,
testnet: self.args.flag_testnet, testnet: self.args.flag_testnet,
password_files: self.args.flag_password.clone(), password_files: self.args.arg_password.clone(),
unlocked_accounts: to_addresses(&self.args.flag_unlock)?, unlocked_accounts: to_addresses(&self.args.arg_unlock)?,
enable_hardware_wallets: !self.args.flag_no_hardware_wallets, enable_hardware_wallets: !self.args.flag_no_hardware_wallets,
enable_fast_unlock: self.args.flag_fast_unlock, enable_fast_unlock: self.args.flag_fast_unlock,
}; };
@ -508,8 +513,8 @@ impl Configuration {
Ok(Some(StratumOptions { Ok(Some(StratumOptions {
io_path: self.directories().db, io_path: self.directories().db,
listen_addr: self.stratum_interface(), listen_addr: self.stratum_interface(),
port: self.args.flag_ports_shift + self.args.flag_stratum_port, port: self.args.arg_ports_shift + self.args.arg_stratum_port,
secret: self.args.flag_stratum_secret.as_ref().map(|s| s.parse::<H256>().unwrap_or_else(|_| keccak(s))), secret: self.args.arg_stratum_secret.as_ref().map(|s| s.parse::<H256>().unwrap_or_else(|_| keccak(s))),
})) }))
} else { Ok(None) } } else { Ok(None) }
} }
@ -519,7 +524,7 @@ impl Configuration {
return Err("Force sealing can't be used with reseal_min_period = 0".into()); return Err("Force sealing can't be used with reseal_min_period = 0".into());
} }
let reseal = self.args.flag_reseal_on_txs.parse::<ResealPolicy>()?; let reseal = self.args.arg_reseal_on_txs.parse::<ResealPolicy>()?;
let options = MinerOptions { let options = MinerOptions {
new_work_notify: self.work_notify(), new_work_notify: self.work_notify(),
@ -527,26 +532,26 @@ impl Configuration {
reseal_on_external_tx: reseal.external, reseal_on_external_tx: reseal.external,
reseal_on_own_tx: reseal.own, reseal_on_own_tx: reseal.own,
reseal_on_uncle: self.args.flag_reseal_on_uncle, reseal_on_uncle: self.args.flag_reseal_on_uncle,
tx_gas_limit: match self.args.flag_tx_gas_limit { tx_gas_limit: match self.args.arg_tx_gas_limit {
Some(ref d) => to_u256(d)?, Some(ref d) => to_u256(d)?,
None => U256::max_value(), None => U256::max_value(),
}, },
tx_queue_size: self.args.flag_tx_queue_size, tx_queue_size: self.args.arg_tx_queue_size,
tx_queue_memory_limit: if self.args.flag_tx_queue_mem_limit > 0 { tx_queue_memory_limit: if self.args.arg_tx_queue_mem_limit > 0 {
Some(self.args.flag_tx_queue_mem_limit as usize * 1024 * 1024) Some(self.args.arg_tx_queue_mem_limit as usize * 1024 * 1024)
} else { None }, } else { None },
tx_queue_gas_limit: to_gas_limit(&self.args.flag_tx_queue_gas)?, tx_queue_gas_limit: to_gas_limit(&self.args.arg_tx_queue_gas)?,
tx_queue_strategy: to_queue_strategy(&self.args.flag_tx_queue_strategy)?, tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?,
pending_set: to_pending_set(&self.args.flag_relay_set)?, pending_set: to_pending_set(&self.args.arg_relay_set)?,
reseal_min_period: Duration::from_millis(reseal_min_period), reseal_min_period: Duration::from_millis(reseal_min_period),
reseal_max_period: Duration::from_millis(self.args.flag_reseal_max_period), reseal_max_period: Duration::from_millis(self.args.arg_reseal_max_period),
work_queue_size: self.args.flag_work_queue_size, work_queue_size: self.args.arg_work_queue_size,
enable_resubmission: !self.args.flag_remove_solved, enable_resubmission: !self.args.flag_remove_solved,
tx_queue_banning: match self.args.flag_tx_time_limit { tx_queue_banning: match self.args.arg_tx_time_limit {
Some(limit) => Banning::Enabled { Some(limit) => Banning::Enabled {
min_offends: self.args.flag_tx_queue_ban_count, min_offends: self.args.arg_tx_queue_ban_count,
offend_threshold: Duration::from_millis(limit), offend_threshold: Duration::from_millis(limit),
ban_duration: Duration::from_secs(self.args.flag_tx_queue_ban_time as u64), ban_duration: Duration::from_secs(self.args.arg_tx_queue_ban_time as u64),
}, },
None => Banning::Disabled, None => Banning::Disabled,
}, },
@ -557,11 +562,11 @@ impl Configuration {
} }
fn ui_port(&self) -> u16 { fn ui_port(&self) -> u16 {
self.args.flag_ports_shift + self.args.flag_ui_port self.args.arg_ports_shift + self.args.arg_ui_port
} }
fn ntp_servers(&self) -> Vec<String> { fn ntp_servers(&self) -> Vec<String> {
self.args.flag_ntp_servers.split(",").map(str::to_owned).collect() self.args.arg_ntp_servers.split(",").map(str::to_owned).collect()
} }
fn ui_config(&self) -> UiConfiguration { fn ui_config(&self) -> UiConfiguration {
@ -581,7 +586,7 @@ impl Configuration {
enabled: self.dapps_enabled(), enabled: self.dapps_enabled(),
dapps_path: PathBuf::from(self.directories().dapps), dapps_path: PathBuf::from(self.directories().dapps),
extra_dapps: if self.args.cmd_dapp { extra_dapps: if self.args.cmd_dapp {
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect() self.args.arg_dapp_path.iter().map(|path| PathBuf::from(path)).collect()
} else { } else {
vec![] vec![]
}, },
@ -616,9 +621,9 @@ impl Configuration {
self_secret: self.secretstore_self_secret()?, self_secret: self.secretstore_self_secret()?,
nodes: self.secretstore_nodes()?, nodes: self.secretstore_nodes()?,
interface: self.secretstore_interface(), interface: self.secretstore_interface(),
port: self.args.flag_ports_shift + self.args.flag_secretstore_port, port: self.args.arg_ports_shift + self.args.arg_secretstore_port,
http_interface: self.secretstore_http_interface(), http_interface: self.secretstore_http_interface(),
http_port: self.args.flag_ports_shift + self.args.flag_secretstore_http_port, http_port: self.args.arg_ports_shift + self.args.arg_secretstore_http_port,
data_path: self.directories().secretstore, data_path: self.directories().secretstore,
}) })
} }
@ -626,7 +631,7 @@ impl Configuration {
fn ipfs_config(&self) -> IpfsConfiguration { fn ipfs_config(&self) -> IpfsConfiguration {
IpfsConfiguration { IpfsConfiguration {
enabled: self.args.flag_ipfs_api, enabled: self.args.flag_ipfs_api,
port: self.args.flag_ports_shift + self.args.flag_ipfs_api_port, port: self.args.arg_ports_shift + self.args.arg_ipfs_api_port,
interface: self.ipfs_interface(), interface: self.ipfs_interface(),
cors: self.ipfs_cors(), cors: self.ipfs_cors(),
hosts: self.ipfs_hosts(), hosts: self.ipfs_hosts(),
@ -637,7 +642,7 @@ impl Configuration {
if !self.args.cmd_dapp { if !self.args.cmd_dapp {
return Ok(None); return Ok(None);
} }
let path = self.args.arg_path.get(0).map(String::as_str).unwrap_or("."); let path = self.args.arg_dapp_path.as_ref().map(String::as_str).unwrap_or(".");
let path = Path::new(path).canonicalize() let path = Path::new(path).canonicalize()
.map_err(|e| format!("Invalid path: {}. Error: {:?}", path, e))?; .map_err(|e| format!("Invalid path: {}. Error: {:?}", path, e))?;
let name = path.file_name() let name = path.file_name()
@ -654,14 +659,14 @@ impl Configuration {
U256::from_dec_str(&format!("{:.0}", wei_per_gas)).unwrap() U256::from_dec_str(&format!("{:.0}", wei_per_gas)).unwrap()
} }
if let Some(dec) = self.args.flag_gasprice.as_ref() { if let Some(dec) = self.args.arg_gasprice.as_ref() {
return Ok(GasPricerConfig::Fixed(to_u256(dec)?)); return Ok(GasPricerConfig::Fixed(to_u256(dec)?));
} else if let Some(dec) = self.args.flag_min_gas_price { } else if let Some(dec) = self.args.arg_min_gas_price {
return Ok(GasPricerConfig::Fixed(U256::from(dec))); return Ok(GasPricerConfig::Fixed(U256::from(dec)));
} }
let usd_per_tx = to_price(&self.args.flag_usd_per_tx)?; let usd_per_tx = to_price(&self.args.arg_usd_per_tx)?;
if "auto" == self.args.flag_usd_per_eth.as_str() { if "auto" == self.args.arg_usd_per_eth.as_str() {
// Just a very rough estimate to avoid accepting // Just a very rough estimate to avoid accepting
// ZGP transactions before the price is fetched // ZGP transactions before the price is fetched
// if user does not want it. // if user does not want it.
@ -669,11 +674,11 @@ impl Configuration {
return Ok(GasPricerConfig::Calibrated { return Ok(GasPricerConfig::Calibrated {
initial_minimum: wei_per_gas(usd_per_tx, last_known_usd_per_eth), initial_minimum: wei_per_gas(usd_per_tx, last_known_usd_per_eth),
usd_per_tx: usd_per_tx, usd_per_tx: usd_per_tx,
recalibration_period: to_duration(self.args.flag_price_update_period.as_str())?, recalibration_period: to_duration(self.args.arg_price_update_period.as_str())?,
}); });
} }
let usd_per_eth = to_price(&self.args.flag_usd_per_eth)?; let usd_per_eth = to_price(&self.args.arg_usd_per_eth)?;
let wei_per_gas = wei_per_gas(usd_per_tx, usd_per_eth); let wei_per_gas = wei_per_gas(usd_per_tx, usd_per_eth);
info!( info!(
@ -686,7 +691,7 @@ impl Configuration {
} }
fn extra_data(&self) -> Result<Bytes, String> { fn extra_data(&self) -> Result<Bytes, String> {
match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) { match self.args.arg_extradata.as_ref().or(self.args.arg_extra_data.as_ref()) {
Some(x) if x.len() <= 32 => Ok(x.as_bytes().to_owned()), Some(x) if x.len() <= 32 => Ok(x.as_bytes().to_owned()),
None => Ok(version_data()), None => Ok(version_data()),
Some(_) => Err("Extra data must be at most 32 characters".into()), Some(_) => Err("Extra data must be at most 32 characters".into()),
@ -696,7 +701,7 @@ impl Configuration {
fn init_reserved_nodes(&self) -> Result<Vec<String>, String> { fn init_reserved_nodes(&self) -> Result<Vec<String>, String> {
use std::fs::File; use std::fs::File;
match self.args.flag_reserved_peers { match self.args.arg_reserved_peers {
Some(ref path) => { Some(ref path) => {
let mut buffer = String::new(); let mut buffer = String::new();
let mut node_file = File::open(path).map_err(|e| format!("Error opening reserved nodes file: {}", e))?; let mut node_file = File::open(path).map_err(|e| format!("Error opening reserved nodes file: {}", e))?;
@ -712,10 +717,10 @@ impl Configuration {
} }
fn net_addresses(&self) -> Result<(SocketAddr, Option<SocketAddr>), String> { fn net_addresses(&self) -> Result<(SocketAddr, Option<SocketAddr>), String> {
let port = self.args.flag_ports_shift + self.args.flag_port; let port = self.args.arg_ports_shift + self.args.arg_port;
let listen_address = SocketAddr::new("0.0.0.0".parse().unwrap(), port); let listen_address = SocketAddr::new("0.0.0.0".parse().unwrap(), port);
let public_address = if self.args.flag_nat.starts_with("extip:") { let public_address = if self.args.arg_nat.starts_with("extip:") {
let host = &self.args.flag_nat[6..]; let host = &self.args.arg_nat[6..];
let host = host.parse().map_err(|_| format!("Invalid host given with `--nat extip:{}`", host))?; let host = host.parse().map_err(|_| format!("Invalid host given with `--nat extip:{}`", host))?;
Some(SocketAddr::new(host, port)) Some(SocketAddr::new(host, port))
} else { } else {
@ -726,12 +731,12 @@ impl Configuration {
fn net_config(&self) -> Result<NetworkConfiguration, String> { fn net_config(&self) -> Result<NetworkConfiguration, String> {
let mut ret = NetworkConfiguration::new(); let mut ret = NetworkConfiguration::new();
ret.nat_enabled = self.args.flag_nat == "any" || self.args.flag_nat == "upnp"; ret.nat_enabled = self.args.arg_nat == "any" || self.args.arg_nat == "upnp";
ret.boot_nodes = to_bootnodes(&self.args.flag_bootnodes)?; ret.boot_nodes = to_bootnodes(&self.args.arg_bootnodes)?;
let (listen, public) = self.net_addresses()?; let (listen, public) = self.net_addresses()?;
ret.listen_address = Some(format!("{}", listen)); ret.listen_address = Some(format!("{}", listen));
ret.public_address = public.map(|p| format!("{}", p)); ret.public_address = public.map(|p| format!("{}", p));
ret.use_secret = match self.args.flag_node_key.as_ref() ret.use_secret = match self.args.arg_node_key.as_ref()
.map(|s| s.parse::<Secret>().or_else(|_| Secret::from_unsafe_slice(&keccak(s))).map_err(|e| format!("Invalid key: {:?}", e)) .map(|s| s.parse::<Secret>().or_else(|_| Secret::from_unsafe_slice(&keccak(s))).map_err(|e| format!("Invalid key: {:?}", e))
) { ) {
None => None, None => None,
@ -753,13 +758,13 @@ impl Configuration {
} }
fn network_id(&self) -> Option<u64> { fn network_id(&self) -> Option<u64> {
self.args.flag_network_id.or(self.args.flag_networkid) self.args.arg_network_id.or(self.args.arg_networkid)
} }
fn rpc_apis(&self) -> String { fn rpc_apis(&self) -> String {
let mut apis: Vec<&str> = self.args.flag_rpcapi let mut apis: Vec<&str> = self.args.arg_rpcapi
.as_ref() .as_ref()
.unwrap_or(&self.args.flag_jsonrpc_apis) .unwrap_or(&self.args.arg_jsonrpc_apis)
.split(",") .split(",")
.collect(); .collect();
@ -775,12 +780,12 @@ impl Configuration {
} }
fn rpc_cors(&self) -> Option<Vec<String>> { fn rpc_cors(&self) -> Option<Vec<String>> {
let cors = self.args.flag_jsonrpc_cors.as_ref().or(self.args.flag_rpccorsdomain.as_ref()); let cors = self.args.arg_jsonrpc_cors.as_ref().or(self.args.arg_rpccorsdomain.as_ref());
Self::cors(cors) Self::cors(cors)
} }
fn ipfs_cors(&self) -> Option<Vec<String>> { fn ipfs_cors(&self) -> Option<Vec<String>> {
Self::cors(self.args.flag_ipfs_api_cors.as_ref()) Self::cors(self.args.arg_ipfs_api_cors.as_ref())
} }
fn hosts(&self, hosts: &str, interface: &str) -> Option<Vec<String>> { fn hosts(&self, hosts: &str, interface: &str) -> Option<Vec<String>> {
@ -806,15 +811,15 @@ impl Configuration {
} }
fn ui_hosts(&self) -> Option<Vec<String>> { fn ui_hosts(&self) -> Option<Vec<String>> {
self.hosts(&self.args.flag_ui_hosts, &self.ui_interface()) self.hosts(&self.args.arg_ui_hosts, &self.ui_interface())
} }
fn rpc_hosts(&self) -> Option<Vec<String>> { fn rpc_hosts(&self) -> Option<Vec<String>> {
self.hosts(&self.args.flag_jsonrpc_hosts, &self.rpc_interface()) self.hosts(&self.args.arg_jsonrpc_hosts, &self.rpc_interface())
} }
fn ws_hosts(&self) -> Option<Vec<String>> { fn ws_hosts(&self) -> Option<Vec<String>> {
self.hosts(&self.args.flag_ws_hosts, &self.ws_interface()) self.hosts(&self.args.arg_ws_hosts, &self.ws_interface())
} }
fn ws_origins(&self) -> Option<Vec<String>> { fn ws_origins(&self) -> Option<Vec<String>> {
@ -822,11 +827,11 @@ impl Configuration {
return None; return None;
} }
Self::parse_hosts(&self.args.flag_ws_origins) Self::parse_hosts(&self.args.arg_ws_origins)
} }
fn ipfs_hosts(&self) -> Option<Vec<String>> { fn ipfs_hosts(&self) -> Option<Vec<String>> {
self.hosts(&self.args.flag_ipfs_api_hosts, &self.ipfs_interface()) self.hosts(&self.args.arg_ipfs_api_hosts, &self.ipfs_interface())
} }
fn ipc_config(&self) -> Result<IpcConfiguration, String> { fn ipc_config(&self) -> Result<IpcConfiguration, String> {
@ -834,7 +839,7 @@ impl Configuration {
enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off || self.args.flag_no_ipc), enabled: !(self.args.flag_ipcdisable || self.args.flag_ipc_off || self.args.flag_no_ipc),
socket_addr: self.ipc_path(), socket_addr: self.ipc_path(),
apis: { apis: {
let mut apis = self.args.flag_ipcapi.clone().unwrap_or(self.args.flag_ipc_apis.clone()); let mut apis = self.args.arg_ipcapi.clone().unwrap_or(self.args.arg_ipc_apis.clone());
if self.args.flag_geth { if self.args.flag_geth {
if !apis.is_empty() { if !apis.is_empty() {
apis.push_str(","); apis.push_str(",");
@ -852,19 +857,19 @@ impl Configuration {
let conf = HttpConfiguration { let conf = HttpConfiguration {
enabled: self.rpc_enabled(), enabled: self.rpc_enabled(),
interface: self.rpc_interface(), interface: self.rpc_interface(),
port: self.args.flag_ports_shift + self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port), port: self.args.arg_ports_shift + self.args.arg_rpcport.unwrap_or(self.args.arg_jsonrpc_port),
apis: match self.args.flag_public_node { apis: match self.args.flag_public_node {
false => self.rpc_apis().parse()?, false => self.rpc_apis().parse()?,
true => self.rpc_apis().parse::<ApiSet>()?.retain(ApiSet::PublicContext), true => self.rpc_apis().parse::<ApiSet>()?.retain(ApiSet::PublicContext),
}, },
hosts: self.rpc_hosts(), hosts: self.rpc_hosts(),
cors: self.rpc_cors(), cors: self.rpc_cors(),
server_threads: match self.args.flag_jsonrpc_server_threads { server_threads: match self.args.arg_jsonrpc_server_threads {
Some(threads) if threads > 0 => Some(threads), Some(threads) if threads > 0 => Some(threads),
None => None, None => None,
_ => return Err("--jsonrpc-server-threads number needs to be positive.".into()), _ => return Err("--jsonrpc-server-threads number needs to be positive.".into()),
}, },
processing_threads: self.args.flag_jsonrpc_threads, processing_threads: self.args.arg_jsonrpc_threads,
}; };
Ok(conf) Ok(conf)
@ -876,8 +881,8 @@ impl Configuration {
let conf = WsConfiguration { let conf = WsConfiguration {
enabled: self.ws_enabled(), enabled: self.ws_enabled(),
interface: self.ws_interface(), interface: self.ws_interface(),
port: self.args.flag_ports_shift + self.args.flag_ws_port, port: self.args.arg_ports_shift + self.args.arg_ws_port,
apis: self.args.flag_ws_apis.parse()?, apis: self.args.arg_ws_apis.parse()?,
hosts: self.ws_hosts(), hosts: self.ws_hosts(),
origins: self.ws_origins(), origins: self.ws_origins(),
signer_path: self.directories().signer.into(), signer_path: self.directories().signer.into(),
@ -892,7 +897,7 @@ impl Configuration {
let http_conf = self.http_config()?; let http_conf = self.http_config()?;
let net_addresses = self.net_addresses()?; let net_addresses = self.net_addresses()?;
Ok(NetworkSettings { Ok(NetworkSettings {
name: self.args.flag_identity.clone(), name: self.args.arg_identity.clone(),
chain: self.chain(), chain: self.chain(),
network_port: net_addresses.0.port(), network_port: net_addresses.0.port(),
rpc_enabled: http_conf.enabled, rpc_enabled: http_conf.enabled,
@ -905,13 +910,13 @@ impl Configuration {
Ok(UpdatePolicy { Ok(UpdatePolicy {
enable_downloading: !self.args.flag_no_download, enable_downloading: !self.args.flag_no_download,
require_consensus: !self.args.flag_no_consensus, require_consensus: !self.args.flag_no_consensus,
filter: match self.args.flag_auto_update.as_ref() { filter: match self.args.arg_auto_update.as_ref() {
"none" => UpdateFilter::None, "none" => UpdateFilter::None,
"critical" => UpdateFilter::Critical, "critical" => UpdateFilter::Critical,
"all" => UpdateFilter::All, "all" => UpdateFilter::All,
_ => return Err("Invalid value for `--auto-update`. See `--help` for more information.".into()), _ => return Err("Invalid value for `--auto-update`. See `--help` for more information.".into()),
}, },
track: match self.args.flag_release_track.as_ref() { track: match self.args.arg_release_track.as_ref() {
"stable" => ReleaseTrack::Stable, "stable" => ReleaseTrack::Stable,
"beta" => ReleaseTrack::Beta, "beta" => ReleaseTrack::Beta,
"nightly" => ReleaseTrack::Nightly, "nightly" => ReleaseTrack::Nightly,
@ -927,23 +932,23 @@ impl Configuration {
use path; use path;
let local_path = default_local_path(); let local_path = default_local_path();
let base_path = self.args.flag_base_path.as_ref().or_else(|| self.args.flag_datadir.as_ref()).map_or_else(|| default_data_path(), |s| s.clone()); let base_path = self.args.arg_base_path.as_ref().or_else(|| self.args.arg_datadir.as_ref()).map_or_else(|| default_data_path(), |s| s.clone());
let data_path = replace_home("", &base_path); let data_path = replace_home("", &base_path);
let is_using_base_path = self.args.flag_base_path.is_some(); let is_using_base_path = self.args.arg_base_path.is_some();
// If base_path is set and db_path is not we default to base path subdir instead of LOCAL. // If base_path is set and db_path is not we default to base path subdir instead of LOCAL.
let base_db_path = if is_using_base_path && self.args.flag_db_path.is_none() { let base_db_path = if is_using_base_path && self.args.arg_db_path.is_none() {
"$BASE/chains" "$BASE/chains"
} else { } else {
self.args.flag_db_path.as_ref().map_or(dir::CHAINS_PATH, |s| &s) self.args.arg_db_path.as_ref().map_or(dir::CHAINS_PATH, |s| &s)
}; };
let cache_path = if is_using_base_path { "$BASE/cache" } else { dir::CACHE_PATH }; let cache_path = if is_using_base_path { "$BASE/cache" } else { dir::CACHE_PATH };
let db_path = replace_home_and_local(&data_path, &local_path, &base_db_path); let db_path = replace_home_and_local(&data_path, &local_path, &base_db_path);
let cache_path = replace_home_and_local(&data_path, &local_path, cache_path); let cache_path = replace_home_and_local(&data_path, &local_path, cache_path);
let keys_path = replace_home(&data_path, &self.args.flag_keys_path); let keys_path = replace_home(&data_path, &self.args.arg_keys_path);
let dapps_path = replace_home(&data_path, &self.args.flag_dapps_path); let dapps_path = replace_home(&data_path, &self.args.arg_dapps_path);
let secretstore_path = replace_home(&data_path, &self.args.flag_secretstore_path); let secretstore_path = replace_home(&data_path, &self.args.arg_secretstore_path);
let ui_path = replace_home(&data_path, &self.args.flag_ui_path); let ui_path = replace_home(&data_path, &self.args.arg_ui_path);
if self.args.flag_geth && !cfg!(windows) { if self.args.flag_geth && !cfg!(windows) {
let geth_root = if self.chain() == "testnet".to_owned() { path::ethereum::test() } else { path::ethereum::default() }; let geth_root = if self.chain() == "testnet".to_owned() { path::ethereum::test() } else { path::ethereum::default() };
@ -977,8 +982,8 @@ impl Configuration {
} else { } else {
parity_ipc_path( parity_ipc_path(
&self.directories().base, &self.directories().base,
&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone()), &self.args.arg_ipcpath.clone().unwrap_or(self.args.arg_ipc_path.clone()),
self.args.flag_ports_shift, self.args.arg_ports_shift,
) )
} }
} }
@ -996,32 +1001,32 @@ impl Configuration {
} }
fn ui_interface(&self) -> String { fn ui_interface(&self) -> String {
self.interface(&self.args.flag_ui_interface) self.interface(&self.args.arg_ui_interface)
} }
fn rpc_interface(&self) -> String { fn rpc_interface(&self) -> String {
let rpc_interface = self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()); let rpc_interface = self.args.arg_rpcaddr.clone().unwrap_or(self.args.arg_jsonrpc_interface.clone());
self.interface(&rpc_interface) self.interface(&rpc_interface)
} }
fn ws_interface(&self) -> String { fn ws_interface(&self) -> String {
self.interface(&self.args.flag_ws_interface) self.interface(&self.args.arg_ws_interface)
} }
fn ipfs_interface(&self) -> String { fn ipfs_interface(&self) -> String {
self.interface(&self.args.flag_ipfs_api_interface) self.interface(&self.args.arg_ipfs_api_interface)
} }
fn secretstore_interface(&self) -> String { fn secretstore_interface(&self) -> String {
self.interface(&self.args.flag_secretstore_interface) self.interface(&self.args.arg_secretstore_interface)
} }
fn secretstore_http_interface(&self) -> String { fn secretstore_http_interface(&self) -> String {
self.interface(&self.args.flag_secretstore_http_interface) self.interface(&self.args.arg_secretstore_http_interface)
} }
fn secretstore_self_secret(&self) -> Result<Option<NodeSecretKey>, String> { fn secretstore_self_secret(&self) -> Result<Option<NodeSecretKey>, String> {
match self.args.flag_secretstore_secret { match self.args.arg_secretstore_secret {
Some(ref s) if s.len() == 64 => Ok(Some(NodeSecretKey::Plain(s.parse() Some(ref s) if s.len() == 64 => Ok(Some(NodeSecretKey::Plain(s.parse()
.map_err(|e| format!("Invalid secret store secret: {}. Error: {:?}", s, e))?))), .map_err(|e| format!("Invalid secret store secret: {}. Error: {:?}", s, e))?))),
Some(ref s) if s.len() == 40 => Ok(Some(NodeSecretKey::KeyStore(s.parse() Some(ref s) if s.len() == 40 => Ok(Some(NodeSecretKey::KeyStore(s.parse()
@ -1033,7 +1038,7 @@ impl Configuration {
fn secretstore_nodes(&self) -> Result<BTreeMap<Public, (String, u16)>, String> { fn secretstore_nodes(&self) -> Result<BTreeMap<Public, (String, u16)>, String> {
let mut nodes = BTreeMap::new(); let mut nodes = BTreeMap::new();
for node in self.args.flag_secretstore_nodes.split(',').filter(|n| n != &"") { for node in self.args.arg_secretstore_nodes.split(',').filter(|n| n != &"") {
let public_and_addr: Vec<_> = node.split('@').collect(); let public_and_addr: Vec<_> = node.split('@').collect();
if public_and_addr.len() != 2 { if public_and_addr.len() != 2 {
return Err(format!("Invalid secret store node: {}", node)); return Err(format!("Invalid secret store node: {}", node));
@ -1056,7 +1061,7 @@ impl Configuration {
} }
fn stratum_interface(&self) -> String { fn stratum_interface(&self) -> String {
self.interface(&self.args.flag_stratum_interface) self.interface(&self.args.arg_stratum_interface)
} }
fn rpc_enabled(&self) -> bool { fn rpc_enabled(&self) -> bool {
@ -1088,7 +1093,7 @@ impl Configuration {
return true; return true;
} }
let ui_disabled = self.args.flag_unlock.is_some() || let ui_disabled = self.args.arg_unlock.is_some() ||
self.args.flag_geth || self.args.flag_geth ||
self.args.flag_no_ui; self.args.flag_no_ui;
@ -1098,7 +1103,7 @@ impl Configuration {
fn verifier_settings(&self) -> VerifierSettings { fn verifier_settings(&self) -> VerifierSettings {
let mut settings = VerifierSettings::default(); let mut settings = VerifierSettings::default();
settings.scale_verifiers = self.args.flag_scale_verifiers; settings.scale_verifiers = self.args.flag_scale_verifiers;
if let Some(num_verifiers) = self.args.flag_num_verifiers { if let Some(num_verifiers) = self.args.arg_num_verifiers {
settings.num_verifiers = num_verifiers; settings.num_verifiers = num_verifiers;
} }
@ -1108,7 +1113,7 @@ impl Configuration {
fn whisper_config(&self) -> ::whisper::Config { fn whisper_config(&self) -> ::whisper::Config {
::whisper::Config { ::whisper::Config {
enabled: self.args.flag_whisper, enabled: self.args.flag_whisper,
target_message_pool_size: self.args.flag_whisper_pool_size * 1024 * 1024, target_message_pool_size: self.args.arg_whisper_pool_size * 1024 * 1024,
} }
} }
} }
@ -1404,7 +1409,7 @@ mod tests {
let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]); let conf3 = parse(&["parity", "--tx-queue-strategy", "gas"]);
// then // then
let min_period = conf0.args.flag_reseal_min_period; let min_period = conf0.args.arg_reseal_min_period;
assert_eq!(conf0.miner_options(min_period).unwrap(), mining_options); assert_eq!(conf0.miner_options(min_period).unwrap(), mining_options);
mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice; mining_options.tx_queue_strategy = PrioritizationStrategy::GasFactorAndGasPrice;
assert_eq!(conf1.miner_options(min_period).unwrap(), mining_options); assert_eq!(conf1.miner_options(min_period).unwrap(), mining_options);
@ -1563,10 +1568,10 @@ mod tests {
// given // given
// when // when
let conf0 = parse(&["parity", "--ui-path", "signer"]); let conf0 = parse(&["parity", "--ui-path=signer"]);
let conf1 = parse(&["parity", "--ui-path", "signer", "--ui-no-validation"]); let conf1 = parse(&["parity", "--ui-path=signer", "--ui-no-validation"]);
let conf2 = parse(&["parity", "--ui-path", "signer", "--ui-port", "3123"]); let conf2 = parse(&["parity", "--ui-path=signer", "--ui-port", "3123"]);
let conf3 = parse(&["parity", "--ui-path", "signer", "--ui-interface", "test"]); let conf3 = parse(&["parity", "--ui-path=signer", "--ui-interface", "test"]);
// then // then
assert_eq!(conf0.directories().signer, "signer".to_owned()); assert_eq!(conf0.directories().signer, "signer".to_owned());

View File

@ -25,7 +25,7 @@ use futures::{future, IntoFuture, Future, BoxFuture};
use hash_fetch::fetch::Client as FetchClient; use hash_fetch::fetch::Client as FetchClient;
use hash_fetch::urlhint::ContractClient; use hash_fetch::urlhint::ContractClient;
use helpers::replace_home; use helpers::replace_home;
use light::client::LightChainClient; use light::client::Client as LightClient;
use light::on_demand::{self, OnDemand}; use light::on_demand::{self, OnDemand};
use node_health::{SyncStatus, NodeHealth}; use node_health::{SyncStatus, NodeHealth};
use rpc; use rpc;
@ -87,16 +87,16 @@ impl ContractClient for FullRegistrar {
} }
/// Registrar implementation for the light client. /// Registrar implementation for the light client.
pub struct LightRegistrar<T> { pub struct LightRegistrar {
/// The light client. /// The light client.
pub client: Arc<T>, pub client: Arc<LightClient>,
/// Handle to the on-demand service. /// Handle to the on-demand service.
pub on_demand: Arc<OnDemand>, pub on_demand: Arc<OnDemand>,
/// Handle to the light network service. /// Handle to the light network service.
pub sync: Arc<LightSync>, pub sync: Arc<LightSync>,
} }
impl<T: LightChainClient + 'static> ContractClient for LightRegistrar<T> { impl ContractClient for LightRegistrar {
fn registrar(&self) -> Result<Address, String> { fn registrar(&self) -> Result<Address, String> {
self.client.engine().additional_params().get("registrar") self.client.engine().additional_params().get("registrar")
.ok_or_else(|| "Registrar not defined.".into()) .ok_or_else(|| "Registrar not defined.".into())
@ -106,14 +106,7 @@ impl<T: LightChainClient + 'static> ContractClient for LightRegistrar<T> {
} }
fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String> { fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String> {
let header = self.client.best_block_header(); let (header, env_info) = (self.client.best_block_header(), self.client.latest_env_info());
let env_info = self.client.env_info(BlockId::Hash(header.hash()))
.ok_or_else(|| format!("Cannot fetch env info for header {}", header.hash()));
let env_info = match env_info {
Ok(x) => x,
Err(e) => return future::err(e).boxed(),
};
let maybe_future = self.sync.with_context(move |ctx| { let maybe_future = self.sync.with_context(move |ctx| {
self.on_demand self.on_demand

View File

@ -65,40 +65,40 @@ pub fn find_deprecated(args: &Args) -> Vec<Deprecated> {
result.push(Deprecated::Replaced("--ipc-off", "--no-ipc")); result.push(Deprecated::Replaced("--ipc-off", "--no-ipc"));
} }
if args.flag_etherbase.is_some() { if args.arg_etherbase.is_some() {
result.push(Deprecated::Replaced("--etherbase", "--author")); result.push(Deprecated::Replaced("--etherbase", "--author"));
} }
if args.flag_extradata.is_some() { if args.arg_extradata.is_some() {
result.push(Deprecated::Replaced("--extradata", "--extra-data")); result.push(Deprecated::Replaced("--extradata", "--extra-data"));
} }
// Removed in 1.7 // Removed in 1.7
if args.flag_dapps_port.is_some() { if args.arg_dapps_port.is_some() {
result.push(Deprecated::Replaced("--dapps-port", "--jsonrpc-port")); result.push(Deprecated::Replaced("--dapps-port", "--jsonrpc-port"));
} }
if args.flag_dapps_interface.is_some() { if args.arg_dapps_interface.is_some() {
result.push(Deprecated::Replaced("--dapps-interface", "--jsonrpc-interface")); result.push(Deprecated::Replaced("--dapps-interface", "--jsonrpc-interface"));
} }
if args.flag_dapps_hosts.is_some() { if args.arg_dapps_hosts.is_some() {
result.push(Deprecated::Replaced("--dapps-hosts", "--jsonrpc-hosts")); result.push(Deprecated::Replaced("--dapps-hosts", "--jsonrpc-hosts"));
} }
if args.flag_dapps_cors.is_some() { if args.arg_dapps_cors.is_some() {
result.push(Deprecated::Replaced("--dapps-cors", "--jsonrpc-cors")); result.push(Deprecated::Replaced("--dapps-cors", "--jsonrpc-cors"));
} }
if args.flag_dapps_user.is_some() { if args.arg_dapps_user.is_some() {
result.push(Deprecated::Removed("--dapps-user")); result.push(Deprecated::Removed("--dapps-user"));
} }
if args.flag_dapps_pass.is_some() { if args.arg_dapps_pass.is_some() {
result.push(Deprecated::Removed("--dapps-pass")); result.push(Deprecated::Removed("--dapps-pass"));
} }
if args.flag_dapps_apis_all.is_some() { if args.flag_dapps_apis_all {
result.push(Deprecated::Replaced("--dapps-apis-all", "--jsonrpc-apis")); result.push(Deprecated::Replaced("--dapps-apis-all", "--jsonrpc-apis"));
} }
@ -124,15 +124,15 @@ mod tests {
args.flag_dapps_off = true; args.flag_dapps_off = true;
args.flag_ipcdisable = true; args.flag_ipcdisable = true;
args.flag_ipc_off = true; args.flag_ipc_off = true;
args.flag_etherbase = Some(Default::default()); args.arg_etherbase = Some(Default::default());
args.flag_extradata = Some(Default::default()); args.arg_extradata = Some(Default::default());
args.flag_dapps_port = Some(Default::default()); args.arg_dapps_port = Some(Default::default());
args.flag_dapps_interface = Some(Default::default()); args.arg_dapps_interface = Some(Default::default());
args.flag_dapps_hosts = Some(Default::default()); args.arg_dapps_hosts = Some(Default::default());
args.flag_dapps_cors = Some(Default::default()); args.arg_dapps_cors = Some(Default::default());
args.flag_dapps_user = Some(Default::default()); args.arg_dapps_user = Some(Default::default());
args.flag_dapps_pass = Some(Default::default()); args.arg_dapps_pass = Some(Default::default());
args.flag_dapps_apis_all = Some(Default::default()); args.flag_dapps_apis_all = true;
args args
}), vec![ }), vec![
Deprecated::DoesNothing("--jsonrpc"), Deprecated::DoesNothing("--jsonrpc"),

View File

@ -22,7 +22,7 @@ use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant, Duration}; use std::time::{Instant, Duration};
use ethcore::client::{BlockId, BlockChainClient, BlockChainInfo, BlockQueueInfo, ChainNotify, ClientReport, Client}; use ethcore::client::*;
use ethcore::header::BlockNumber; use ethcore::header::BlockNumber;
use ethcore::service::ClientIoMessage; use ethcore::service::ClientIoMessage;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};

View File

@ -1,90 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Weak};
use ethcore::encoded;
use ethcore::engines::{Engine, StateDependentProof};
use ethcore::header::Header;
use ethcore::receipt::Receipt;
use ethsync::LightSync;
use futures::{future, Future, BoxFuture};
use light::client::fetch::ChainDataFetcher;
use light::on_demand::{request, OnDemand};
use parking_lot::RwLock;
use bigint::hash::H256;
const ALL_VALID_BACKREFS: &str = "no back-references, therefore all back-references valid; qed";
/// Allows on-demand fetch of data useful for the light client.
pub struct EpochFetch {
/// A handle to the sync service.
pub sync: Arc<RwLock<Weak<LightSync>>>,
/// The on-demand request service.
pub on_demand: Arc<OnDemand>,
}
impl EpochFetch {
fn request<T>(&self, req: T) -> BoxFuture<T::Out, &'static str>
where T: Send + request::RequestAdapter + 'static, T::Out: Send + 'static
{
match self.sync.read().upgrade() {
Some(sync) => {
let on_demand = &self.on_demand;
let maybe_future = sync.with_context(move |ctx| {
on_demand.request(ctx, req).expect(ALL_VALID_BACKREFS)
});
match maybe_future {
Some(x) => x.map_err(|_| "Request canceled").boxed(),
None => future::err("Unable to access network.").boxed(),
}
}
None => future::err("Unable to access network").boxed(),
}
}
}
impl ChainDataFetcher for EpochFetch {
type Error = &'static str;
type Body = BoxFuture<encoded::Block, &'static str>;
type Receipts = BoxFuture<Vec<Receipt>, &'static str>;
type Transition = BoxFuture<Vec<u8>, &'static str>;
fn block_body(&self, header: &Header) -> Self::Body {
self.request(request::Body(header.encoded().into()))
}
/// Fetch block receipts.
fn block_receipts(&self, header: &Header) -> Self::Receipts {
self.request(request::BlockReceipts(header.encoded().into()))
}
/// Fetch epoch transition proof at given header.
fn epoch_transition(&self, hash: H256, engine: Arc<Engine>, checker: Arc<StateDependentProof>)
-> Self::Transition
{
self.request(request::Signal {
hash: hash,
engine: engine,
proof_check: checker,
})
}
}

View File

@ -16,8 +16,6 @@
//! Utilities and helpers for the light client. //! Utilities and helpers for the light client.
mod epoch_fetch;
mod queue_cull; mod queue_cull;
pub use self::epoch_fetch::EpochFetch;
pub use self::queue_cull::QueueCull; pub use self::queue_cull::QueueCull;

View File

@ -23,7 +23,7 @@ use ethcore::service::ClientIoMessage;
use ethsync::LightSync; use ethsync::LightSync;
use io::{IoContext, IoHandler, TimerToken}; use io::{IoContext, IoHandler, TimerToken};
use light::client::LightChainClient; use light::client::Client;
use light::on_demand::{request, OnDemand}; use light::on_demand::{request, OnDemand};
use light::TransactionQueue; use light::TransactionQueue;
@ -41,9 +41,9 @@ const TIMEOUT_MS: u64 = 1000 * 60 * 10;
const PURGE_TIMEOUT_MS: u64 = 1000 * 60 * 9; const PURGE_TIMEOUT_MS: u64 = 1000 * 60 * 9;
/// Periodically culls the transaction queue of mined transactions. /// Periodically culls the transaction queue of mined transactions.
pub struct QueueCull<T> { pub struct QueueCull {
/// A handle to the client, for getting the latest block header. /// A handle to the client, for getting the latest block header.
pub client: Arc<T>, pub client: Arc<Client>,
/// A handle to the sync service. /// A handle to the sync service.
pub sync: Arc<LightSync>, pub sync: Arc<LightSync>,
/// The on-demand request service. /// The on-demand request service.
@ -54,7 +54,7 @@ pub struct QueueCull<T> {
pub remote: Remote, pub remote: Remote,
} }
impl<T: LightChainClient + 'static> IoHandler<ClientIoMessage> for QueueCull<T> { impl IoHandler<ClientIoMessage> for QueueCull {
fn initialize(&self, io: &IoContext<ClientIoMessage>) { fn initialize(&self, io: &IoContext<ClientIoMessage>) {
io.register_timer(TOKEN, TIMEOUT_MS).expect("Error registering timer"); io.register_timer(TOKEN, TIMEOUT_MS).expect("Error registering timer");
} }

View File

@ -26,6 +26,8 @@ extern crate ansi_term;
extern crate app_dirs; extern crate app_dirs;
extern crate ctrlc; extern crate ctrlc;
extern crate docopt; extern crate docopt;
#[macro_use]
extern crate clap;
extern crate env_logger; extern crate env_logger;
extern crate fdlimit; extern crate fdlimit;
extern crate futures; extern crate futures;

View File

@ -32,7 +32,6 @@ use ethsync::{ManageNetwork, SyncProvider, LightSync};
use hash_fetch::fetch::Client as FetchClient; use hash_fetch::fetch::Client as FetchClient;
use jsonrpc_core::{self as core, MetaIoHandler}; use jsonrpc_core::{self as core, MetaIoHandler};
use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache}; use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache};
use light::client::LightChainClient;
use node_health::NodeHealth; use node_health::NodeHealth;
use parity_reactor; use parity_reactor;
use parity_rpc::dispatch::{FullDispatcher, LightDispatcher}; use parity_rpc::dispatch::{FullDispatcher, LightDispatcher};
@ -399,9 +398,9 @@ impl ActivityNotifier for LightClientNotifier {
} }
/// RPC dependencies for a light client. /// RPC dependencies for a light client.
pub struct LightDependencies<T> { pub struct LightDependencies {
pub signer_service: Arc<SignerService>, pub signer_service: Arc<SignerService>,
pub client: Arc<T>, pub client: Arc<::light::client::Client>,
pub sync: Arc<LightSync>, pub sync: Arc<LightSync>,
pub net: Arc<ManageNetwork>, pub net: Arc<ManageNetwork>,
pub secret_store: Arc<AccountProvider>, pub secret_store: Arc<AccountProvider>,
@ -420,7 +419,7 @@ pub struct LightDependencies<T> {
pub whisper_rpc: Option<::whisper::RpcFactory>, pub whisper_rpc: Option<::whisper::RpcFactory>,
} }
impl<C: LightChainClient + 'static> LightDependencies<C> { impl LightDependencies {
fn extend_api<T: core::Middleware<Metadata>>( fn extend_api<T: core::Middleware<Metadata>>(
&self, &self,
handler: &mut MetaIoHandler<Metadata, T>, handler: &mut MetaIoHandler<Metadata, T>,
@ -569,7 +568,7 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
} }
} }
impl<T: LightChainClient + 'static> Dependencies for LightDependencies<T> { impl Dependencies for LightDependencies {
type Notifier = LightClientNotifier; type Notifier = LightClientNotifier;
fn activity_notifier(&self) -> Self::Notifier { LightClientNotifier } fn activity_notifier(&self) -> Self::Notifier { LightClientNotifier }

View File

@ -223,16 +223,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024; config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
config.queue.verifier_settings = cmd.verifier_settings; config.queue.verifier_settings = cmd.verifier_settings;
// start on_demand service. let service = light_client::Service::start(config, &spec, &db_dirs.client_path(algorithm), cache.clone())
let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone()));
let sync_handle = Arc::new(RwLock::new(Weak::new()));
let fetch = ::light_helpers::EpochFetch {
on_demand: on_demand.clone(),
sync: sync_handle.clone(),
};
let service = light_client::Service::start(config, &spec, fetch, &db_dirs.client_path(algorithm), cache.clone())
.map_err(|e| format!("Error starting light client: {}", e))?; .map_err(|e| format!("Error starting light client: {}", e))?;
let txq = Arc::new(RwLock::new(::light::transaction_queue::TransactionQueue::default())); let txq = Arc::new(RwLock::new(::light::transaction_queue::TransactionQueue::default()));
let provider = ::light::provider::LightProvider::new(service.client().clone(), txq.clone()); let provider = ::light::provider::LightProvider::new(service.client().clone(), txq.clone());
@ -244,6 +235,9 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
net_conf.boot_nodes = spec.nodes.clone(); net_conf.boot_nodes = spec.nodes.clone();
} }
// start on_demand service.
let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone()));
let mut attached_protos = Vec::new(); let mut attached_protos = Vec::new();
let whisper_factory = if cmd.whisper.enabled { let whisper_factory = if cmd.whisper.enabled {
let (whisper_net, whisper_factory) = ::whisper::setup(cmd.whisper.target_message_pool_size) let (whisper_net, whisper_factory) = ::whisper::setup(cmd.whisper.target_message_pool_size)
@ -267,7 +261,6 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
}; };
let light_sync = LightSync::new(sync_params).map_err(|e| format!("Error starting network: {}", e))?; let light_sync = LightSync::new(sync_params).map_err(|e| format!("Error starting network: {}", e))?;
let light_sync = Arc::new(light_sync); let light_sync = Arc::new(light_sync);
*sync_handle.write() = Arc::downgrade(&light_sync);
// spin up event loop // spin up event loop
let event_loop = EventLoop::spawn(); let event_loop = EventLoop::spawn();

View File

@ -25,7 +25,7 @@ use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use light::cache::Cache as LightDataCache; use light::cache::Cache as LightDataCache;
use light::client::LightChainClient; use light::client::{Client as LightClient, LightChainClient};
use light::{cht, TransactionQueue}; use light::{cht, TransactionQueue};
use light::on_demand::{request, OnDemand}; use light::on_demand::{request, OnDemand};
@ -63,9 +63,9 @@ use util::Address;
const NO_INVALID_BACK_REFS: &'static str = "Fails only on invalid back-references; back-references here known to be valid; qed"; const NO_INVALID_BACK_REFS: &'static str = "Fails only on invalid back-references; back-references here known to be valid; qed";
/// Light client `ETH` (and filter) RPC. /// Light client `ETH` (and filter) RPC.
pub struct EthClient<T> { pub struct EthClient {
sync: Arc<LightSync>, sync: Arc<LightSync>,
client: Arc<T>, client: Arc<LightClient>,
on_demand: Arc<OnDemand>, on_demand: Arc<OnDemand>,
transaction_queue: Arc<RwLock<TransactionQueue>>, transaction_queue: Arc<RwLock<TransactionQueue>>,
accounts: Arc<AccountProvider>, accounts: Arc<AccountProvider>,
@ -73,7 +73,7 @@ pub struct EthClient<T> {
polls: Mutex<PollManager<PollFilter>>, polls: Mutex<PollManager<PollFilter>>,
} }
impl<T> Clone for EthClient<T> { impl Clone for EthClient {
fn clone(&self) -> Self { fn clone(&self) -> Self {
// each instance should have its own poll manager. // each instance should have its own poll manager.
EthClient { EthClient {
@ -89,12 +89,12 @@ impl<T> Clone for EthClient<T> {
} }
impl<T: LightChainClient + 'static> EthClient<T> { impl EthClient {
/// Create a new `EthClient` with a handle to the light sync instance, client, /// Create a new `EthClient` with a handle to the light sync instance, client,
/// and on-demand request service, which is assumed to be attached as a handler. /// and on-demand request service, which is assumed to be attached as a handler.
pub fn new( pub fn new(
sync: Arc<LightSync>, sync: Arc<LightSync>,
client: Arc<T>, client: Arc<LightClient>,
on_demand: Arc<OnDemand>, on_demand: Arc<OnDemand>,
transaction_queue: Arc<RwLock<TransactionQueue>>, transaction_queue: Arc<RwLock<TransactionQueue>>,
accounts: Arc<AccountProvider>, accounts: Arc<AccountProvider>,
@ -209,7 +209,7 @@ impl<T: LightChainClient + 'static> EthClient<T> {
} }
} }
impl<T: LightChainClient + 'static> Eth for EthClient<T> { impl Eth for EthClient {
type Metadata = Metadata; type Metadata = Metadata;
fn protocol_version(&self) -> Result<String, Error> { fn protocol_version(&self) -> Result<String, Error> {
@ -466,7 +466,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
} }
// This trait implementation triggers a blanked impl of `EthFilter`. // This trait implementation triggers a blanked impl of `EthFilter`.
impl<T: LightChainClient + 'static> Filterable for EthClient<T> { impl Filterable for EthClient {
fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number } fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number }
fn block_hash(&self, id: BlockId) -> Option<RpcH256> { fn block_hash(&self, id: BlockId) -> Option<RpcH256> {

View File

@ -2244,7 +2244,7 @@ mod tests {
use super::{PeerInfo, PeerAsking}; use super::{PeerInfo, PeerAsking};
use ethkey; use ethkey;
use ethcore::header::*; use ethcore::header::*;
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient}; use ethcore::client::*;
use ethcore::transaction::UnverifiedTransaction; use ethcore::transaction::UnverifiedTransaction;
use ethcore::miner::MinerService; use ethcore::miner::MinerService;

View File

@ -25,7 +25,7 @@ use tests::helpers::{TestNet, Peer as PeerLike, TestPacket};
use ethcore::client::TestBlockChainClient; use ethcore::client::TestBlockChainClient;
use ethcore::spec::Spec; use ethcore::spec::Spec;
use io::IoChannel; use io::IoChannel;
use light::client::fetch::{self, Unavailable}; use light::client::Client as LightClient;
use light::net::{LightProtocol, IoContext, Capabilities, Params as LightParams}; use light::net::{LightProtocol, IoContext, Capabilities, Params as LightParams};
use light::provider::LightProvider; use light::provider::LightProvider;
use network::{NodeId, PeerId}; use network::{NodeId, PeerId};
@ -36,8 +36,6 @@ use light::cache::Cache;
const NETWORK_ID: u64 = 0xcafebabe; const NETWORK_ID: u64 = 0xcafebabe;
pub type LightClient = ::light::client::Client<Unavailable>;
struct TestIoContext<'a> { struct TestIoContext<'a> {
queue: &'a RwLock<VecDeque<TestPacket>>, queue: &'a RwLock<VecDeque<TestPacket>>,
sender: Option<PeerId>, sender: Option<PeerId>,
@ -218,14 +216,7 @@ impl TestNet<Peer> {
// skip full verification because the blocks are bad. // skip full verification because the blocks are bad.
config.verify_full = false; config.verify_full = false;
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let client = LightClient::in_memory( let client = LightClient::in_memory(config, &Spec::new_test(), IoChannel::disconnected(), cache);
config,
&Spec::new_test(),
fetch::unavailable(), // TODO: allow fetch from full nodes.
IoChannel::disconnected(),
cache
);
peers.push(Arc::new(Peer::new_light(Arc::new(client)))) peers.push(Arc::new(Peer::new_light(Arc::new(client))))
} }

View File

@ -71,8 +71,8 @@ fn authority_round() {
// Push transaction to both clients. Only one of them gets lucky to produce a block. // Push transaction to both clients. Only one of them gets lucky to produce a block.
net.peer(0).chain.miner().set_engine_signer(s0.address(), "".to_owned()).unwrap(); net.peer(0).chain.miner().set_engine_signer(s0.address(), "".to_owned()).unwrap();
net.peer(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap(); net.peer(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap();
net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain));
net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain));
net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1))); net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1)));
net.peer(1).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler0))); net.peer(1).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler0)));
// exchange statuses // exchange statuses
@ -160,8 +160,8 @@ fn tendermint() {
trace!(target: "poa", "Peer 0 is {}.", s0.address()); trace!(target: "poa", "Peer 0 is {}.", s0.address());
net.peer(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap(); net.peer(1).chain.miner().set_engine_signer(s1.address(), "".to_owned()).unwrap();
trace!(target: "poa", "Peer 1 is {}.", s1.address()); trace!(target: "poa", "Peer 1 is {}.", s1.address());
net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain) as _); net.peer(0).chain.engine().register_client(Arc::downgrade(&net.peer(0).chain));
net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain) as _); net.peer(1).chain.engine().register_client(Arc::downgrade(&net.peer(1).chain));
net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler0))); net.peer(0).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler0)));
net.peer(1).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1))); net.peer(1).chain.set_io_channel(IoChannel::to_handler(Arc::downgrade(&io_handler1)));
// Exhange statuses // Exhange statuses